Aggiorna il modello angolare dopo aver impostato il valore di input con jQuery


160

Ho questo semplice scenario:

Elemento di input il cui valore viene modificato dal metodo val () di jQuery.

Sto cercando di aggiornare il modello angolare con il valore impostato da jQuery. Ho provato a scrivere una direttiva semplice, ma non sta facendo quello che voglio.

Ecco la direttiva:

var myApp = angular.module('myApp', []);
myApp.directive('testChange', function() {
    return function(scope, element, attrs) {        
        element.bind('change', function() {
            console.log('value changed');
        })
    }
})

questa è la parte jQuery:

$(function(){
    $('button').click(function(){
        $('input').val('xxx');
    })
})

e html:

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
        <input test-change ng-model="foo" />
        <span>{{foo}}</span>
    </div>
</div>

<button>clickme</button>

Ecco il violino con il mio tentativo:
http://jsfiddle.net/U3pVM/743/

qualcuno può indicarmi la giusta direzione?


2
Mix AngularJS e jQuery, al di fuori delle direttive, è spesso una cattiva idea. JQuery è obbligatorio per quello che vuoi fare?
Blackhole,

Perché non impostare l'evento click con angolare su una funzione nel controller per modificare il valore del modello?
Jimmy Kane,

@Blackhole, sto usando il plugin di caricamento jquery che fa il suo lavoro e inserisce il percorso del file caricato nell'input nascosto. Tutto ciò di cui ho bisogno è avere accesso a quel percorso nel modello angolare. Quindi ho pensato di impostarlo come valore di input nascosto e dopo che è stato modificato aggiorno il modello angolare.
Michal J.

Non vedo la chiamata di Jquery nel tuo violino ... Puoi controllare e indicare dove cambi valore con JQ?
Valentyn Shybanov,

Il violino si collega a un'app di esempio di Todo, che non si riferisce a questa domanda.
Stewie,

Risposte:


322

ngModel ascolta l'evento "input", quindi per "correggere" il tuo codice dovrai attivare l'evento dopo aver impostato il valore:

$('button').click(function(){
    var input = $('input');
    input.val('xxx');
    input.trigger('input'); // Use for Chrome/Firefox/Edge
    input.trigger('change'); // Use for Chrome/Firefox/Edge + IE11
});

Per la spiegazione di questo particolare comportamento, dai un'occhiata a questa risposta che ho dato qualche tempo fa: "In che modo AngularJS rileva internamente eventi come" onclick "," onchange "? "


Ma sfortunatamente, questo non è l'unico problema che hai. Come sottolineato con altri commenti post, il tuo approccio incentrato su jQuery è chiaramente sbagliato. Per maggiori informazioni, dai un'occhiata a questo post: come faccio a "pensare in AngularJS" se ho uno sfondo jQuery? ).


5
Freddo! Con una sola eccezione: perché non funziona su input nascosti? Quando cambio il mio tipo di input in testo, funziona come previsto.
Karol,

8
Ciò ha risolto un grave problema durante l'utilizzo dei plugin del calendario jquery. Attaccando il plugin per attivare ('input') dopo input.val () l'evento ng-change si attiva dopo che l'utente seleziona la data del calendario. Grazie!
Drone Brain,

3
Funziona perfettamente con input nascosti: element.triggerHandler ("change");
falko,

2
questo non funziona per me. $ ( "# Distanza") val (i dati).; $ ( "# Distanza") trigger ( 'ingresso.');
Stas Svishov

10
Con Angular 1.4.3, l' inputevento non funziona su IE incluso IE11. inputL'evento funziona solo quando $sniff.hasEvent('input')è vero ma $sniff.hasEvent('input')è falso anche su IE11! Possiamo invece usare l' changeevento .
Shuhei Kagawa,

61

Spero che questo sia utile per qualcuno.

Non sono stato in grado di ottenere l' jQuery('#myInputElement').trigger('input')evento per essere raccolto la mia app angolare.

Sono stato comunque in grado angular.element(jQuery('#myInputElement')).triggerHandler('input')di essere prelevato.


2
per favore spiega la soluzione non scrivere semplicemente il codice. ottengo angolare non è $ non è una funzione
Thakhani Tharage

1
$ rappresenta jQuery qui. È taggato nella domanda.
ginman,

Questo ha funzionato anche per me mentre $ ('myInputElement'). Trigger ('input') era traballante. Sembrava funzionare in modo casuale a volte ma non altri e non sono mai riuscito a stabilire uno schema. Questa soluzione funziona sempre.
BryanP

2
Il mio è lavorato con # prefisso:angular.element($('#myInputElement')).triggerHandler('input')
Ebru Yener,

Questo trigger Handler ha funzionato anche per me, avevo a che fare con textarea non input. Grazie
Mounir,

25

La risposta accettata che ha scatenato l' inputevento con jQuery non ha funzionato per me. La creazione di un evento e l'invio con JavaScript nativo hanno funzionato.

$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));

Questa è stata la soluzione anche per me. Usando Angular 1.1.5, jQuery 2.2.4 e Jasmine 2.5.3. Molto, MOLTO strano che nessun altro meccanismo di innesco funzioni.
Lars-Erik,

Stavo cercando il metodo JS nativo per attivare la convalida del modulo durante l'impostazione di un input in uno script e questo ha funzionato per me, grazie.
disperdere

Funziona anche con Angular 5, fantastico!
Igor

Grazie. Particolarmente utile in webview.evaluatejavascript
Berry Wing

22

Non penso che jQuery sia richiesto qui.

È possibile utilizzare $ orologio e ng clic invece

