Vraag ng-repeat met ng-transclude binnen een richtlijn


Ik wil een lijst met aangepast gedrag maken wanneer de inhoud verandert. Ik probeer hier een richtlijn voor te maken, maar ik ben een beetje verdwaald over het combineren van de ng-transclude met de ng-repeat-richtlijn. Kan iemand me op het goede spoor zetten?

html:

<div ng-app="myApp">
  <div ng-controller="ctrl">
    <mylist items="myItem in items">
       <span class="etc">{{myItem}}</span>
    </mylist>
  </div>
</div>

javascript:

angular.module('myApp', [])    

.controller('ctrl', function ($scope) {
  $scope.items = ['one', 'two', 'three'];
})    

.directive('mylist', function () {
  return {
    restrict:'E',
    transclude: 'element',
    replace: true,
    scope: true,
    template: [
      '<ul>',
        '<li ng-repeat="WhatGoesHere in items" ng-transclude></li>',
      '</ul>'
    ].join(''),
    link: function (scope, element, attr) {
      var parts = attr.items.split(' in ');
      var itemPart = parts[0];
      var itemsPart = parts[1];
      scope.$watch(itemsPart, function (value) {
        scope.items = value; 
      });      
    }
  }
});

Ik heb een deel van dit enigszins werkend hier

BEWERK:

criteria:

  • De sjabloon van het artikel moet worden gedefinieerd in de weergave, niet in de richtlijn en moet toegang hebben tot een itemeigenschap in een onderliggend bereik. Idealiter wil ik dit definiëren zoals in de ng-repeat-richtlijn
  • De richtlijn moet toegang hebben tot de lijst, zodat ik goede horloges kan instellen en dingen kan veranderen. Indien mogelijk zou ik graag gemakkelijke toegang hebben tot de gegenereerde DOM-items (ik kan het ook doen met element[0].querySelectorAll('ul>li') of zoiets, het hoeft alleen maar in Chrome te werken).
  • Indien mogelijk zou ik de logica in de ng-repeat-richtlijn opnieuw willen gebruiken, omdat het al veel doet wat ik wil. Bij voorkeur wil ik de code niet kopiëren. Ik wil gewoon zijn gedrag vergroten, het niet veranderen

44
2018-01-17 21:13


oorsprong


antwoorden:


Los het probleem zelf op:

Ik kan het in de compileerstap doen (jsfiddle) door het toevoegen van de ng-repeat attribuut wanneer de sjabloon is gecompileerd en deze de inhoud van mijn attribuut toevoegt.

html:

<div ng-app="myApp">
  <div ng-controller="ctrl">
    <mylist element="myItem in items">{{myItem}}</mylist>
  </div>
</div>

javascript:

var myApp = angular.module('myApp', [])

.controller('ctrl', function ($scope) {
  $scope.items = ['one', 'two', 'three'];
})

.directive('mylist', function ($parse) {
  return {
    restrict:'E',
    transclude: 'element',
    replace: true,
    scope: true,
    template: [
      '<ul>',
      '<li ng-transclude></li>',
      '</ul>'
    ].join(''),
    compile: function (tElement, tAttrs, transclude) {
      var rpt = document.createAttribute('ng-repeat');
      rpt.nodeValue = tAttrs.element;
      tElement[0].children[0].attributes.setNamedItem(rpt);
      return function (scope, element, attr) {
        var rhs = attr.element.split(' in ')[1];
        scope.items = $parse(rhs)(scope);
        console.log(scope.items);
      }        
    }
  }
});

20
2018-01-20 16:26



Een alternatieve manier om dit als volgt te bereiken.

index.html:

<html ng-app='myApp'>

<head>
    <title>AngularJS Transclude within Repeat Within Directive</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script>
    <script src='index.js'></script>
</head>

<body ng-controller='myController'>
    <people>Hello {{person.name}}</people>
    <button name="button" ng-click="changeRob()">Change Rob</button>
</body>
</html>

index.js:

var myApp = angular.module( 'myApp', [] );

myApp.controller( 'myController', function( $scope ) {
    $scope.people = [
        { name: 'Rob'  },
        { name: 'Alex' },
        { name: 'John' }
    ];

    $scope.changeRob = function() {
        $scope.people[0].name = 'Lowe';
    }
});

myApp.directive( 'people', function() {
    return {
        restrict: 'E',

        transclude: true,
        template: '<div ng-repeat="person in people" transcope></div>',
    }
});

