Angularjs: input [text] ngChange si attiva mentre il valore cambia


92

ngChange viene attivato mentre il valore sta cambiando (ngChange non è simile al classico evento onChange). Come posso associare il classico evento onChange con angularjs, che si attiverà solo quando i contenuti sono impegnati?

Associazione corrente:

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

Sto solo cercando qualcosa di simile e mi è capitato che potresti anche prendere in considerazione l'aggiornamento solo quando il campo è valido. In questo modo l'utente può avere difficoltà a ottenere l'input in un formato valido (o potresti aiutarlo con prompt e filtri), quindi puoi premiarlo con un aggiornamento quando lo fa bene!
Steve Black

Una soluzione molto più flessibile che consente di specificare l'evento da utilizzare (non solo la sfocatura) e altre proprietà dovrebbero essere integrate in
angular

Risposte:


96

Questo post mostra un esempio di una direttiva che ritarda le modifiche del modello a un input fino all'attivazione dell'evento blur .

Ecco un violino che mostra il ng-change che funziona con la nuova direttiva ng-model-on-blur. Nota che questa è una leggera modifica al violino originale .

Se aggiungi la direttiva al tuo codice, cambierai il tuo legame con questo:

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

Ecco la direttiva:

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

Nota: come menzionato da @wjin nei commenti qui sotto, questa funzione è supportata direttamente in Angular 1.3 (attualmente in beta) tramite ngModelOptions. Consulta i documenti per maggiori informazioni.


1
Attenzione, elm.unbind ('input') genera un 'TypeError' in Internet Explorer 8 in modo che le altre istruzioni di unbind non vengano eseguite affatto. L'ho risolto spostando elm.unbind ('input') su una riga separata e circondato da un blocco try / catch.
Rob Juurlink

1
Angular 1.2 ha una ng-blurdirettiva: docs.angularjs.org/api/ng.directive:ngBlur
JJ Zabkar

5
Ho fatto funzionare questo codice, ma ho dovuto impostare la priorità della direttiva (cioè priorità: 100). Sto usando Angular 1.2.10. La mia ipotesi è che la direttiva ngModelOnblur fosse in esecuzione prima della direttiva ngModel, quindi non c'era ancora nulla da svincolare. Inoltre, questa pagina fa sembrare che ci possa essere una soluzione integrata per questo in futuro: github.com/angular/angular.js/pull/1783
Alan West

4
NOTA Almeno in angolare 1.3 questa funzionalità è supportata nell'implementazione predefinita tramite ng-model-options="{ updateOn: 'default blur' }"Vedi documentazione
wjin

2
@RobJuurlink (o chiunque altro incontri il 'TypeError' di IE8 durante il tentativo di associare o disassociare a 'input') - Guardando la fonte di Angular, vedrai che usano $snifferper determinare se il browser supporta 'input' e in caso contrario, tornano a "keydown". Se aggiorni la direttiva sopra per separare solo 'input' se $sniffer.hasEvent('input')restituisce true, puoi evitare
quell'errore

32

Si tratta di recenti aggiunte ad AngularJS, per servire come risposta futura (anche per un'altra domanda ).

Le versioni più recenti di Angular (ora in 1.3 beta), AngularJS supporta nativamente questa opzione, usando ngModelOptions, come

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

Documenti di NgModelOptions

Esempio:

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

Non funziona correttamente nella 1.3 beta 5, ma è stato risolto nell'attuale build master 2602
manikanta

Ed è per questo che è ancora in versione beta e non è utilizzabile in applicazioni "reali" come quella che sto costruendo in questo momento.
reaper_unique

Ecco un ng-model-options come il modulo per Angular 1.2.x github.com/fergaldoyle/modelOptions
Fergal

8

Nel caso in cui qualcun altro cerchi un supporto aggiuntivo per la pressione dei tasti di "invio", ecco un aggiornamento del violino fornito da Gloppy

Codice per l'associazione dei tasti:

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

5

Per chiunque abbia problemi con IE8 (non gli piace lo svincolo ('input'), ho trovato un modo per aggirarlo.

Inietta $ sniffer nella tua direttiva e usa:

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

IE8 si calma se lo fai :)


o usa semplicemente try / catch
wired_in

4

Secondo le mie conoscenze dovremmo usare ng-change con l'opzione select e nel caso della casella di testo dovremmo usare ng-blur.


Questa è la risposta corretta ora, allora, quando la domanda è stata posta, a quanto pare non esisteva.
downhand

Grazie mille ... questa dovrebbe essere la risposta
Renjith


0

Ignora l'input predefinito suChange behavior (chiama la funzione solo quando il focus e il valore della perdita di controllo sono stati modificati)

NOTA: ngChange non è simile al classico evento onChange che attiva l'evento mentre il valore sta cambiando Questa direttiva memorizza il valore dell'elemento quando ottiene il focus
Sulle sfocature controlla se il nuovo valore è cambiato e in tal caso attiva l'evento

@param {String} - nome della funzione da richiamare quando "onChange" dovrebbe essere attivato

@esempio <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

Ho avuto esattamente lo stesso problema e questo ha funzionato per me. Aggiungi ng-model-updatee ng-keyupe sei a posto! Ecco i documenti

 <input type="text" name="userName"
         ng-model="user.name"
         ng-change="update()"
         ng-model-options="{ updateOn: 'blur' }"
         ng-keyup="cancel($event)" />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.