Getter & poseur de soutien avec ng-model en AngularJs
J'essaie d'obtenir des getter/setter de soutien pour les ng-modèle de mise en œuvre d'une directive qui va prendre soin d'obtenir et de définir les valeurs de/à partir de la vue/modèle. Je suis presque là, mais j'arrive à la fin de l'infinie $digest boucles.
L'idée est de définir ng-model="$someFieldToStoreInTheScope", et puis avoir les getter/setter de la directive faire les mises à jour entre le champ et le getter/setter fonctions.
J'utilise $regarder pour mettre à jour le modèle à l'aide de l'incubateur expression lorsque le ngModelController met à jour le champ dans le champ d'application, et une autre montre de mettre à jour ce champ lors de la lecture des modifications de l'expression.
Jeter un oeil à: http://jsfiddle.net/BDyAs/10/
Html:
<div ng-app="myApp">
<body>
<form name="form">
<input type="text" ng-model="$ngModelValue" ng-model-getter-setter="get=getValue();set=setValue($value)"/> {{myDerivedValue}}
</form>
</body>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.directive(
{
'ngModelGetterSetter': function () {
return {
require: "ngModel",
controller: ctrl,
link: function(scope, element, attrs, ngModelCtrl)
{
var getterSetterExpression = attrs.ngModelGetterSetter;
var tokens = getterSetterExpression.split(";");
var getExpression = tokens[0].split("=")[1];
var setExpression = tokens[1].split("=")[1];
function updateViewValue()
{
var updateExpression = attrs.ngModel + "=" + getExpression;
scope.$eval(updateExpression);
}
function updateModelValue()
{
scope.$value = ngModelCtrl.$viewValue;
scope.$eval(setExpression);
}
updateViewValue();
scope.$watch(getExpression, updateViewValue);
scope.$watch(attrs.ngModel, updateModelValue);
}
};
}
});
function ctrl($scope) {
$scope.getValue = function ()
{
return $scope.myValue;
}
$scope.setValue = function (val)
{
$scope.myValue = val;
$scope.myDerivedValue = $scope.myValue * 2;
}
$scope.setValue(5);
setInterval(function () { $scope.setValue($scope.getValue() + 1); $scope.$apply(); }, 1000);
}
J'ai mis un setInterval() dans mon code pour modifier le modèle et voir si elle se propage correctement dans la vue.
Aucune idée pourquoi il y a une infinité de digérer la boucle, et comment le supprimer?
Oui, la question est qu'il ne fonctionne pas bien à cause de l'infinie digérer boucle. Pourquoi est-ce que la boucle là et comment l'enlever?
L'infini digérer boucle semblent être causée par angularjs avoir un moment difficile la propagation de la nouvelle valeur partout avant qu'il se propage à l'ancienne valeur, dans la même boucle. Je pouvais briser la boucle en ajoutant les appels à ngModelCtrl.$setViewValue() et ngModelCtrl.$render() dans le updateViewValue() fonction (Violon: jsfiddle.net/BDyAs/12), mais il serait intéressant de savoir plus précisément ce qui se passait, et si la façon dont je me suis cassé la boucle est la meilleure façon de le faire.
Je pense que la boucle infinie est parce que sur changeValue la montre est l'appel de la méthode de jeu qui, en fait, c'est de modifier le modèle... de sorte que la montre est de nouveau appelée. Peut-être que vous pouvez essayer quelque chose comme "si réel!=nouveau --> mise à jour d'autre --> ne rien faire".
OriginalL'auteur sboisse | 2014-01-22
Vous devez vous connecter pour publier un commentaire.
NOTE AngularJs 1.3 supporte maintenant les Getter/Setter pour ng-model. Reportez-vous à http://docs.angularjs.org/api/ng/directive/ngModelOptions pour plus d'informations.
Je pouvais briser la boucle infinie avec des appels supplémentaires
et
dans les gestionnaires d'événements. Pas sûr si c'est la meilleure façon de le faire bien.
Voir violon: http://jsfiddle.net/BDyAs/12/
EDIT:
J'ai amélioré le code encore plus dans
http://jsfiddle.net/BDyAs/15/
par la séparation de la directive dans le séparé pour le getter et le setter.
C'est une très bonne nouvelle. Si vous pouvez fournir un lien vers la newsletter, ce serait super!
Je pense que cela pourrait être ce que @DrogoNevets faisait allusion (à noter qu'il est angulaire 1.3, non compris dans d'1.2): docs.angularjs.org/api/ng/directive/ngModelOptions
On dirait qu'IL est. J'ai ajouté une note à la réponse. Merci pour le partage.
OriginalL'auteur sboisse
Je pense que la question de la rupture de l'empreinte de la boucle a été répondu. Voici un autre, beaucoup plus propre d'aborder le même problème qui n'implique pas de
$watch
.Lorsque vous n'avez pas besoin de soutenir les anciens navigateurs, l'utilisation ECMAScript 5 accesseurs.
Il suffit d'ajouter une propriété à votre angulaire de contrôleur:
Maintenant tout ce que vous devez faire est de référence
accessorWrappedMyValue
deng-model
comme suit:Lecture
Ce blog a une belle introduction à l'ES5 accesseurs.
Utilisation cette caractéristique de la matrice de décider si vous pouvez aller avec ES5 ou pas. Les lignes intéressantes sont "Getter /Setter de la propriété de l'initialiseur" et "Objet.defineProperty".
OriginalL'auteur theDmi