Aktualisieren Sie das Winkelmodell, nachdem Sie den Eingabewert mit jQuery festgelegt haben

160

Ich habe dieses einfache Szenario:

Geben Sie ein Element ein, dessen Wert durch die val () -Methode von jQuery geändert wird.

Ich versuche, das Winkelmodell mit dem von jQuery festgelegten Wert zu aktualisieren. Ich habe versucht, eine einfache Anweisung zu schreiben, aber sie macht nicht das, was ich will.

Hier ist die Richtlinie:

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

Dies ist der jQuery-Teil:

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

und html:

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

<button>clickme</button>

Hier ist die Geige mit meinem Versuch:
http://jsfiddle.net/U3pVM/743/

Kann mich bitte jemand in die richtige Richtung weisen?

Michal J.
quelle
2
Das Mischen von AngularJS und jQuery außerhalb der Direktiven ist oft eine schlechte Idee. Ist jQuery für das, was Sie tun möchten, obligatorisch?
Blackhole
Warum setzen Sie das Klickereignis nicht mit Winkel auf eine Funktion im Controller, um den Wert des Modells zu ändern?
Jimmy Kane
@Blackhole, ich verwende das jquery-Upload-Plugin, das seine Arbeit erledigt und den Pfad zur hochgeladenen Datei in die versteckte Eingabe einfügt. Ich brauche nur Zugriff auf diesen Pfad im Winkelmodell. Also dachte ich, ich setze es als Wert für versteckte Eingaben und aktualisiere das Winkelmodell, nachdem es geändert wurde.
Michal J.
Ich sehe keinen Jquery-Aufruf in Ihrer Geige ... Können Sie überprüfen und zeigen, wo Sie den Wert mit JQ ändern?
Valentyn Shybanov
Ihre Geige verlinkt auf eine Todo-Beispiel-App, die sich nicht auf diese Frage bezieht.
Stewie

Antworten:

322

ngModel wartet auf das Ereignis "Eingabe". Um Ihren Code zu "reparieren", müssen Sie dieses Ereignis auslösen, nachdem Sie den Wert festgelegt haben:

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

Zur Erklärung dieses speziellen Verhaltens lesen Sie die Antwort, die ich vor einiger Zeit gegeben habe: " Wie fängt AngularJS intern Ereignisse wie 'onclick', 'onchange' ab? "


Leider ist dies nicht das einzige Problem, das Sie haben. Wie bereits in anderen Kommentaren erwähnt, ist Ihr jQuery-zentrierter Ansatz eindeutig falsch. Weitere Informationen finden Sie in diesem Beitrag: Wie denke ich in AngularJS, wenn ich einen jQuery-Hintergrund habe? ).

Stewie
quelle
5
Cool! Mit einer Ausnahme: Warum funktioniert es nicht bei versteckten Eingaben? Wenn ich meinen Eingabetyp auf Text umstelle, funktioniert dies wie erwartet.
Karol
8
Dies löste ein großes Problem bei der Verwendung von JQuery-Kalender-Plugins. Durch Hacken des Plugins zum Auslösen ('Eingabe') nach input.val () wird das ng-change-Ereignis ausgelöst, nachdem der Benutzer das Kalenderdatum ausgewählt hat. Vielen Dank!
Drone Brain
3
Funktioniert perfekt bei versteckten Eingaben: element.triggerHandler ("change");
Falko
2
das funktioniert bei mir nicht. $ ("# Distance"). Val (Daten); $ ("# Distance"). Trigger ('input');
Stas Svishov
10
Mit Angular 1.4.3 funktioniert das inputEreignis im IE einschließlich IE11 nicht. inputEreignis funktioniert nur, wenn $sniff.hasEvent('input')es wahr ist, aber $sniff.hasEvent('input')auch unter IE11 falsch! Wir können stattdessen changeevent verwenden.
Shuhei Kagawa
61

Hoffe das ist nützlich für jemanden.

Ich konnte das jQuery('#myInputElement').trigger('input')Ereignis nicht in meine eckige App aufnehmen.

Ich konnte jedoch angular.element(jQuery('#myInputElement')).triggerHandler('input')abgeholt werden.

Ginman
quelle
2
Bitte erläutern Sie die Lösung. Schreiben Sie nicht nur Code. Ich bekomme eckig ist nicht $ ist keine Funktion
Thakhani Tharage
1
$ steht hier für jQuery. Es ist in der Frage markiert.
Ginman
Dies funktionierte auch für mich, während $ ('myInputElement'). Trigger ('input') flockig war. Es schien manchmal zufällig zu funktionieren, aber nicht bei anderen, und ich konnte nie ein Muster festlegen. Diese Lösung funktioniert jedes Mal.
BryanP
2
Meins wird mit # Präfix gearbeitet:angular.element($('#myInputElement')).triggerHandler('input')
Ebru Yener
Dieser TriggerHandler hat auch bei mir funktioniert, ich habe es mit Textbereich nicht eingegeben. Vielen Dank
Mounir
25

Die akzeptierte Antwort, die ein inputEreignis mit jQuery auslöste, funktionierte bei mir nicht. Das Erstellen eines Ereignisses und das Versenden mit nativem JavaScript haben den Trick getan.

