2013-12-11 52 views
0

当我$编译包含指令的元素时,我看到指令的行为不一致。在我的情况下,我有一个指令来验证密码是否与另一个密码字段匹配。该指令看起来像这样:AngularJS:用另一个指令编译元素会改变行为

app.directive('passwordMatches', function() { 
return { 
    require: 'ngModel', 
    restrict: 'A', 
    scope: { 
     otherPasswordFieldValue: '=passwordMatches' 
    }, 
    link: function (scope, elem, attrs, ngModelController) { 
     function validate(value) { 
      return value === scope.otherPasswordFieldValue; 
     } 

     //For DOM -> model validation 
     ngModelController.$parsers.unshift(function (value) { 
      var valid = validate(value); 
      ngModelController.$setValidity('password-matches', valid); 
      return valid ? value : undefined; 
     }); 

     //For model -> DOM validation 
     ngModelController.$formatters.unshift(function (value) { 
      ngModelController.$setValidity('password-matches', validate(value)); 
      return value; 
     }); 

     scope.$watch(function() { return scope.otherPasswordFieldValue }, function() { 
      var valid = validate(ngModelController.$viewValue); 
      ngModelController.$setValidity('password-matches', valid); 
     }); 
     } 
    }; 
}); 

这个工作很好。但我有另一个指令,经常在同一个元素上使用。该指令的细节并不重要,因为我已经证明问题的根源在于第二个指令编译元素。只要我添加这个指令,行为就会改变。没有编译元素,我的passwordMatches指令工作正常(如果我输入的内容与其他字段不匹配,并且我可以输入任何我想要的内容,则该字段将变为无效)。

只要我编译元素,我可以键入我想要的东西,直到我使字段匹配,并且它的行为正常,直到那一点。但是,一旦两个字段中的值匹配,如果输入任何内容以使它们不匹配,则该字段将完全消失。最简单的方法是在这个jsbin中:http://jsbin.com/IkuMECEf/12/edit。要重现,请在第一个字段中输入“foo”,然后尝试在第二个字段中输入“fooo”(三个)。只要你输入第三个“o”字段就会被删除。如果你注释掉$ compile,它可以正常工作。

谢谢!

+0

什么是在第二个指令'$ compile'的目的是什么?目前只在'input'上运行,没有看到任何需要在demo中编译的东西 – charlietfl

+0

是的,我不想让这些细节复杂化演示。这是另一个向元素添加验证相关ng-class的指令。我需要一个指令来执行此操作,因为ng类内容是基于正在执行的验证类型而动态的。由于它添加了一个角度指令,它需要再次编译该元素。 –

+0

也许可以使用返回类的函数? '纳克级= “vaildationClass()”'。 – charlietfl

回答

0

第二个指令是编译已经由Angular编译的dom元素。这第二次编译增加了第二个$watch,解析器等,因为所有的指令的链接功能再次被调用(here's a good detailed look at $compile)要确认这一点,你可以把console.log放在$watch中,你会看到(用第二个指令)每一次更改 - 因为重复的$watch(删除第二个指令,它只会触发一次 - 如预期的那样)。第二个编译步骤不仅会导致您遇到的问题,还可能导致其他问题。

如果您必须重新编译一个Angular元素,那么您首先需要删除现有的元素。

这里有一个办法处理这一(解释在评论):

compile: function(compileElement) { 
    compileElement.removeAttr('another-directive'); 
    return function(scope, element) { 

    // Create an "uncompiled" element using a copy of the current element's html 
    newe = angular.element(element.html()); 

    // Remember where we were 
    parent= element.parent(); 

    // Deleting the current "compiled" element 
    element.remove(); 

    // Add the uncompiled copy 
    parent.append(news); 

    // Compile the copy 
    $compile(newe)(scope); 
    }; 

updated punker

+1

将元素移动到父级之外...更简单'element.after(newe); element.remove();' – charlietfl

+0

@charliefl好点。在这个问题上将会非常简短地包含这两个要素 - 但它应该如此简短以至于它没有任何实际的影响。 – KayakDave

+0

想知道我自己...可能会包装跨度可能然后解开跨度后 – charlietfl

相关问题