web-dev-qa-db-fra.com

AngularJS - Flou + modifié?

Quel est le moyen le plus simple de combiner ng-changé et ng-blur?

J'ai trouvé ce post: Comment laisser ng-model ne pas mettre à jour immédiatement?

Cependant, cela ne fonctionne plus dans angluar 1.2+. Existe-t-il un moyen d'obtenir le même comportement?

Je suppose que je dois stocker moi-même une copie de l'ancienne valeur et comparer la nouvelle valeur à celle sur flou si j'essaie de faire de même, ou existe-t-il un moyen plus simple?

19
Roger Johansson

Cela fait ce que je veux. Il stocke la valeur sur le focus et la compare à la nouvelle valeur de flou; s'il est modifié, il déclenche l'expression dans l'attribut.

 app.directive('changeOnBlur', function() {
            return {
                restrict: 'A',
                require: 'ngModel',
                link: function(scope, Elm, attrs, ngModelCtrl) {
                    if (attrs.type === 'radio' || attrs.type === 'checkbox') 
                        return;

                    var expressionToCall = attrs.changeOnBlur;

                    var oldValue = null;
                    Elm.bind('focus',function() {
                        scope.$apply(function() {
                            oldValue = Elm.val();
                            console.log(oldValue);
                        });
                    })
                    Elm.bind('blur', function() {
                        scope.$apply(function() {
                            var newValue = Elm.val();
                            console.log(newValue);
                            if (newValue !== oldValue){
                                scope.$eval(expressionToCall);
                            }
                                //alert('changed ' + oldValue);
                        });         
                    });
                }
            };
        });

usage:

 <input ng-model="foo" change-on-blur="someFunc()" />
14
Roger Johansson

Utilisez ng-model options. De cette manière, ng-change ne se déclenche que lorsque l'entrée est floue.

<input type="text" 
       ng-model="a.b" 
       ng-model-options="{updateOn: 'blur'}" 
       ng-change="onchange()"/>
43
Niels Steenbeek

Que diriez-vous de cette solution. Travaille pour moi:

<input ng-init="oldValue = value" ng-model="value"
       ng-blur="oldValue != value && callYourFunc(foo)">
4
Michael

que diriez-vous ce plunkr ?

en utilisant le ng-blur construit par angular, mettez à jour votre "valeur persistante" sur le flou

<input type="text" ng-model="boxValue" ng-blur="doneEditing(boxValue)">

lors de la sauvegarde, vérifiez que la valeur est différente

$scope.doneEditing = function(v) {
  if (v !== $scope.persistedValue) // only save when value is different
    $scope.persistedValue=v;
}

À ma connaissance, il n'y a pas d'option spéciale sur ng-blur pour la pré-vérification de l'égalité. Un simple if semble faire l'affaire

3
Chris Montgomery

J'utilise AngularJs 1.2.x et je suis tombé sur le problème du changement, qui consiste à tirer sur chaque changement. ng-blur peut être utilisé mais il se déclenche même s'il n'y a pas de changement dans la valeur. Donc, les deux ne peuvent pas être utilisés efficacement.

Avec Angularjs 1.3.x, les choses sont plus simples avec ng-model-options comme ci-dessous

invoquer la fonction de changement "onBlur"  

ng-change="ctrl.onchange()" ng-model-options="{updateOn: 'blur'}"

Et 

retarder l'invocation de la fonction de changement de 500 ms  

ng-change="ctrl.onchange()" ng-model-options='{ debounce: 500 }'"

Revenons maintenant à la question d'obtenir de telles choses avec AngularJs 1.2.x

invoquer la fonction de changement "onBlur"

html

<input type="text" ng-model="ctrl.a.c" sd-change-on-blur="ctrl.onchange()" /> Or

<input type="text" ng-model="ctrl.a.c" sd-change-on-blur="ctrl.onchange(ctrl.a.c)" />

JS 

