Angularjs: input [text] ngChange срабатывает при изменении значения


92

ngChange запускается при изменении значения (ngChange не похож на классическое событие onChange). Как я могу связать классическое событие onChange с angularjs, которое будет срабатывать только при фиксации содержимого?

Текущая привязка:

<input type="text" ng-model="name" ng-change="update()" />

Просто ищу что-то подобное, и мне пришло в голову, что вы также можете рассмотреть возможность обновления только тогда, когда поле является действительным. Таким образом, пользователь может бороться с получением ввода в допустимый формат (или вы можете помочь им с помощью подсказок и фильтров), а затем вы можете вознаградить их обновлением, когда они все сделают правильно!
Стив Блэк,

В ближайшее время в angular должно быть встроено гораздо более гибкое решение, которое позволяет указать используемое событие (а не только размытие) и другие свойства: github.com/angular/angular.js/pull/2129
wired_in

Ответы:


96

В этом сообщении показан пример директивы, которая задерживает изменение модели на входе до срабатывания события размытия .

Вот скрипка, которая показывает, как ng-change работает с новой директивой ng-model-on-blur. Обратите внимание, что это небольшая поправка к исходной скрипке .

Если вы добавите директиву в свой код, вы измените свою привязку на это:

<input type="text" ng-model="name" ng-model-onblur ng-change="update()" />

Вот директива:

// override the default input to update on blur
angular.module('app', []).directive('ngModelOnblur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        priority: 1, // needed for angular 1.2.x
        link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
});

Примечание: как @wjin упоминает в комментариях ниже, эта функция поддерживается непосредственно в Angular 1.3 (в настоящее время в бета-версии) через ngModelOptions. Дополнительную информацию см. В документации .


1
Внимание: elm.unbind ('input') вызывает ошибку TypeError в Internet Explorer 8, поэтому другие операторы unbind не будут выполняться вообще. Я решил это, переместив elm.unbind ('input') в отдельную строку и окружив ее блоком try / catch.
Роб Джурлинк

1
В Angular 1.2 есть ng-blurдиректива: docs.angularjs.org/api/ng.directive:ngBlur
JJ Zabkar

5
Я заставил этот код работать, но мне нужно было установить приоритет директивы (т.е. приоритет: 100). Я использую Angular 1.2.10. Я предполагаю, что директива ngModelOnblur работала до директивы ngModel, поэтому отвязать еще нечего. Кроме того, эта страница создает впечатление, что в будущем для этого может быть встроено решение: github.com/angular/angular.js/pull/1783
Алан Вест

4
Примечание По крайней мере , в угловом 1.3 эта функция поддерживается в реализации по умолчанию через ng-model-options="{ updateOn: 'default blur' }"См документации
wjin

2
@RobJuurlink (или любой другой, кто сталкивается с IE8 'TypeError' при попытке привязки или отмены привязки к 'input') - глядя на исходный код Angular, вы увидите, что они используют, $snifferчтобы определить, поддерживает ли браузер 'input', а если нет, они возвращаются к «нажатию клавиши». Если вы обновите указанную выше директиву, чтобы отвязать «ввод» только в том случае, если она $sniffer.hasEvent('input')вернет true - тогда вы сможете избежать этой ошибки и по-прежнему работать в IE8
bvaughn

33

Речь идет о недавних дополнениях к AngularJS, которые послужат ответом в будущем (также для другого вопроса ).

Более новые версии Angular (сейчас в бета-версии 1.3), AngularJS изначально поддерживает эту опцию, используя ngModelOptions, например,

ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"

Документы NgModelOptions

Пример:

<input type="text" name="username"
       ng-model="user.name"
       ng-model-options="{updateOn: 'default blur', debounce: {default: 500, blur: 0} }" />

Это не работает правильно в 1.3 beta 5, но исправлено в текущей основной сборке 2602
manikanta

И именно поэтому он все еще находится в стадии бета-тестирования и не может использоваться в «реальных» приложениях, таких как то, которое я создаю сейчас.
reaper_unique

Вот ng-model-options, например модуль для Angular 1.2.x github.com/fergaldoyle/modelOptions
Fergal

8

В случае, если кто-то еще ищет дополнительную поддержку нажатия клавиш "Enter", вот обновление скрипки, предоставленное Gloppy

Код для привязки нажатия клавиш:

elm.bind("keydown keypress", function(event) {
    if (event.which === 13) {
        scope.$apply(function() {
            ngModelCtrl.$setViewValue(elm.val());
        });
    }
});

5

Для тех, кто борется с IE8 (ему не нравится unbind ('input'), я нашел способ обойти это.

Вставьте $ sniffer в свою директиву и используйте:

if($sniffer.hasEvent('input')){
    elm.unbind('input');
}

IE8 успокоится, если вы сделаете это :)


или просто используйте try / catch
wired_in

4

Насколько мне известно, мы должны использовать ng-change с опцией выбора, а в случае текстового поля мы должны использовать ng-blur.


Это правильный ответ сейчас, тогда, когда задавался вопрос, очевидно, что его не существовало.
даунхенд

Большое спасибо ... это должно быть ответ
Renjith

3

Разве не используется $ scope. $ Watch, чтобы лучше отразить изменения переменной области?


1
Пища для размышлений: benlesh.com/2013/10/title.html (озаглавленный: вам, вероятно, не следует использовать $ watch в своих контроллерах)
BenB 05

0

Переопределить входное поведение onChange по умолчанию (вызывать функцию только при изменении фокуса потери управления и значения)

ПРИМЕЧАНИЕ: ngChange не похож на классическое событие onChange, которое запускает событие при изменении значения. Эта директива сохраняет значение элемента, когда он получает фокус.
При размытии он проверяет, изменилось ли новое значение, и если да, запускает событие.

@param {String} - имя функции, которая будет вызываться при срабатывании onChange

@example <input my-on-change = "myFunc" ng-model = "model">

angular.module('app', []).directive('myOnChange', function () { 
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            myOnChange: '='
        },
        link: function (scope, elm, attr) {
            if (attr.type === 'radio' || attr.type === 'checkbox') {
                return;
            }
            // store value when get focus
            elm.bind('focus', function () {
                scope.value = elm.val();

            });

            // execute the event when loose focus and value was change
            elm.bind('blur', function () {
                var currentValue = elm.val();
                if (scope.value !== currentValue) {
                    if (scope.myOnChange) {
                        scope.myOnChange();
                    }
                }
            });
        }
    };
});

0

У меня была точно такая же проблема, и это сработало для меня. Добавьте, ng-model-updateи ng-keyupвсе готово! Вот документы

 <input type="text" name="userName"
         ng-model="user.name"
         ng-change="update()"
         ng-model-options="{ updateOn: 'blur' }"
         ng-keyup="cancel($event)" />
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.