I have a factory where I have a couple of predefined partners (it could be anything else, I thought it's an example that's easy to understand). On run time, we select the current partner (based on some logic I omitted here).
angular.module('myApp').factory('PartnersService', function ($location, $log) {
var partners = {
firstPartner: {
name: 'Default Partner',
id: 1 // just an extra property as example
},
secondPartner: {
name: 'Other Partner',
id: 2
}
};
// set default value
var partner = partners.firstPartner;
var initPartner = function () {
// based on some logic (omitted), select partner
partner = partners.secondPartner;
$log.log("initPartner should have changed partner to " + partner.name);
};
return {
initPartner: initPartner,
partners: partners,
partner: partner,
};
});
Then, I would like to access the partner as PartnersService.partner
and see as it changes, e.g. from a controller:
angular.module('myApp').controller('myController',
function ($scope, $log, PartnersService) {
// PartnersService.partner is the default partner (firstPartner)
PartnersService.initPartner();
// After initPartner, PartnersService.partner is still
// the default, but I expected it to change
});
I found some workarounds (in my opinion... are they workarounds?), but it feels unnatural for me, so I'd like to ask if there's a better way.
See my full, working example on JS Bin. I apologize if you find the example a bit lengthy, but I wanted to make sure Stack Overflow users understand my concerns and can point out if something is wrong with the way I think.
Workaround 1 (getter?):
angular.module('myApp').controller('myController', function ($scope, $log, PartnersService) {
PartnersService.initPartner();
var partner = PartnersService.getPartner();
$log.log('I could use a getter: ' + partner.name);
});
angular.module('myApp').factory('PartnersService', function ($location, $log) {
var getPartner = function () {
return partner;
};
return {
getPartner: getPartner,
// ...
};
});
Workaround 2 (nest in an object literal):
angular.module('myApp').controller('myController', function ($scope, $log, PartnersService) {
PartnersService.initPartner();
$log.log('or nest the partner in an extra object literal: '
+ PartnersService.extraObjectLiteral.partner.name);
});
angular.module('myApp').factory('PartnersService', function ($location, $log) {
var partners = { /*...*/ }
var extraObjectLiteral = {
partner: partners.firstPartner
};
var initPartner = function () {
// based on some logic (omitted), select partner
extraObjectLiteral.partner = partners.secondPartner;
};
return {
extraObjectLiteral: extraObjectLiteral,
//...
};
});
Change to:
this.partner = partners.secondPartner;
in your initPartner method. That will solve it.
What you're really doing when you do
var partners = { ... }
var partner = partners.firstPartner;
is, you're creating local objects in the class, but they are not exposed members of the class. And with the
return {
initPartner: initPartner,
partners: partners,
partner: partner
};
you create members of the class, and copy the values of the local variables to the class' members. In your initPartner method, you change the local object, but the class' object remain unchanged.