1

I want to make table directive, but i'm not sure how to do it. Here is my source code.

Directive:

InterfaceModule.directive('gList', function() {
    return {
        restrict: 'AEC',
        transclude: true,
        templateUrl: 'interface/gList.html'
    };
});

gList.html:

<table class="table table-condensed">
<tr>
    <td style="width: 20px">
        <span class="icon-f-gear-small"></span>
    </td>
    <td ng-transclude>

    </td>
</tr>
</table>

controller:

App.controller('ResultController', ['$scope', function($scope) {
    $scope.testItems = ['element 1', 'element 2', 'element 3']
}])

html code:

<div ng-controller="ResultController">
    <g-list>
        <a href="#" ng-click="someFunction()">{{item}}</a>
    </g-list>
</div>

I need to use ng-repeat in <tr> tag, although I don't want to use it in directive template, I want it to use in my main html file. If I use it in g-list tag (<g-list ng-repeat="item in testItems">) I am getting seperate table to each element in array, I need one table and number of rows which is equal to array size (in this case one table with 3 rows). So the question would be how to change my directive that works as I explained. Thanks in advance!

UPDATE

Thanks for answer. Now it's a bit more clear, but I still have several questions. The main Idea is that i want to have in final something like this:

<g-list icon="gear-small">
     <g-entry function="someFunction()">Sąrašo elementas 1</g-entry>
     <g-entry link="/some/url" count="20">Sąrašo elementas 2</g-entry>
     <g-entry link="/some/url" disabled="Netinkama objekto būsena">Sąrašo elementas 3</g-entry>
</g-list>

There will be entries where i will need to call function and there will be entries where I will have to go to some url on clik event.

2
  • Transclude is not appropriate here, see github.com/angular/angular.js/issues/7874 Commented Oct 2, 2014 at 10:51
  • Thanks for response! I'm quite new to directives, maybe you could help me to transform my directive into the one I want, or give some similar example? Commented Oct 2, 2014 at 11:01

2 Answers 2

1

Can you explain what you want to achieve and why you don't want to use the ng-repeat inside your directive ? Is it because you want to reuse the template somewhere else ? At first glance, I don't see any way to keep the directive at the table level without including the ng-repeat, unless you are ready to gut it completely and transclude all its contents. If you can live with a "tr" directive, this would be the simplest way to keep the ng-repeat out of your directive : I would limit the directive to the <tr> and put table directly in your html code.

<div ng-controller="ResultController">
    <table class="table table-condensed">
        <g-list ng-repeat="item in items" src="item" fcn="someFunction()">

        </g-list>
    </table>
</div>

With your template now looking like :

<tr>
    <td style="width: 20px">
        <span class="icon-f-gear-small"></span>
    </td>
    <td >
        <a href="#" ng-click="fcn()">{{src}}</a>
    </td>
</tr>

And your directive would need

scope {
   src:'=',
   fcn:'&'
}

Depending on what you want to achieve, and what your concerns with the ng-repeat are, there are other things to explore : you could use ng-include inside your template, you could possibly forego the transclusion and pass your function to your directive... More info would be appreciated.

(EDITED to remove the transclusion)

EDIT 2 : Ok, here is a barebone solution with two different entries. Some things can probably be improved, and the code might slightly change depending on your exact needs Postulate : your item looks like :

item : {
    type:yyy, // can take 'url' and 'function' 
    value:xxx
}

interface/entry1.html , with a function

<tr>
    <td style="width: 20px">
        <span class="icon-f-gear-small"></span>
    </td>
    <td >
        <a href="#" ng-click="fcn()">{{item.value}}</a>
    </td>
</tr>

interface/entry2.html , with a url

<tr>
    <td style="width: 20px">
        <span class="icon-f-gear-small"></span>
    </td>
    <td >
        <a href="{{item.url}}">{{item.value}}</a>
    </td>
</tr>

interface/gList.html, directive template (ng-repeat is back)

<table class="table table-condensed">
    <div ng-repeat="item in items" ng-switch="item.type">
        <ng-include src="'interface/entry1.html'" ng-switch-when="function"/>
        <ng-include src="'interface/entry2.html'" ng-switch-default/>
    </div>
</table>

directive.js

InterfaceModule.directive('gList', function() {
    return {
        scope {
            items:'=',
            fcn:'&'
        }
        restrict: 'AEC',

        templateUrl: 'interface/gList.html'
    };
});

html code

<div ng-controller="ResultController">
    <g-list items="myItems" fcn="someFunction()">
</div>

Please note that the directive scope is now isolated from your main scope, and thus cannot access any scope variables that you don't explicitely feed (here, items and fcn). This is usually a good practice if you want to avoid too much interaction and cluttering (although there is still some interaction possible : "=" denotes a two-way binding, so changing items in your directive will be refrlected in your main scope). Ang again, there are multiple ways to do it. You could, for example, forego the gList entirely and create a small directive for the gEntry instead, and loop over it. This way, you could feed the "type" directly into the directive instead of adding it to the item.

Sign up to request clarification or add additional context in comments.

2 Comments

Are the various entries totally arbitrary, or are there only a limited number of different types ? In the latter case, you could simply have your directive check the item your are processing and choose among several tr types (each could be an include, with a ng-switch to select the right one)
Yes it is limited number of types 3-5 I think. Could you update your answer with information you said now, I would be really grateful.
0

Took a little bit of tweaking from here, here's the code for a directive with a repeated inner template and scope to pass references:

app.directive('myTable', function($compile){
  return {
    restrict: 'E',
      scope: {
          items: '='
      },
      compile: function (tElement) {
          // Extract the children from this instance of the directive
          var children = tElement.children();

          var tableTemplate =
              '<table>' +
              '<tr ng-repeat="item in items">' +
                  '<td>first column</td>' +
                  '<td insert></td>' +
              '</tr>' +
              '</table>';

          var table = angular.element(tableTemplate);

          // Find the 'insert' attribute and append children
          angular.element(table[0].querySelector('[insert]'))
              .append(children)
              .removeAttr('insert');

          // Append this new template to the directive element
          tElement.html('');
          tElement.append(table);

          // Create a compile function that we can call from the linker
          var compile = $compile(table);

          return function(scope) {
              // In the linker, compile against the scope
              compile(scope);
          };
    }
  };
});

Here's an example in JSFiddle

If you want to import the template from elsewhere you can use the $templateCache

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.