2013-12-11 78 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

相關問題