<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    <input test-change ng-model="foo" />
    <span>{{foo}}</span>

    <button ng-click=" foo= 'xxx' ">click me</button>
    <!-- this changes foo value, you can also call a function from your controller -->
  </div>
</div>

Nel tuo controller:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});

1
Grazie Utopik, hai ragione, non dovrei mescolare jquery con angolare quando c'è un modo per fare il lavoro usando angolare.
Michal J.

17

È necessario utilizzare il seguente codice per aggiornare l'ambito del modello di input specifico come segue

$('button').on('click', function(){
    var newVal = $(this).data('val');
    $('select').val(newVal).change();

    var scope = angular.element($("select")).scope();
    scope.$apply(function(){
        scope.selectValue = newVal;
    });
});

1
var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); quella parte mi ha aiutato molto. Il mio problema era l'aggiornamento di un modello angolare dopo una chiamata ajax jquery nella funzione successo. Era lento con $ http perché c'era un listener di eventi di modifica duplicato per l'elemento che stava facendo qualcos'altro, quindi l'ho unito in jQuery.
Emmanuel Mahuni,

1
L'uso di element.scope () è una cattiva idea, perché funziona solo con la registrazione abilitata. Se ti trovi in ​​un sito di produzione, dovresti disabilitare la registrazione nella tua configurazione con $compileProvider.debugInfoEnabled(false);o $logProvider.debugEnabled(false);Vedi code.angularjs.org/1.4.0/docs/guide/production per maggiori informazioni.
RWAM

Ho provato questo metodo per la variabile nascosta e ha funzionato. var li_cuboid_id = $ ('# li_cuboid_id'); li_cuboid_id.val (json.cuboidId) .Inserire (); var scope = angular.element ($ ("# li_cuboid_id")). scope (); scope. $ apply (function () {scope.cuboidId = json.cuboidId;}); la variabile nascosta è definita come: <input id = "li_cuboid_id" type = hidden ng-model = "cuboidId">
Rahul Varadkar

7

Ho apportato modifiche solo all'inizializzazione del controller aggiungendo listener sul pulsante di azione:

$(document).on('click', '#action-button', function () {
        $timeout(function () {
             angular.element($('#input')).triggerHandler('input');
        });
});

Altre soluzioni non hanno funzionato nel mio caso.


4

So che è un po 'tardi per rispondere qui, ma forse potrei risparmiare un giorno.

Ho avuto a che fare con lo stesso problema. Un modello non verrà popolato una volta aggiornato il valore dell'input da jQuery. Ho provato a utilizzare gli eventi trigger, ma nessun risultato.

Ecco cosa ho fatto per salvarti la giornata.

Dichiara una variabile nel tag dello script in HTML.

Piace:

<script>
 var inputValue="";

// update that variable using your jQuery function with appropriate value, you want...

</script>

Una volta che l'hai fatto utilizzando il servizio angolare di seguito.

$ finestra

Ora sotto la funzione getData chiamata dallo stesso ambito del controller otterrai il valore desiderato.

var myApp = angular.module('myApp', []);

app.controller('imageManagerCtrl',['$scope','$window',function($scope,$window) {

$scope.getData = function () {
    console.log("Window value " + $window.inputValue);
}}]);

3

Ho scritto questo piccolo plugin per jQuery che effettuerà tutte le chiamate per .val(value)aggiornare l'elemento angolare se presente:

(function($, ng) {
  'use strict';

  var $val = $.fn.val; // save original jQuery function

  // override jQuery function
  $.fn.val = function (value) {
    // if getter, just return original
    if (!arguments.length) {
      return $val.call(this);
    }

    // get result of original function
    var result = $val.call(this, value);

    // trigger angular input (this[0] is the DOM object)
    ng.element(this[0]).triggerHandler('input');

    // return the original result
    return result; 
  }
})(window.jQuery, window.angular);

Basta inserire questo script dopo jQuery e angular.js e gli val(value)aggiornamenti ora dovrebbero funzionare bene.


Versione minimizzata:

!function(n,t){"use strict";var r=n.fn.val;n.fn.val=function(n){if(!arguments.length)return r.call(this);var e=r.call(this,n);return t.element(this[0]).triggerHandler("input"),e}}(window.jQuery,window.angular);

Esempio:


Mi dispiace gravemente approfondire, ma hai idea di come questo potrebbe / potrebbe funzionare con la casella di controllo o seleziona poiché quelli usano .prop invece di .val? Questo funziona perfettamente per i cambiamenti di input .val almeno, quindi grazie!
Austin,

@Austin Temo di non saperlo. Questa è una domanda di 5 anni su due tecnologie che sono ampiamente considerate obsolete, in quanto tali non ho tenuto a mente le conoscenze. Buona fortuna per ottenere la soluzione di cui hai bisogno però.
davi

2

Se stai usando IE, devi usare: input.trigger ("change");


2

Inserisci .change() dopo aver impostato il valore.

esempio:('id').val.('value').change();

inoltre, non dimenticare di aggiungere onchangeo ng-changetaggare in html


0

Ho fatto questo per essere in grado di aggiornare il valore di ngModel dall'esterno con Vanilla / jQuery:

function getScope(fieldElement) {
    var $scope = angular.element(fieldElement).scope();
    var nameScope;
    var name = fieldElement.getAttribute('name');
    if($scope) {
        if($scope.form) {
            nameScope = $scope.form[name];
        } else if($scope[name]) {
            nameScope = $scope[name];
        }
    }
    return nameScope;
}

function setScopeValue(fieldElement, newValue) {
    var $scope = getScope(fieldElement);
    if($scope) {
        $scope.$setViewValue(newValue);
        $scope.$validate();
        $scope.$render();
    }
}

setScopeValue(document.getElementById("fieldId"), "new value");
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.