app.directive('sdChangeOnBlur', function() {
  return {
    restrict: 'A',
    scope: {
      sdChangeOnBlur: '&'
    },
    link: function(scope, Elm, attrs) {
      if (attrs.type === 'radio' || attrs.type === 'checkbox')
        return;

      var parameters = getParameters(attrs.sdChangeOnBlur);

      var oldValue = null;
      Elm.bind('focus', function() {
        scope.$apply(function() {
          oldValue = Elm.val();
        });
      })

      Elm.bind('blur', function() {
        scope.$apply(function() {
          if (Elm.val() != oldValue) {
            var params = {};
            if (parameters && parameters.length > 0) {
              for (var n = 0; n < parameters.length; n++) {
                params[parameters[n]] = scope.$parent.$eval(parameters[n]);
              }
            } else {
              params = null;
            }

            if (params == null) {
              scope.sdChangeOnBlur();
            } else {
              scope.sdChangeOnBlur(params)
            }
          }
        });
      });
    }
  };
});

function getParameters(functionStr) {
  var paramStr = functionStr.slice(functionStr.indexOf('(') + 1, functionStr.indexOf(')'));
  var params;
  if (paramStr) {
    params = paramStr.split(",");
  }
  var paramsT = [];
  for (var n = 0; params && n < params.length; n++) {
    paramsT.Push(params[n].trim());
  }
  return paramsT;
}

retarder l'invocation de la fonction de changement de 500 ms

html

<input type="text" ng-model="name" sd-change="onChange(name)" sd-change-delay="300"/>

OR

<input type="text" ng-model="name" sd-change="onChange()" sd-change-delay="300"/>

JS

app.directive('sdChange', ['$timeout',
  function($timeout) {
    return {
      restrict: 'A',
      scope: {
        sdChange: '&',
        sdChangeDelay: '@' //optional
      },
      link: function(scope, Elm, attr) {
        if (attr.type === 'radio' || attr.type === 'checkbox') {
          return;
        }

        if (!scope.sdChangeDelay) {
          scope.sdChangeDelay = 500; //defauld delay
        }

        var parameters = getParameters(attr.sdChange);

        var delayTimer;
        Elm.bind('keydown keypress', function() {
          if (delayTimer !== null) {
            $timeout.cancel(delayTimer);
          }

          delayTimer = $timeout(function() {
            var params = {};
            if (parameters && parameters.length > 0) {
              for (var n = 0; n < parameters.length; n++) {
                params[parameters[n]] = scope.$parent.$eval(parameters[n]);
              }
            } else {
              params = null;
            }

            if (params == null) {
              scope.sdChange();
            } else {
              scope.sdChange(params)
            }
            delayTimer = null;
          }, scope.sdChangeDelay);

          scope.$on(
            "$destroy",
            function(event) {
              $timeout.cancel(delayTimer);
              console.log("Destroyed");
            }
          );
        });
      }
    };
  }
]);

function getParameters(functionStr) {
  var paramStr = functionStr.slice(functionStr.indexOf('(') + 1, functionStr.indexOf(')'));
  var params;
  if (paramStr) {
    params = paramStr.split(",");
  }
  var paramsT = [];
  for (var n = 0; params && n < params.length; n++) {
    paramsT.Push(params[n].trim());
  }
  return paramsT;
}

les plnkrs pour les deux approches sont 

http://plnkr.co/edit/r5t0KwMtNeOhgnaidKhS?p=preview

http://plnkr.co/edit/9PGbYGCDCtB52G8bJkjx?p=info

3
Yogesh Manware

Les versions les plus récentes d’AngularJS (maintenant en version 1.3 bêta) le supportent de manière native. Voir ma réponse ici

2
manikanta

La solution qui a fonctionné pour moi était la suivante:

<input id="fieldId" type="text"
ng-model="form.fields.thisField"
ng-model-options="{ updateOn: 'blur' }"
ng-change="form.save()" />

J'ai trouvé cette solution ici

Cette page indique qu'elle nécessite la version 1.3.0+ d’AngularJS. Je l'ai testé avec AngularJS version 1.5.11 et cela fonctionne dans cette version pour moi.

1
Kmeixner