2017-03-08 32 views
2

任何人都可以帮助我解决在ng-repeat内编译指令时的范围界定问题吗?自定义指令无法在ng-repeat内编译

https://plnkr.co/edit/y6gfpe01x3ya8zZ5QQpt?p=preview

自定义指令input-by-type可以取代<div>基于变量类型适当<input> - 直到ng-repeat内使用能正常工作。

正如您在plnkr示例中所看到的,该指令按预期工作,直至在ng-repeat内使用。

如果我手动引用inputs[0]编译input-by-type指令,它工作得很好:

<label> 
    {{ inputs[0].name }} 
    <div input-by-type="{{ inputs[0].type }}" name="myInputA" ng-model="data.A" ng-required="true"></div> 
</label> 

然而,那一刻我在ng-repeat块把这个包,编译失败,一些意想不到的输出:

<label ng-repeat="input in inputs"> 
    {{ input.name }} 
    <div input-by-type="{{ input.type }}" name="myInput{{ $index }}" ng-model="data[input.id]" ng-required="true"></div> 
</label> 

预期输出:

Expected


实际输出:

Actual

回答

2

的postLink功能缺失elementattrs参数:

app.directive('inputByType', ['$compile', '$interpolate', function($compile, $interpolate){ 
    return { 
     restrict: 'A', // [attribute] 
     require: '^ngModel', 
     scope: true, 
     // terminal: true, 
     compile: function(element, attrs, transclude){ 
      var inputs = { 
       text: '<input type="text" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="...">', 
       email: '<input type="email" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="[email protected]">', 
       number: '<input type="number" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="###">', 
       // image upload (redacted) 
       // file upload (redacted) 
       // date picker (redacted) 
       // color picker (redacted) 
       // boolean (redacted) 
      }; 
      //return function(scope){ 
      //USE postLink element, attrs 
      return function postLinkFn(scope, element, attrs) { 
       var type = $interpolate(attrs.inputByType)(scope); // Convert input-by-type="{{ some.type }}" into a useable value 
       var html = inputs[type] || inputs.text; 
       var e = $compile(html)(scope); 
       element.replaceWith(e); 
       console.log(type, html, element, e); 
      }; 
     }, 
    }; 
}]); 

通过省略elementattrs参数,postLink函数创建一个闭包并使用compile函数的参数elementattrs。即使$ compile服务使用正确的参数调用postLink函数,它们也被忽略,而是使用编译阶段版本。

这会导致ng-repeat出现问题,因为它会克隆元素以将其附加到新的DOM元素。

+0

我知道的postLink参数但是它并没有醒悟过来了,他们可以根据相位不同。谢谢。 – oodavid

0

@ georgeawg的答案是正确的,但是我遇到了第二个问题,我将在下面概述一个解决方案。

问题:ngModel不会按预期行事($pristine/$dirty等属性将不可用,也不会传播到容器formCtrl)。

为了解决这个问题,我跟着这个答案的建议:https://stackoverflow.com/a/21687744/1122851和改变了postLink被编译的元素,像这样的方式:

var type = $interpolate(attrs.inputByType)(scope); 
var html = inputs[type] || inputs.text; 
var template = angular.element(html); 
element.replaceWith(template); 
$compile(template)(scope); 

我才明白,require: 'ngModel'scope: trueterminal: true没有无论如何,它们都是我各种测试中的遗物。最终代码:

app.directive('inputByType', ['$compile', '$interpolate', function($compile, $interpolate){ 
    return { 
     restrict: 'A', // [attribute] 
     compile: function(element, attrs, transclude){ 
      var inputs = { 
       text: '<input type="text" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="...">', 
       email: '<input type="email" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="[email protected]">', 
       number: '<input type="number" name="'+attrs.name+'" ng-model="'+attrs.ngModel+'" ng-disabled="'+attrs.ngDisabled+'" ng-required="'+attrs.ngRequired+'" placeholder="###">', 
       // image upload (redacted) 
       // file upload (redacted) 
       // date picker (redacted) 
       // color picker (redacted) 
       // boolean (redacted) 
      }; 
      return function postLinkFn(scope, element, attrs) { 
       var type = $interpolate(attrs.inputByType)(scope); // Convert input-by-type="{{ some.type }}" into a useable value 
       var html = inputs[type] || inputs.text; 
       var template = angular.element(html); 
       element.replaceWith(template); 
       $compile(template)(scope); 
      }; 
     }, 
    }; 
}]); 

演示:https://plnkr.co/edit/ZB5wlTKr0g5pXkRTRmas?p=preview

相关问题