angularjs, $compiled templates and ng-repeat

北战南征 提交于 2019-12-12 03:37:20

问题


Essentially, I take two templates inside a compile function of a directive. I compile them once and for all (via $compile) in the compile phase of the directive. In the link phase of the directive, I watch a scope variable and applies one or the other compiled template to the scope.

testApp.directive('testField', ['$compile', function ($compile) {
  return {
    restrict: 'E',
    scope: true,
    compile: function(tElement, tAttrs) {
      var viewFn = $compile("<div>View: <span ng-repeat='x in [1,2,3]'>{{x}}</span></div>");
      var editFn = $compile("<div>Edit: <span ng-repeat='x in [4,5,6]'>{{x}}</span></div>");

      return function (scope, element, attrs) {
        var innerScope = null;

        scope.$watch("mode", function (mode) {
          if (innerScope) innerScope.$destroy();
          innerScope = scope.$new();

          if (mode == 'VIEW') {
              element.empty().append(viewFn(innerScope));
          } else {
              element.empty().append(editFn(innerScope));
          }
        });
      };
    }
  };
}]);

It works fine, except when the template includes a Ng-repeat that is not the root element in which case it behave strangely:

To reproduce, go to http://plnkr.co/edit/RCqlNWTVdXVoMQCkFcQn?p=preview And switch a couple of time from Edit to View.

You'll notice the number of iterations of ng-repeat grows over time. First time, it displays 123 and 456, like it should

After the first back and forth between view and edit, it displays 123123 and 456456

And it keeps adding one iteration every time you do a back and forth between view and edit.


回答1:


I probably found the solution shortly after posting.

The problem apparently lies in the fact that ng-repeat needs to clone the template.

After stumbling on a comment in the angular source, turns out we can pass a second argument to the function returned by compile.

This second argument is a function that is called with a clone of the template (and the scope being linked to).

so instead of

      if (mode == 'VIEW') {
          element.empty().append(viewFn(innerScope));
      } else {
          element.empty().append(editFn(innerScope));
      }

I can do

      function setElts(elts) {
         element.empty().append(elts);
      }

      if (mode == 'VIEW') {
        viewFn(innerScope, setElts);
      } else {
        editFn(innerScope, setElts);
      }



回答2:


Maybe you can do like this.

Firstly, you inject new dom directly in your view. After, catch it and apply $compile.

like this;

var viewFn = "<div>View: <span ng-repeat='x in [1,2,3]'>{{x}}</span></div>";
...
element.html(viewFn);
...
$compile(tElement.contents())(innerScope);


来源:https://stackoverflow.com/questions/31957525/angularjs-compiled-templates-and-ng-repeat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!