在 angularjs 中创建一个容器指令 [英] Create a container directive in angularjs
问题描述
所以我正在尝试创建一个指令,该指令将在列中布局一组项目.在 plunker 中,我有一个极其简化的版本,它只使用一个 ul,但这并不重要.我希望指令像 .
一样被调用<tab name="{{ item }}"></tab></my-column-layout>
我想使用内部 html(此处的选项卡)作为集合中每个项目的模板.我试着只是在 my-column-layout 模板中有一个 ng-repeat 像
template : '- </li></ul>
有效,但它无法访问包含的控制器范围,因此我无法在选项卡上有任何单击事件并让它调用控制器中的函数.所以我认为我使用 transclude 朝着正确的方向前进,但不确定.此外,当我尝试向名称集合中添加一些其他名称时,这不会显示在我的指令的集合中.我的 scope.$watch('collection' ...) 从未被调用过.
http://plnkr.co/edit/4vyZDAhBcbULEd3uIznh?p=preview
希望有人能帮忙
我做了一些我认为类似的事情.如果我以某种方式错过了重点,请告诉我.我有一个指令,它根据远程数据执行嵌入的 ng-repeat.这是它的工作原理.
更新
问题在于页面标记中的模板.但是,如果您希望 ng-repeat 模板存在于同一页面标记上,您可以这样做:
不完全一样的东西,但它给你同样的效果——模板与指令在同一页面上——只是没有嵌套.
更新结束
我在父作用域和子作用域中有相同的数组:即 $scope.items
.因为它是一个引用类型,通过原型继承,两个作用域都引用同一个对象.在不更新属性的位置,我像这样初始化它 $scope.items = $scope.items ||[];
-- 即如果该属性尚未初始化,则对其进行初始化,否则保留.
directive('navbar', ['$location', '$http', function ($location, $http) {返回 {限制:'E',转置:真实,范围:{标题:'@'},控制器:'NavbarCtrl',templateUrl: 'navbar.html',替换:真的,链接:函数($scope,$element,$attrs,navbarCtrl){$scope.items = [];$scope.heading = $scope.heading ||$attrs.heading;$http.get(itemsUrl).success(function(data) {$scope.items = ... 异步获取数据 ... ;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 = 函数(网址){angular.forEach($scope.items, function (item) {if ('http://' + item.link === url) {$scope.select(item);}});};}
然后,在我嵌入的模板中,我有:
<a href="/{{item.link}}">{{item.title}}</a>
在页面标记中,我是这样使用的:
<导航栏标题="导航栏标题"/>
So I'm trying to create a directive that will layout a collection of items in columns. In the plunker I have a extremely simplified version which only uses a single ul, but that is not important. I want the directive to be called like .
<my-column-layout collection="names">
<tab name="{{ item }}"></tab>
</my-column-layout>
I want to use the inner html (the tab here) as a template for each item in the collection. I tried to just have a ng-repeat in the my-column-layout template like
template : '<ul><li ng-repeat="item in collection" ng-transclude></li></ul>
which worked but it didnt have access to the containing controllers scope, so I couldn't have any click events on the tab and have it call an function in the controller. So i think I am heading the right direction with using transclude but not sure. Also when I try to add some other name to the collection of names, then this doesnt show up in the collection in my directive. My scope.$watch('collection' ...) is never called.
http://plnkr.co/edit/4vyZDAhBcbULEd3uIznh?p=preview
Hope someone can help
I do something that I think is similar. Let me know if I've somehow missed the point. I have a directive that does a transcluded ng-repeat based on remote data. Here's how it works.
Update
It's the template in the page markup that's the issue. However, if you want the ng-repeat template to exist on the same page markup, you can do this:
<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>
Not exactly the same thing, but it get's you the same effect - template on the same page as the directive - just not nested with it.
Update End
I have the same array in the parent and the child scopes: i.e. $scope.items
. Because it's a reference type, through prototypical inheritance, both scopes reference the same object. In the location that doesn't update the property, I initialize it like this $scope.items = $scope.items || [];
-- i.e. if the property hasn't been initialized, initialize it, otherwise keep it.
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)
});
}
}
}])
The directive's $watch calls a controller function, and that function has access to the controller $scope through its closure.
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);
}
});
};
}
Then, in my template, which I transclude, I have:
<li ng-repeat="item in items" ng-class="{active: item.selected}">
<a href="/{{item.link}}">{{item.title}}</a>
</li>
In the page markup, I use it like this:
<div ng-controller="NavbarCtrl">
<navbar heading="Navbar Heading"/>
</div>
这篇关于在 angularjs 中创建一个容器指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!