myApp.directive( 'transcope', function() {
    return {
        link: function( $scope, $element, $attrs, controller, $transclude ) {
            if ( !$transclude ) {
                throw minErr( 'ngTransclude' )( 'orphan',
                    'Illegal use of ngTransclude directive in the template! ' +
                    'No parent directive that requires a transclusion found. ' +
                    'Element: {0}',
                    startingTag( $element ));
            }
            var innerScope = $scope.$new();

            $transclude( innerScope, function( clone ) {
                $element.empty();
                $element.append( clone );
                $element.on( '$destroy', function() {
                    innerScope.$destroy();
                });
            });
        }
    };
}); 

Zie het hier in actie soortgelijke plunker. Op basis hiervan lange Github kwestie discussie.


14
2017-07-01 14:12



Andere antwoorden helaas werkt niet met de nieuwste versie van hoekig (ik controleerde 1.4) dus ik denk dat er een voordeel is om te delen deze jbin Ik vond:

var app = angular.module('app', [])
  .controller('TestCtrl', function($scope) {
    $scope.myRecords = ['foo', 'bar', 'baz'];
  });

app.directive('myDirective', function($compile) {
  var template = '<div id="inner-transclude" ng-repeat="record in records"></div>';

  return {
    scope: {
      records: '='
    },
    restrict: 'A',
    compile: function(ele) {
      var transclude = ele.html();
      ele.html('');

      return function(scope, elem) {
        var tpl = angular.element(template);
        tpl.append(transclude);

        $compile(tpl)(scope);

        elem.append(tpl);
      };
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>


<div ng-app="app" ng-controller="TestCtrl">
  <div my-directive records="myRecords">
    ?: {{record}}
  </div>

</div>


9
2018-06-10 20:10



Transcluding is niet nodig omdat items bevat wat we nodig hebben om de sjabloon weer te geven. Anders gezegd, er is niets in het element - d.w.z. <mylist>nothing new here we need to transclude</mylist>. Het lijkt erop dat Angular ook de $ $ voor ons zal doen.

.directive('mylist', function () {
  return {
    restrict:'E',
    replace: true,
    scope: true,
    template: [
      '<ul>',
      '<li ng-repeat="myItem in items">{{myItem}}</li>',
      '</ul>'
    ].join('')
  }
});

HTML:

<mylist></mylist>

Viool.

Houd er rekening mee dat het maken van een nieuwe scope optioneel is, dus je zou op deze regel kunnen reageren:

//scope: true,

Bijwerken: U kunt desgewenst een isolate scope maken:

scope: { items: '='},

HTML:

<mylist items=items></mylist>

Viool.

Update2: op basis van aanvullende informatie van Jan:

De sjabloon van het item moet worden gedefinieerd in de weergave ... Ik wil de logica in de ng-repeat-richtlijn opnieuw gebruiken

Oké, laten we het allemaal in de weergave plaatsen en ng-repeat gebruiken:

<ul mylist>
  <li ng-repeat="myItem in items">
    <span class="etc">{{myItem}}</span>
   </li>
</ul>

het [de richtlijn] moet toegang hebben tot een itemeigenschap in een onderliggende scope ... De richtlijn moet toegang hebben tot de lijst, zodat ik de juiste horloges kan instellen en dingen kan wijzigen

Volgend op je originele viool, gebruiken we een normale onderliggende scope (d.w.z. de onderliggende scope ervaart prototypisch van de bovenliggende scope): scope: true,. Dit zorgt ervoor dat de richtlijn toegang heeft tot de eigenschappen die zijn gedefinieerd op het bereik van de controller, bijvoorbeeld items.

toegang tot de gegenereerde DOM-items

De verbindingsfunctie van de richtlijn heeft een element argument. Dus in de HTML hierboven wordt het element ingesteld op de <ul>element. We hebben dus toegang tot alle DOM-elementen. bv element.find('li') of element.children(). In de viool waarnaar hieronder wordt verwezen, heb ik $ de items matrix. De $ watch callback heeft toegang tot element, zodat u toegang hebt tot de gegenereerde DOM-items. De terugroeplogboeken element.children() naar de console.

Viool.

Samenvattend, om gewoon gedrag aan een lijst toe te voegen, hoeft u slechts een richtlijn te plegen op een of andere manier.


5
2018-01-17 21:45