我有一个显示“主”项目列表的指令,当用户点击其中一个项目时,我希望页面上的任何“详细信息”指令(可能有多个)更新详细信息当前选择的“主”项目。
目前我正在使用id和href属性作为“详细信息”指令的一种方式来查找其相应的主指令。但我的印象是,这不是有角度的方式,所以如果不是,那么什么是更好的解决方案呢?
我很欣赏通常在引发指令之间的相互通信问题时,显而易见的解决方案是使用require:“^ master-directive”或使用服务,但在这种情况下,指令不在相同的层次结构,我不认为使用服务是合适的,因为它会使解决方案更复杂。
这是一些说明性代码,显示了我目前正在做的事情。
<div>
<master-list id="master1"></master-list>
</div>
<div>
<details-item href="#master1" ></details-item>
</div>
在master-list指令中选择一个项目时,我设置一个属性来指示当前选择的主项目:
attrs.$set('masterListItemId',item.id);
在details-item指令的链接函数中我做:
if (attrs.href) {
var id = attrs.href.split('#')[1];
var masterList = angular.element(document.getElementById(id));
if (masterList) {
var ctrl = masterList.controller('masterList');
ctrl.attrs().$observe('masterListItemId',function(value) {
attrs.$set('detailItemId',value);
});
}
}
attrs.$observe('detailItemId',function(id) {
// detail id changed so refresh
});
使我不能使用服务进行指令间通信的一个方面是(在我的情况下)可能在同一页面上有多个'masterList'元素,如果这些元素在逻辑上与同一服务相关,该服务最终将管理多个masterList元素的选择状态。如果您认为每个masterList元素都有一个关联的detailItem,那么如何更新正确的detailItem元素以反映其关联的masterList的状态?
<div>
<master-list id="master1"></master-list>
</div>
<div>
<master-list id="master2"></master-list>
</div>
<div>
<details-item href="#master1" ></details-item>
</div>
<div>
<details-item href="#master2" ></details-item>
</div>
最后我试图使用指令,而不是使用控制器代码(因为已经明智地建议),因为我真的很喜欢masterList和它关联的detailItems之间的关系在html中被'声明',而不是javascript因此,通过单独查看html,这些元素之间的关系是显而易见的。
这一点尤其重要,因为我有足够的知识来创建使用指令的html ui的用户,但理解javascript是一个太过分了。
是否有更好的方法来实现与角度做事方式更加一致的相同事物?
答案 0 :(得分:2)
我想我会为此使用服务。该服务将保存您关注的详细数据,因此它看起来像这样。
在master-list
模板中,您可能会有类似项目列表的内容:
<ul>
<li ng-repeat"item in items"><a ng-click="select(item)">{{item.name}}</a></li>
</ul>
......或类似的。
然后在您的指令中,您将拥有(仅部分代码)
.directive('masterList',function(DetailsService) {
return {
controller: function($scope) {
$scope.select = function(item) {
DetailsService.pick(item); // or however you get and retrieve data
};
}
};
})
.directive('detailsItem',function(DetailsService) {
return {
controller: function($scope) { // you could do this in the link as well
$scope.data = DetailsService.item;
}
};
})
然后在您的详细信息模板中使用data
:
<div>Details for {{data.name}}</div>
<ul>
<li ng-repeat="detail in data.details">{{detail.description}}</li>
</ul>
或类似的东西。
我不会使用id
或href
,而是使用服务来检索,保存和传递信息。
编辑:
这是一个jsfiddle,它在2个控制器之间执行,但指令是相同的想法 http://jsfiddle.net/u3u5kte7/
编辑: 如果您想拥有多个主服务器和详细信息,请保持模板不变,但更改指令控制器和服务,如下所示:
.directive('masterList',function(DetailsService) {
return {
controller: function($scope) {
$scope.select = function(item) {
DetailsService.pick($scope.listId,item); // or however you get and retrieve data
};
}
};
})
.directive('detailsItem',function(DetailsService) {
return {
controller: function($scope) { // you could do this in the link as well
$scope.data = DetailsService.get($scope.listId).item;
}
};
})
.factory('DetailsService',function(){
var data = {};
return {
pick: function(id,item) {
data[id] = data[id] || {item:{}};
// set data[id].item to whatever you want here
},
get: function(id) {
data[id] = data[id] || {item:{}};
return data[id];
}
};
})
答案 1 :(得分:2)
如果没有指令,我会选择完全不同的方法。指令是DOM操作的理想选择。但在这种情况下,我会坚持只使用模板和管理所有数据的控制器,并摆脱指令。使用ng-repeat重复项目
请查看这个小提琴,以获取此示例:http://jsfiddle.net/wbrand/2xrne4k3
模板:
<div ng-controller="ItemController as ic"> Masterlist: <ul><li ng-repeat="item in ic.items" ng-click="ic.selected($index)">{{item.prop1}}</li></ul>
Detaillist:
<ul><li ng-repeat="item in ic.items" >
{{item.prop1}}
<span ng-if="item.selected">SELECTED!</span>
</li></ul>
</div>
控制器:
angular.module('app',[]).controller('ItemController',function(){
this.items = [{prop1:'some value'},{prop1:'some other value'}]
this.selectedItemIndex;
this.selected = function(index){
this.items.forEach(function(item){
item.selected = false;
})
this.items[index].selected = true
}
})