2016-04-20 16 views
0

Ich habe einen Winkel Controller wie folgt:beobachten mehrere Variablen mit vollständiger Name unbekannt

function SignUpController($window, accountService) { 

    var vm = this; 
    vm.errors = null; 
    vm.user = null; 

    vm.submit = function (user) { 

    accountService.signup(user) 

     .then(function (response) {  
     $window.location.href = "/"; 
     }) 

    .catch(function (response) { 
     vm.errors = response.data.errors; 
    } 

    }; 

} 

Die API eine Liste der Fehler zurückgibt, falls sie vorhanden sind, wie folgt:

[ 
    {code: "name", "message": "the name is required"} 
] 

Wenn Sind Fehler, füge ich diese Liste zu vm.errors hinzu. In HTML habe ich:

Die Direktive beobachtet vm.errors und füllt alle Spannen mit Validatoren mit der richtigen Fehlermeldung.

In meinen Controllern verwende ich immer vm.errors, aber in meinem HTML verwende ich oft etwas anderes, wie vmsignup, da ich vielleicht mehrere Controller habe.

So in diesem Beispiel die Richtlinie muss vmsignup.errors haben, damit es funktioniert:

angular.module("app").directive("validator", validator); 
validator.$inject = ["$parse"]; 

function validator($parse) { 

    var validator = { 
    link: link, 
    replace: false, 
    restrict: "A" 
    }; 

    return validator; 

    function link(scope, element, attributes) { 

    scope.$watch("vmsignup.errors", function (errors) { 

    if (errors) { 

     var result = errors.filter(function (error) { 

     if (error.code == null) 
      return false; 

     var position = attributes.validator.lastIndexOf("."); 

     if (position > -1) 
      return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase(); 
     else 
      return attributes.validator.toLowerCase() === error.code.toLowerCase(); 

     });   

     if (result.length > 0) { 
     element.show().text(result[0].message); 
     return; 
     } 

    } 

    element.hide(); 

    }); 
} 

ich die Direktive wie etwas haben möchte:

scope.$watch("vm*.errors", ... 

Ich nehme an, dies ist unmöglich, aber Es muss einen Weg geben, das zu lösen, oder?

ich glaube, die Lösung könnte eine neue Richtlinie „Validierung“ auf dem Formular verwendet hat, zu sagen, was das Modell ist:

<form name="form" ng-controller="SignUpController as vmsignup" validation-model="vmsignup"> 

Dann würde ich dies auf der Validator-Direktive verwenden:

scope.$watch(validator.model + ".errors", function (errors) { 

Ist das eine gute Option? Kann das gemacht werden? Kann mir jemand helfen?

+0

Sie sollten das Problem, das Sie lösen möchten, besser beschreiben. Vielleicht zeige ich mehr Code .. Ich glaube, dass Sie eine andere Lösung wählen könnten, um dasselbe Ergebnis zu erzielen. – manzapanza

+0

@manzapanza Fair genug. Ich habe gerade meine Frage mit mehr Code aktualisiert und erklärt, was ich mache und was das "kleine" Problem ist, das ich lösen möchte. Hilft der zusätzliche Code und die zusätzlichen Informationen? Ich habe nichts vermisst. –

Antwort

0

Sie können zu diesem Zweck $ Watchgroup verwenden

+0

Aber kann ich "vm * .errors" in der Watchgroup verwenden, wo * irgendwas bedeutet? Denken Sie daran, dass vmsignup nur ein Beispiel ist ... Ich könnte vm * in meiner Anwendung haben –

+0

Lesen über whatchGroup Ich glaube nicht, dass es Ausdrücke akzeptiert ... Die Werte müssen gut definiert sein ... –

+0

Ja. Ausdrücke arbeiten nicht mit irgendwelchen $ watchers zusammen. Wenn Sie wissen, dass Ihre Variablen vorher überwacht werden müssen, können Sie $ watchGroup verwenden. – Ambegodas

0

Sie kein * als Platzhalter in einem $watch Ausdruck verwenden können, aber Sie können mit $watchCollection ...

Eine Reihe von zum Beispiel eine Sammlung beobachten Eigenschaften:

$scope.$watchCollection('[prop1, prop2]', function(newValues, oldValues){ 
    var newProp1 = newValues[0]; 
    var newProp2 = newValues[1]; 
}); 

ein Array von Funktionen Wert zurückkehr:

UPDATE

als @Ambegodas sagte, können Sie die errors Sammlung als Parameter an Ihre Richtlinie übergeben. So Ihr Code werden:

angular 
    .module("app") 
    .directive("validator", validator); 

validator.$inject = ["$parse"]; 

function validator($parse) { 

    var validator = { 
    link: link, 
    replace: false, 
    restrict: "A" 
    }; 

    return validator; 

    function link(scope, element, attributes) { 

    scope.$watch(attributes.errors, function (errors) { 

     if (errors) { 

     var result = errors.filter(function (error) { 
      if (error.code == null) return false; 
      var position = attributes.validator.lastIndexOf("."); 
      if (position > -1) { 
      return attributes.validator.slice(position + 1).toLowerCase() === error.code.toLowerCase(); 
      } 
      return attributes.validator.toLowerCase() === error.code.toLowerCase(); 
     }); 

     if (result.length > 0) { 
      element.show().text(result[0].message); 
      return; 
     } 
     } 

     element.hide(); 

    }, true); // << objectEquality == true 

    } 
} 

DIFFERENT VORSCHLAG

Sie könnten Serverseite Validierungen für diejenigen Eingangs erstellen, die Sie nicht nur mit Client-Seite Validierungen validieren können.

HTML:

<form name="form" novalidate ng-submit="vm.submit(vm.account)"> 

    <div class="form-group" mt-show-errors> 
    <label class="control-label" for="username">Username</label> 
    <input type="text" mt-validate-username class="form-control" name="username" id="username" ng-model="vm.account.username" required> 
    <div ng-show="form.$submitted || form.username.$touched"> 
     <span ng-show="form.login.$error.required" class="help-block">Username is required</span> 
     <span ng-show="form.login.$error.mtValidateUsername" class="help-block">Username already taken</span> 
    </div> 
    </div> 

    <!-- more inputs --> 

</form> 

RICHTLINIE:

angular 
    .module('app.directives') 
    .directive('mtValidateUsername', mtValidateUsername); 

    function mtValidateUsername($timeout, MyAccountService) { 
    return { 
     require: 'ngModel', 
     scope: false, 
     link: function (scope, element, attrs, modelCtrl) { 
     var timeoutId; 
     modelCtrl.$parsers.push(function (inputValue) { 
      if (!inputValue) return ''; 
      $timeout.cancel(timeoutId); 
      timeoutId = $timeout(function() { 
      MyAccountService.validateUsername(inputValue).then(function() { 
       modelCtrl.$setValidity('mtValidateUsername', true); 
      }).catch(function(){ 
       modelCtrl.$setValidity('mtValidateUsername', false); 
      }); 
      }, 1000); // 1 second throttle 
      return inputValue; 
     }); 
     } 
    }; 
    } 
+0

Ja, ich weiß, aber das ist keine gute Lösung, da ich eine Sammlung aller Namen von Ansichtsmodellen innerhalb der Direktive haben müsste ... So etwas schwer zu kontrollieren. Kann eine Validierungsanweisung erstellt werden und der Validator darauf zugreifen? Siehe meine aktualisierte Frage ... Danke. –

+0

@MiguelMoura Hast du gesehen, dass ich meine Antwort aktualisiert habe? – manzapanza

0

Bitte versuchen Sie es unten Ansatz.

 var app = angular.module('MyApp',[]); 

    app.controller('MyCtrl',function($scope){ 
    $scope.errors =1; 
    $scope.change = function(){ 
     $scope.errors = 2; 
    } 

}); 

    app.directive('myDirecitive',function(){ 

    return { 
     restrict:'A', 
     link:linkFunction 
    } 

    function linkFunction(scope,element,atrrs){    

     scope.$watch(atrrs.varName,function(newval,oldval){ 
     console.log("watcher called"); 
     }); 
    } 

}); 

    <body ng-app="MyApp", ng-controller="MyCtrl"> 
    <h1>Sample Application</h1> 
    <input type="text" my-direcitive var-name="errors"/>  
    <button ng-click="change()">Watch</button>  
    </body> 
+0

Meine Idee war, eine Anweisung namens validation-errors = "errors" auf dem Formularlabel zu haben, anstatt sie in allen Eingängen zu haben, da sie in allen gleich ist ... –

+0

Ja. Das ist ähnlich wie bei Ihnen. Ich habe es getestet und es funktioniert. Die Art und Weise, wie ich auf die Variable innerhalb der Direktive zugreife, ist etwas anders. – Ambegodas

Verwandte Themen