AngularJS - Размытие + Изменено?

Каков самый простой способ комбинировать ng-changed и ng-blur?

Я нашел этот пост: Как разрешить ng-model не обновляться сразу?

Однако это больше не работает в angluar 1.2+ Есть ли способ достичь такого же поведения?

Думаю, мне нужно сохранить копию старого значения самостоятельно и сравнить новое значение с тем, что при размытии, если я попытаюсь сделать то же самое, или есть ли более простой способ?

Ответы

Ответ 1

Это делает то, что я хочу. Он сохраняет значение в фокусе и сравнивает его с новым значением при размытии, если оно изменено, оно вызывает выражение в атрибуте.

 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);
                        });         
                    });
                }
            };
        });

использование:

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

Ответ 2

Используйте ng-model options. Таким образом, ng-change будет запускаться только при размытии ввода.

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

Ответ 3

Как насчет этого решения. Работает для меня:

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

Ответ 4

как насчет this plunkr?

используя angular встроенный ng-blur, обновите свое "сохраненное значение" при размытии

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

при сохранении, проверьте, что значение отличается

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

В ng-blur нет специальной опции для предварительного проверки равенства, о котором я знаю. Простой if, кажется, делает трюк

Ответ 5

Я использую AngularJs 1.2.x и наткнулся на проблему ng-change обстрела при каждом изменении. ng-blur можно использовать, но он срабатывает, даже если нет никакого изменения в значении. Поэтому оба нельзя эффективно использовать.

С Angularjs 1.3.x все проще, используя ng-model-options, как показано ниже

, чтобы вызвать функцию изменения "onBlur"

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

И

, чтобы отложить вызов функции изменения на 500 мс

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

Теперь, чтобы вернуться к вопросу о получении таких вещей с помощью AngularJs 1.2.x

, чтобы вызвать функцию изменения "onBlur"

HTML

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

<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;
}

, чтобы отложить вызов функции изменения на 500 мс

HTML

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

ИЛИ

<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;
}

plnkrs для обоих подходов

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

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

Ответ 6

Новые версии AngularJS (теперь в версии 1.3 beta) поддерживают это изначально. См. мой ответ здесь

Ответ 7

Решение, которое сработало для меня, было следующим:

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

Я нашел это решение здесь

Эта страница говорит, что для нее требуется версия AngularJS 1.3.0+. Я протестировал его с версией AngularJS 1.5.11, и он работает в этой версии для меня.

Ответ 8

В app.html

<input type="text" name="name" ng-model="$ctrl.user.name" ng-blur="$ctrl.saveChanges()" ng-change="$ctrl.onFieldChange()"/>

в приложениях

 public onFieldChange() {
    this.isValuesModified = true;
}

//save changes on blur event
public saveChanges() {
    //check if value is modified
    if(this.isValuesModified){

     //Do your stuff here
    }
}