我已经阅读了几篇与此问题相关的帖子和文章,他们帮助我设计了一些工作但是没有解释(至少以我理解的方式)为什么这不起作用。
我创建了一个工厂服务,其工作是管理一个大陆列表和一个选定的大陆。控制器通过表示为对象文字的公共API与此服务进行交互。
var appSvcs = appSvcs || angular.module("app.services", ["app.repositories"]);
appSvcs.factory('ContinentService', ['ContinentRepository',
function (db) {
'use strict';
//#region Private Fields and Variables
var continents = [],
selectedContinent = null;
selectedContinentIndex = -1;
//#endregion Private Fields and Variables
//#region Private Methods
function initContinents() {
return db.getContinents(); // return a promise
};
function setSelectedContinent(continent) {
selectedContinent = angular.copy(continent);
selectedContinentIndex = continents.indexOf(continent);
};
//#endregion Private Methods
//
// Public API
return {
continentService: {
continents: continents,
selectedContinent: selectedContinent,
setSelectedContinent: setSelectedContinent,
initContinents: initContinents,
}
}
}]);
控制器通过公共API与continentService交互。在控制器中,我在本地$ scope ...
上添加了对API的引用$scope.svc = svc.continentService;
由于工厂应该是单件,我期望的是当控制器调用公共方法" setSelectedContinent()"时,将设置selectedContinent和selectedContinentIndex属性,然后可以使用主机控制器和实现此工厂的任何其他控制器。事实证明并非如此。在下面的第二行中,会抛出类型错误..."无法读取属性' Id' of null"。这表明未设置服务的selectedContinent属性。
$scope.svc.setSelectedContinent(continent);
console.log($scope.svc.selectedContinent.Id + " :: " + $scope.svc.selectedContinent.Name);
然而,当我直接设置属性时,它工作正常 - sorta。有一个处理,方法setSelectedContinen()t需要执行,直接设置它显然不允许这种情况发生。
$scope.svc.selectedContinent = continent;
console.log($scope.svc.selectedContinent.Id + " :: " + $scope.svc.selectedContinent.Name);
我已将完整的控制器代码包含在内,以备参考。
angular.module("ListMgrApp").controller('ContinentPanelCtrl',
['$scope', 'ContinentService',
function ($scope, svc) {
'use strict';
//#region Fields and Variables
$scope.svc = svc.continentService;
var $uiContinentList = $('.continent-list');
///#endregion Fields and Variables
//#region private methods
function init() {
//
// Show the pane
$scope.svc.initContinents().then(
function (response) {
$scope.svc.continents = response.data;
},
function (reason) {
//TODO: Handle Error
});
};
//#endregion private methods
//#region $scope methods
$scope.setSelectedContinent = function (continent) {
// $scope.svc.selectedContinent = continent; <-- works but not sufficient
$scope.svc.setSelectedContinent(continent); // <-- Needs to work but does not
console.log(continent.Id + " :: " + continent.Name);
$uiContinentList.find('li[data-id="' + continent.Id + '"]').addClass("selected");
}
//#endregion $scope methods
init();
}]);
答案 0 :(得分:2)
引用您的setSelectedContinent
function setSelectedContinent(continent) {
selectedContinent = angular.copy(continent);
selectedContinentIndex = continents.indexOf(continent);
};
您的功能设置selectedContinent
和selectedContinentIndex
。但是这两个变量是本地变量 function (db)
通过闭包可用于您的功能,而不是您服务的属性。这就是为什么你试图访问它时出错:
$scope.svc.selectedContinent.Id
在你的第二个例子中:
$scope.svc.selectedContinent = continent;
您直接设置为svc
=&gt;的属性恢复它肯定不会有错误。但在这种情况下,您要在svc
上创建另一个属性,该属性与声明区域中的selectedContinent
不一样。
var continents = [],
selectedContinent = null;
selectedContinentIndex = -1;
<强>解决方案:强>
如果您需要将变量创建为私有(仅可通过闭包访问)。您可以提供一些getter函数来返回这些变量:
function getSelectedContinent(continent) {
return selectedContinent;
};
修改您返回的对象:
return {
continentService: {
continents: continents, //remove this if you need a true private property
selectedContinent: selectedContinent, //remove this if you need a true private property
setSelectedContinent: setSelectedContinent,
initContinents: initContinents,
getSelectedContinent: getSelectedContinent //return 1 more function
}
}