angularjsangularjs-directiveangularjs-scopeangularjs-compile

Dynamically create directives from a loop


I have a main directive that has an array on it's scope that contains data for constructing other directives that should be compiled and appended to the main directive.

The problem is that when I iterate through that array I only get the data from the last element in array, so I can't properly bind respective data for each custom directive.

Plunker

main directive :

 angular.module('testApp')
   .directive('mainDirective', ["$compile", function ($compile) {

    return {
       template:   ' <div><p>Main Directive </p><div class="insertion-point"></div></div>',

       link: function (scope, element, attributes, controller) {

          var insertionPoint = element.find('.insertion-point');

          angular.forEach(scope.demoObj.panels, function (value, index) {


              var directiveName = value.type;

              scope.value = value;
              var directiveString = "<div " + directiveName + " panel-data=value ></div>";

              var compiledElement = $compile(directiveString)(scope);

              insertionPoint.append(compiledElement);

        });
    }


    }


}]);

directive to be nested:

 angular.module('testApp')
 .directive('nestedDirective', [function () {

    return {

       scope:{
         panelData:'='
       },
       template:' <div><p>Nested Directive </p>{{panelData.data.test}}</div>'
    }
}]);

data looks like this:

                  $scope.demoObj = {

              panels:[
                {
                    id:'unique_id_1',
                    type:'nested-directive',
                    data:{
                      test:'test 1'
                    }
                },
                {
                    id:'unique_id_2',
                    type:'nested-directive',
                    data:{
                      test:'test 2'
                    }
                },
                {
                    id:'unique_id_3',
                    type:'nested-directive',
                    data:{
                      test:'test 3'
                    }
                }

            ]
        }

As far as I can understand , the compilation is not happening immediately in the forEach statement, that's why every directive gets the data from the object with the id unique_id_3 (last element in array). Also all directives have isolated scope.

edit: I understand that in forEach I need to add the value to the scope so I can pass it to the nested directive isolated scope, and I understand that when the loop finishes scope.value will be the last value of the loop, but I was under the impression that compile will immediately pass the value to the nested directive and be done with it.

So, when does the compilation happen?

How can I circumvent this limitation?


Solution

  • The problem is the link step of the compiledElement will happen in the next digest cycle, at that time, scope.value is the last value of the data.

    The solution is to create different value properties on scope, like this:

    var directiveName = value.type;
    var valueProp = 'value' + index;
    scope[valueProp] = value;
    var directiveString = "<div " + directiveName + " panel-data=" + valueProp + "></div>";
    

    plunk