J'essaie donc de créer une directive qui mettra en page une collection d'éléments dans des colonnes. Dans le plunker, j'ai une version extrêmement simplifiée qui n'utilise qu'un seul ul, mais ce n'est pas important. Je veux que la directive soit appelée comme.
<my-column-layout collection="names"> <tab name="{{ item }}"></tab> </my-column-layout>
Je veux utiliser le html interne (l'onglet ici) comme modèle pour chaque élément de la collection. J'ai essayé d'avoir juste une répétition ng dans le modèle de ma colonne-disposition comme
template : '<ul><li ng-repeat="item in collection" ng-transclude></li></ul>
Qui a fonctionné, mais il n'a pas eu accès à la portée des contrôleurs contenant, de sorte que je n'ai pas eu d'événements de clic sur l'onglet et que l'on appelle une fonction dans le contrôleur. Je pense donc que je suis dans la bonne direction avec l'utilisation de transclus, mais pas sûr. De même, lorsque j'essaie d'ajouter un autre nom à la collection de noms, cela ne s'affiche pas dans la collection de ma directive. Ma portée. $ Watch ('collection' …) n'est jamais appelé.
Http://plnkr.co/edit/4vyZDAhBcbULEd3uIznh?p=preview
Espérons que quelqu'un peut aider
Je fais quelque chose que je pense être similaire. Permettez-moi de savoir si j'ai manqué quelque chose. J'ai une directive qui fait une répétition ng translucide basée sur des données distantes. Voici comment cela fonctionne.
Mettre à jour
C'est le modèle dans le balisage de la page qui est le problème. Cependant, si vous souhaitez que le modèle ng-repeat existe sur le même balisage de page, vous pouvez le faire:
<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>
Pas exactement la même chose, mais il vous appartient du même effet – un modèle sur la même page que la directive – tout simplement pas imbriqué avec elle.
Fin de la mise à jour
J'ai le même tableau dans les domaines parent et enfant: c.- $scope.items
. $scope.items
. Parce que c'est un type de référence, à travers un héritage prototypique, les deux champs font référence au même objet. Dans l'emplacement qui ne met pas à jour la propriété, je l'initialise comme ceci $scope.items = $scope.items || [];
$scope.items = $scope.items || [];
– c'est-à-dire si la propriété n'a pas été initialisée, initialisez-la, sinon gardez-la.
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) }); } } }])
La montre $ de la directive appelle une fonction de contrôleur, et cette fonction a accès à la portée du contrôleur par sa fermeture.
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); } }); }; }
Ensuite, dans mon modèle, que je transmet, j'ai:
<li ng-repeat="item in items" ng-class="{active: item.selected}"> <a href="/{{item.link}}">{{item.title}}</a> </li>
Dans le balisage de la page, je l'utilise comme ceci:
<div ng-controller="NavbarCtrl"> <navbar heading="Navbar Heading"/> </div>
Construire un répéteur personnalisé est une tâche compliquée. Principalement en raison des problèmes de performance, mais aussi parce qu'il devrait bien fonctionner avec d'autres directives.
Si vous avez vraiment besoin de créer un, vous devez d'abord plonger dans ngRepeat
code source pour comprendre certaines considérations et ensuite le muter en fonction de vos besoins.
NgRepeat utilise maintenant $ watchCollection ( depuis 1.2 ) qui a remplacé le pendentif $ .
Donc, ma recommandation est de ne pas créer un répéteur personnalisé , utilisez ngRepeat
!
Je ne sais toujours pas ce que vous voulez atteindre, mais c'est la construction.
Voici un plunker: 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
Ce n'est pas clair pour moi ce que vous faites exactement, mais je corrige une erreur dans votre directive comme suit.
Notez le troisième paramètre de la fonction $ watch. Il est nécessaire de regarder une collection.
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); } } });