How to use "ng-repeat" within template of a directive in Angular JS?

AngularjsAngularjs DirectiveAngularjs Ng-Repeat

Angularjs Problem Overview


I'm new to Angular JS and I am trying to create a custom directive that will be used as below:

<div linkedlist listcolumns="{{cashAccountsColumns}}"></div>

Corrps. controller will be:

$scope.cashAccountsColumns = [
  {"field": "description", "title": "Description"},
  {"field": "owner", "title":"Owner"},
  {"field": "currentBalance", "title":"Current Balance" }
];

And the directive code is:

return {
      restrict : 'EA',
      transclude : false,
      templateUrl : 'html/linkedlist.html',
      scope: {
         listcolumns: "@"
      },
      link : function(scope, element, attrs) {
      }
}

template is:

<table class="box-table" width="100%">
  <thead>
    <tr>
      <th scope="col" ng-repeat="column in listcolumns">
        {{column.title}}
      </th>
    </tr>
  </thead>
</table>

But this is not working. I'm not getting the value of column.title on screen instead too many rows as below are added to DOM:

<th ng-repeat="column in listcolumns" scope="col" class="ng-scope ng-binding"></th>

Angularjs Solutions


Solution 1 - Angularjs

Passing an entire object with attribute will not work, you have to use dual way binding. Just change binding from @ to = and modify the HTML below to make it work:

changes to directive code:

// ...
scope: {
    listcolumns: "="
},
// ...

changes to template:

  <div linkedlist listcolumns="cashAccountsColumns"></div>

Solution 2 - Angularjs

@AjayBeniwal's answer is correct, but I feel as though it could use some additional explanation.

As the Angular documentation points out (in the "Isolating the Scope of a Directive" section), the scope option is an object that contains a property for each isolate scope binding. We use it to separate (isolate) the scope inside a directive from the scope outside, and then map the outer scope to the directive's inner scope.

The name of each property of the scope object corresponds to the directives isolate scope property. In the question's example, the only property of the scope object is listcolumns. Because of this, there must also be a corresponding attribute on the html creating the directive:

<div linkedlist listcolumns="cashAccountsColumns"></div>

The name of the scope property and the directive's attribute are not however required to have the same name. We can map these two values like this:

<div linkedlist short-name="cashAccountsColumns"></div>

-

controller: function ($scope) {
    $scope.cashAccountsColumns = 'value';
},
scope: {
     moreDescriptiveName: "=shortName"
},

For cases where the attribute name is the same as the value you want to bind inside the directive's scope, you can use this shorthand syntax:

<div linkedlist my-name="cashAccountsColumns"></div>

-

controller: function ($scope) {
    $scope.cashAccountsColumns = 'value';
},
scope: {
     myName: "="
},


Additionally, in this example the value of the directive's attribute must correspond to a property of the directive's outer scope. This is because the = in =shortName uses bi-directional binding of attributes from the outer scope to the isolate scope, forcing the value of the directive's attribute to be evaluated as an expression. As this answer eloquently points out, if we instead want to pass a literal string, we can either use @ in place of =, or sorround the directive's isolate scope property with both double and single quotes:

scope: {
     moreDescriptiveName: "@"
},

OR

<div linkedlist short-name="'cashAccountsColumns'"></div>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2401127View Question on Stackoverflow
Solution 1 - AngularjsAjay BeniwalView Answer on Stackoverflow
Solution 2 - AngularjsZach PostenView Answer on Stackoverflow