$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));
Martins Balodis
quelle
Dies war auch für mich die Lösung. Verwenden von Angular 1.1.5, jQuery 2.2.4 und Jasmine 2.5.3. Sehr, sehr seltsam, dass keine anderen Auslösemechanismen funktionieren.
Lars-Erik
Ich suchte nach der nativen JS-Methode zum Auslösen der Formularüberprüfung beim Festlegen einer Eingabe in einem Skript, und dies funktionierte für mich, danke.
zerstreuen
Funktioniert sogar mit Angular 5, großartig!
Igor
Danke dir. Besonders hilfreich in webview.evaluatejavascript
Berry Wing
22

Ich denke nicht, dass jQuery hier erforderlich ist.

Sie können stattdessen $ watch und ng-click verwenden

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

In Ihrem Controller:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});
Utopik
quelle
1
Vielen Dank, Utopik, Sie haben Recht, ich sollte jquery nicht mit eckig mischen, wenn es eine Möglichkeit gibt, die Arbeit mit eckig zu erledigen.
Michal J.
17

Sie müssen den folgenden Code verwenden, um den Umfang des spezifischen Eingabemodells wie folgt zu aktualisieren

$('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;
    });
});
jayM
quelle
1
var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); Dieser Teil hat mir sehr geholfen. Mein Problem bestand darin, ein Winkelmodell nach einem jquery ajax-Aufruf in der Erfolgsfunktion zu aktualisieren. Mit $ http war es langsam, weil es einen doppelten Listener für Änderungsereignisse für das Element gab, das etwas anderes tat, also habe ich es in jQuery zusammengeführt.
Emmanuel Mahuni
1
Die Verwendung von element.scope () ist eine schlechte Idee, da sie nur mit aktivierter Protokollierung funktioniert. Wenn Sie sich an einem Produktionsstandort befinden, sollten Sie die Protokollierung Ihrer Konfiguration mit $compileProvider.debugInfoEnabled(false);oder deaktivieren. Weitere Informationen finden $logProvider.debugEnabled(false);Sie unter code.angularjs.org/1.4.0/docs/guide/production .
RWAM
Ich habe diese Methode für versteckte Variablen ausprobiert und es hat funktioniert. var li_cuboid_id = $ ('# li_cuboid_id'); li_cuboid_id.val (json.cuboidId) .change (); var scope = angle.element ($ ("# li_cuboid_id")). scope (); scope. $ apply (function () {scope.cuboidId = json.cuboidId;}); Die versteckte Variable ist definiert als: <input id = "li_cuboid_id" type = hidden ng-model = "cuboidId">
Rahul Varadkar
7

Ich habe Änderungen nur an der Controller-Initialisierung vorgenommen, indem ich den Listener auf der Aktionstaste hinzugefügt habe:

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

Andere Lösungen haben in meinem Fall nicht funktioniert.

Ebru Yener
quelle
4

Ich weiß, dass es etwas spät ist, hier zu antworten, aber vielleicht kann ich einmal am Tag etwas sparen.

Ich habe mich mit dem gleichen Problem befasst. Ein Modell wird nicht gefüllt, sobald Sie den Wert der Eingabe von jQuery aktualisieren. Ich habe versucht, Trigger-Ereignisse zu verwenden, aber kein Ergebnis.

Hier ist, was ich getan habe, um Ihren Tag zu retten.

Deklarieren Sie eine Variable in Ihrem Skript-Tag in HTML.

Mögen:

<script>
 var inputValue="";

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

</script>

Sobald Sie dies getan haben, verwenden Sie den folgenden Service von Angular.

$ window

Die folgende getData-Funktion, die vom selben Controller-Bereich aufgerufen wird, gibt Ihnen den gewünschten Wert.

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

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

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

Ich habe dieses kleine Plugin für jQuery geschrieben, das alle Aufrufe zum .val(value)Aktualisieren des Winkelelements ausführt, falls vorhanden:

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

Fügen Sie dieses Skript einfach nach jQuery und angular.js ein, und val(value)Updates sollten jetzt gut funktionieren .


Minimierte Version:

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

Beispiel:

dav_i
quelle
Es tut mir leid, das ausgraben zu müssen, aber eine Idee, wie dies mit Kontrollkästchen oder Auswahlmöglichkeiten funktionieren würde / könnte, da diese .prop anstelle von .val verwenden? Dies funktioniert perfekt für die Eingabe von .val-Änderungen. Vielen Dank!
Austin
@Austin Ich fürchte, ich weiß es nicht. Dies ist eine 5 Jahre alte Frage zu zwei Technologien, die allgemein als veraltet gelten. Daher habe ich das Wissen nicht im Kopf behalten. Viel Glück bei der Suche nach der Lösung, die Sie benötigen.
dav_i
2

Wenn Sie IE verwenden, müssen Sie Folgendes verwenden: input.trigger ("change");

Wilhelm
quelle
2

.change()nach dem Einstellen des Wertes hinzufügen .

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

Vergessen Sie auch nicht, HTML hinzuzufügen onchangeoder zu ng-changemarkieren

Azeez
quelle
0

Ich habe dies getan, um den Wert von ngModel von außen mit Vanilla / jQuery aktualisieren zu können:

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");
anlijudavid
quelle