所以我正在尝试创建一个指令来布局列中的项集合。 在plunker我有一个非常简化的版本,只使用一个ul,但这并不重要。我想要将指令调用为。
<my-column-layout collection="names">
<tab name="{{ item }}"></tab>
</my-column-layout>
我想使用内部html(此处的选项卡)作为集合中每个项目的模板。我试着去 在my-column-layout模板中有一个ng-repeat,比如
template : '<ul><li ng-repeat="item in collection" ng-transclude></li></ul>
虽然有效,但它没有访问包含控制器的范围,所以我无法在选项卡上有任何点击事件,并让它调用控制器中的一个函数。 所以我认为我正在朝着正确的方向前进,但是不确定。此外,当我尝试在名称集合中添加其他名称时,这不会出现在我的指令集合中。我的范围。$ watch('collection'...)永远不会被调用。
http://plnkr.co/edit/4vyZDAhBcbULEd3uIznh?p=preview
希望有人可以提供帮助
答案 0 :(得分:1)
我做的事情与我认为相似。如果我错过了这一点,请告诉我。我有一个基于远程数据执行转换ng-repeat的指令。这是它的工作原理。
<强>更新强>
这是页面标记中的模板问题。但是,如果您希望ng-repeat模板存在于同一页面标记上,则可以执行以下操作:
<script type="text/ng-template" id="navbar.html">
<li ng-repeat="item in items" ng-class="{active: item.selected}">
<a href="/{{item.link}}">{{item.title}}</a>
</li>
</script>
不完全相同的东西,但它得到的效果相同 - 与指令在同一页面上的模板 - 只是没有与它嵌套。
更新结束
我在父级和子级范围内有相同的数组:即$scope.items
。因为它是引用类型,所以通过原型继承,两个作用域都引用同一个对象。在不更新属性的位置,我像这样$scope.items = $scope.items || [];
初始化它 - 即如果属性尚未初始化,则初始化它,否则保留它。
directive('navbar', ['$location', '$http', function ($location, $http) {
return {
restrict: 'E',
transclude: true,
scope: { heading: '@'},
controller: 'NavbarCtrl',
templateUrl: 'navbar.html',
replace: true,
link: function ($scope, $element, $attrs, navbarCtrl) {
$scope.items = [];
$scope.heading = $scope.heading || $attrs.heading;
$http.get(itemsUrl).success(function(data) {
$scope.items = ... async get of data ... ;
navbarCtrl.selectByUrl($location.absUrl());
});
$scope.$watch('$location.absUrl()', function (locationPath) {
navbarCtrl.selectByUrl(locationPath)
});
}
}
}])
该指令的$ watch调用一个控制器函数,该函数可以通过其闭包访问控制器$ scope。
function NavbarCtrl($scope, $timeout, $http, $location, $attrs) {
$scope.items = $scope.items || [];
this.select = $scope.select = function (item) {
angular.forEach($scope.items, function (item) {
item.selected = false;
});
item.selected = true;
};
this.selectByUrl = function (url) {
angular.forEach($scope.items, function (item) {
if ('http://' + item.link === url) {
$scope.select(item);
}
});
};
}
然后,在我转发的模板中,我有:
<li ng-repeat="item in items" ng-class="{active: item.selected}">
<a href="/{{item.link}}">{{item.title}}</a>
</li>
在页面标记中,我使用它:
<div ng-controller="NavbarCtrl">
<navbar heading="Navbar Heading"/>
</div>
答案 1 :(得分:1)
构建自定义转发器是一项复杂的任务。主要是因为性能问题,但也因为它应该与其他指令一起使用。
如果你真的需要构建一个,你必须先深入研究ngRepeat
源代码,了解一些注意事项,然后根据自己的需要进行变更。
ngRepeat现在使用 $ watchCollection (自1.2 )取代了深度$ watch 值。
所以我的建议是不要构建自定义转发器,请使用ngRepeat
!
我仍然不知道你想要实现什么,但这就是构造。
这是一个掠夺者:http://plnkr.co/edit/pziqRzz0i1mU6eG5lAmd?p=preview
ngTransclude
app.directive('myTransclude',function(){
return {
require: "^myColumnLayout",
link: function(scope,elm,attr,ctrl,$transclude){
$transclude(function(clone){
elm.empty();
elm.append(clone);
ctrl.do("Hi")
})
}
}
});
app.directive('myColumnLayout', function() {
return {
restrict: 'EA',
transclude: true,
controller: function(){
this.do = function(x) {
console.log(x)
}
},
template: '<ul><li ng-repeat="item in collection track by $index" my-transclude></li></ul>',
scope: {
collection: '='
}
}
});
my-transclude
答案 2 :(得分:0)
我不清楚你究竟做了什么,但我在你的指令中修正了如下错误。
注意$ watch函数的第三个参数。观看收藏是必要的。
app.directive('myColumnLayout', function () {
return {
restrict: 'EA',
transclude: true,
scope: {
collection: '='
},
link: function (scope, elem, attrs, container, transclude) {
scope.$watch('collection', function (newVal, oldVal) {
elem.empty();
for (var i = 0; i < newVal.length; i++) {
var li = angular.element('<li></li>');
var scp = scope.$parent.$new();
scp.item = newVal[i];
transclude(scp, function (clone) {
elem.append(clone);
});
}
}, true);
}
}
});