Mike Sav
Mike Sav

Reputation: 15311

AngularJS - Can I change the value / expersion of ng-repeat in View using a directive

I have a hypothetical question. Say I have two object arrays in my Controller and in my view I loop through the data of one of these object arrays. Now is it possible for me to switch the value of this ng-repart (or change the expression) in a directive. For example...

here is my controller:

controller('MainCtrl', ['$scope', function($scope) {
            $scope.beatles = [{id:1, name: "John", inst: "Guitar", alive: false},{id:2, name: "Paul", inst: "Bass", alive: true},{id:3, name: "George", inst: "Guitar", alive: false},{id:4, name: "Ringo", inst: "Drums", alive: true}];

            $scope.huskers = [{id:1, name: "Bob", inst: "Guitar", alive: true},{id:2, name: "Grant", inst: "Drums", alive: true},{id:3, name: "George", inst: "Bass", alive: true}];
    }])

Here is my view...

<div data-my-template-dir class="beatles">
        <div data-ng-repeat="beatle in beatles track by $index">
          Name: {{beatle.name}}, Instrument: {{ beatle.inst }}
        </div>
</div>

Here is my directive...

restrict: 'A',
link: function (scope, element) {
  element.bind('click', function () {
     console.log('i am clicked');
     element[0].children[0].setAttribute('data-ng-repeat','beatle in huskers track by $index');
     // something should go here... like scope.apply() ???? 
});

Now, it seems that the directive does work with the model/ctrl... but the HTML doesn't seem to update in the view... am I going about this wrong, can I update the ng-repeat in the directive?

I have a plunker (or jsbin) here: https://jsbin.com/fasako/edit?html,output

Upvotes: 1

Views: 70

Answers (2)

Frank Bryce
Frank Bryce

Reputation: 8446

OK, so I have a couple of comments.

First, I think there is a better to accomplish what you want. Instead of editing the markup, in order for angular to reprocess the markup, in order for it to load different data into memory, in order to put it's own processed markup on the screen.... while making for a remarkable run-on sentence probably isn't the best programming decision.

I'd suggest just having one object with all of your data, then have an ng-click item which chooses which array to process in the ng-repeat.

I came up with the following example.

angular.module('myModule',[])
.directive('myTemplate', function() {
  return {
    restrict: 'A',
    template: 
      '<div ng-repeat="item in lists[listSelected] track by $index">' +
        'Name: {{item.name}}, Instrument: {{ item.inst }}' +
      '</div>',
    controller: 'myTemplateCtrl'
  };
})
.controller('myTemplateCtrl', ['$scope', function($scope) {
  $scope.listSelected = 'beatles';
  
  $scope.lists = 
    { 
      beatles:
      [
        { id:1, name: "John", inst: "Guitar", alive: false },
        { id:2, name: "Paul", inst: "Bass", alive: true },
        { id:3, name: "George", inst: "Guitar", alive: false },
        { id:4, name: "Ringo", inst: "Drums", alive: true }
      ],
      huskers:
      [
        { id:1, name: "Bob", inst: "Guitar", alive: true },
        { id:2, name: "Grant", inst: "Drums", alive: true },
        { id:3, name: "George", inst: "Bass", alive: true }
      ]
    }
  ;
  
  // this should only be bound to scope once the arrays exist
  $scope.changeSelection = function() {
    $scope.listSelected = $scope.listSelected === 'beatles' ? 'huskers' : 'beatles';
  };
}]);
body {
  font-family: "Comic Sans MS", "Lucida Sans Unicode", "Lucida Grande", sans-serif;
}
    
.beatles {
  padding: 10px;
  border: 1px solid lightblue;
  background-color: aliceblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myModule">
  <div my-template ng-click="changeSelection()" class="beatles"></div>
</div>

Upvotes: 1

Avraam Mavridis
Avraam Mavridis

Reputation: 8920

You have to use $compile to compile again your ng-repeat and then append it to the DOM

Something like:

element[0].children[0].setAttribute('data-ng-repeat','beatle in huskers track by $index');
newRepeat = element[0].children[0].html()
template = $compile(newRepeat)($scope)
element.children[0].replaceWith(template)

Upvotes: 0

Related Questions