In my app I have 2 almost identical controllers. A lot of functions are the same, so I'd like to prototype them. This is Controller #1:
c2gcontroller.js
angular.module('c2gyoApp')
.controller('C2gCtrl', function($scope) {
// some unique stuff
$scope.feeDay = 59;
...
// the identical functions
$scope.getMinutes = function(minutes) {
var duration = moment.duration(minutes, 'm');
return duration.minutes();
};
...
});
and Controller #2:
c2gbcontroller.js
angular.module('c2gyoApp')
.controller('C2gbCtrl', function($scope) {
// some unique stuff
$scope.feeDay = 89;
...
// the identical functions
$scope.getMinutes = function(minutes) {
var duration = moment.duration(minutes, 'm');
return duration.minutes();
};
...
});
I've tried putting $scope.getMinutes
into a factory:
smfactory.js
angular.module('c2gyoApp')
.factory('smfactory', function() {
return {
getHours: function(minutes) {
var duration = moment.duration(minutes, 'm');
return Math.ceil(duration.asHours() % 24);
}
};
});
I've injected smfactory
into c2gcontroller.js
c2gcontroller.js (attempt #1)
angular.module('c2gyoApp')
.controller('C2gCtrl', function($scope, smfactory) {
...
// the identical functions
$scope.getHours = smfactory.getHours(minutes);
...
});
This yields an error that minutes is not defined
line 33 col 42 'minutes' is not defined.
So I tried:
c2gcontroller.js (attempt #2)
angular.module('c2gyoApp')
.controller('C2gCtrl', function($scope, smfactory) {
...
// the identical functions
$scope.getMinutes = function(minutes) {
return smfactory.getHours(minutes);
};
...
});
which doesn't yield an error, but my app did become unresponsive. Basically $scope.getMinutes
doesn't return anything now.
I've read and watched a lot about AngularJS Services, Factories, Providers, but I don't know where to go from here. What would be the proper way to prototype c2gcontroller.js
and c2gbcontroller.js
?
This is where using a combination of JavaScript awesomeness, and the controller as
syntax really comes in handy.
If we pull your common functions out into a plain old object:
var commonStuff = {
getHours: function(minutes) {
var duration = moment.duration(minutes, 'm');
return Math.ceil(duration.asHours() % 24);
}
};
Then if we refactor our controller to be a normal JS object, we can augment it with a mixin one of two ways. Either directly onto the object itself, or via the prototype.
//Using the instance
function MyCtrl(){
var vm = this;
angular.extend(vm, commonStuff);
//Other stuff
}
//Or via the prototype
function MyCtrl(){
var vm = this;
}
//Controller specific
MyCtrl.prototype = {
};
angular.extend(MyCtrl.prototype, commonStuff);
The biggest difference is that now you can just reference the controller directly via the use of the controller as
syntax.
<div ng-controller="myCtrl as ctrl">
<a href="" ng-click="ctrl.getHours(120)">Get Hours</a>
</div>
How about pseudo inheritance with angular.extend
/* define a "base" controller with shared functionality */
.controller('baseCtrl', ['$scope', ..
function($scope, ...) {
$scope.getMinutes = function(minutes) {
var duration = moment.duration(minutes, 'm');
return duration.minutes();
};
.controller('C2gCtrl', ['$controller', '$scope', ...
function($controller, $scope, ...) {
// copies the functionality from baseCtrl to this controller
angular.extend(this, $controller('baseCtrl', {$scope: $scope}));
// some unique stuff
$scope.feeDay = 59;
})
.controller('C2gbCtrl', ['$controller', '$scope', ...
function($controller, $scope, ...) {
// copies the functionality from baseCtrl to this controller
angular.extend(this, $controller('baseCtrl', {$scope: $scope}))
// some unique stuff
$scope.feeDay = 89;
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With