Как правильно привязать свойство сервиса в AngularJS?
У меня есть фабрика, где у меня есть пара предопределенных партнеров (это может быть что угодно, я думал, что это пример, который легко понять). Во время выполнения мы выбираем текущего партнера (основываясь на некоторой логике, которую я здесь пропустил).
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,
};
});
Затем я хотел бы получить доступ к партнеру как PartnersService.partner
и посмотрите, как он меняется, например, из контроллера:
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
});
Я нашел некоторые обходные пути (по моему мнению... они обходные пути?), Но это кажется мне неестественным, поэтому я хотел бы спросить, есть ли лучший способ.
Смотрите мой полный, рабочий пример на JS Bin. Я прошу прощения, если вы найдете пример немного длинным, но я хотел убедиться, что пользователи Stack Overflow понимают мои проблемы и могут указать, если что-то не так с моим мнением.
Обходной путь 1 (получатель?):
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,
// ...
};
});
Обходной путь 2 (гнездо в литерале объекта):
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,
//...
};
});
3 ответа
Изменить на:
this.partner = partners.secondPartner;
в вашем методе initPartner. Это решит это.
Что вы действительно делаете, когда делаете
var partners = { ... }
var partner = partners.firstPartner;
вы создаете локальные объекты в классе, но они не являются открытыми членами класса. И с
return {
initPartner: initPartner,
partners: partners,
partner: partner
};
вы создаете члены класса и копируете значения локальных переменных в члены класса. В вашем методе initPartner вы изменяете локальный объект, но объект класса остается неизменным.
Я хотел бы пойти с подходом использования геттеров и сеттеров, так как он следует шаблону раскрытия модуля, который действительно предпочтителен для поддержки более чистого, более читаемого и понятного кода.
Заводской код выглядит следующим образом.
(function () {
angular.module('myApp').
factory('PartnersService', PartnersService);
function PartnersService($location, $log) {
var partners = {
firstPartner: {
name: 'Default Partner',
id: 1 // just an extra property as example
},
secondPartner: {
name: 'Other Partner',
id: 2
}
};
var partner;
//Set default value
setDefaultPartner();
var service = {
getPartner: getPartner,
setPartner: setPartner
};
return service;
/*** Function Declarations ***/
/* Accessible Functions */
function getPartner() {
return partner;
}
function setPartner() {
var selectedPartner = initPartner();
return selectedPartner;
}
/* Private Functions */
function initPartner() {
/*
* Some (omitted) logic to select partner
*/
partner = partners.secondPartner;
$log.log("initPartner should have changed partner to " + partner.name);
return partner;
}
function setDefaultPartner() {
partner = partners.firstPartner;
}
}
})();
Обратите внимание, что единственными открытыми / доступными членами остаются getPartner
а также setPartner
(который вызывает initPartner
) функции.
Контроллер будет следующим.
(function () {
angular.module('myApp').
controller('myController', myController);
function myController($scope, $log, PartnersService) {
$scope.partner = PartnersService.getPartner();
$log.log("should be default partner: " + $scope.partner.name);
$scope.partner = PartnersService.setPartner();
$log.log("After setPartner which calls initPartner, the current partner is now the " + $scope.partner.name);
}
})();
Модифицируя свою корзину JS, ниже приводится лог консоли.
"should be default partner: Default Partner"
"initPartner should have changed partner to Other Partner"
"After setPartner which calls initPartner, the current partner is now the Other Partner"
Я не думаю, что вам не хватает ничего очевидного. Оба ваших обходных пути кажутся мне подходящими, за исключением того, что в последнем случае я, вероятно, использовал бы следующую структуру:
var partners = { ... };
var initPartner = function () {
retObj.partner = partners.secondPartner;
};
var retObj = {
initPartner: initPartner,
partners: partners,
partner: partners.firstPartner
};
return retObj;