Zaktualizuj model Angular po ustawieniu wartości wejściowej za pomocą jQuery

160

Mam taki prosty scenariusz:

Element wejściowy, którego wartość jest zmieniana przez metodę val () jQuery.

Próbuję zaktualizować model kątowy o wartość ustawioną przez jQuery. Próbowałem napisać prostą dyrektywę, ale nie robi ona tego, co chcę.

Oto dyrektywa:

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

to jest część jQuery:

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

i html:

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

<button>clickme</button>

Oto skrzypce z moją próbą:
http://jsfiddle.net/U3pVM/743/

Czy ktoś może wskazać mi właściwy kierunek?

Michał J.
źródło
2
Mieszanie AngularJS i jQuery, poza dyrektywami, jest często złym pomysłem. Czy jQuery jest obowiązkowe dla tego, co chcesz zrobić?
Blackhole
Dlaczego nie ustawisz zdarzenia click z angular na funkcję w kontrolerze, aby zmienić wartość modelu?
Jimmy Kane
@Blackhole, używam wtyczki do przesyłania jquery, która wykonuje swoją pracę i umieszcza ścieżkę do przesłanego pliku w ukrytym wejściu. Potrzebuję tylko dostępu do tej ścieżki w modelu kątowym. Pomyślałem więc, że ustawię to jako wartość ukrytych danych wejściowych i po zmianie zaktualizuj model kątowy.
Michał J.
Nie widzę wywołania Jquery na twoich skrzypcach ... Czy możesz sprawdzić i wskazać, gdzie zmieniasz wartość za pomocą JQ?
Valentyn Shybanov
Twoje skrzypce prowadzą do przykładowej aplikacji Todo, która nie dotyczy tego pytania.
Stewie

Odpowiedzi:

322

ngModel nasłuchuje zdarzenia „input”, więc aby „naprawić” kod, musiałbyś wyzwolić to zdarzenie po ustawieniu wartości:

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

Aby wyjaśnić to konkretne zachowanie, zapoznaj się z odpowiedzią, której udzieliłem jakiś czas temu: „W jaki sposób AngularJS wewnętrznie przechwytuje zdarzenia takie jak 'onclick', 'onchange'?


Ale niestety nie jest to jedyny problem, jaki masz. Jak wskazano w innych komentarzach do postów, podejście skoncentrowane na jQuery jest po prostu błędne. Aby uzyskać więcej informacji, spójrz na ten post: Jak „myśleć w AngularJS”, jeśli mam tło w jQuery? ).

Stewie
źródło
5
Chłodny! Z jednym wyjątkiem: dlaczego nie działa na ukrytych danych wejściowych? Kiedy przełączam typ wprowadzania na tekst, działa zgodnie z oczekiwaniami.
Karol
8
To rozwiązało poważny problem podczas korzystania z wtyczek kalendarza jquery. Włamując się do wtyczki, aby wyzwalała ('input') po input.val (), zdarzenie ng-change uruchamia się po wybraniu przez użytkownika daty kalendarza. Dzięki!
Drone Brain
3
Działa doskonale na ukrytych danych wejściowych: element.triggerHandler ("change");
falko
2
to nie działa dla mnie. $ ("# Odległość"). Val (dane); $ ("# Odległość"). Wyzwalacz ('wejście');
Stas Svishov
10
W Angular 1.4.3 inputzdarzenie nie działa w IE, w tym IE11. inputzdarzenie działa tylko wtedy, gdy $sniff.hasEvent('input')jest prawdziwe, ale $sniff.hasEvent('input')jest fałszywe nawet w IE11! Zamiast tego możemy użyć changezdarzenia .
Shuhei Kagawa
61

Mam nadzieję, że to komuś się przyda.

Nie udało mi się odebrać jQuery('#myInputElement').trigger('input')wydarzenia w mojej aplikacji kątowej.

Udało mi się jednak mnie angular.element(jQuery('#myInputElement')).triggerHandler('input')zabrać.

ginman
źródło
2
proszę wyjaśnić rozwiązanie, nie tylko pisz kod. dostaję kątowy to nie $ nie jest funkcją
Thakhani Tharage
1
$ reprezentuje tutaj jQuery. Jest zaznaczone w pytaniu.
ginman
To też zadziałało, gdy $ ('myInputElement'). Trigger ('input') był niestabilny. Wydawało się, że czasami działa przypadkowo, ale nie w innych i nigdy nie mogłem ustalić wzoru. To rozwiązanie działa za każdym razem.
BryanP
2
Mój działa z przedrostkiem #:angular.element($('#myInputElement')).triggerHandler('input')
Ebru Yener
Ten triggerHandler również działał u mnie, miałem do czynienia z tekstem, a nie wejściem. Dzięki
Mounir
25

Zaakceptowana odpowiedź, która wyzwalała inputzdarzenie w jQuery, nie działała dla mnie. Utworzenie zdarzenia i wysłanie go za pomocą natywnego JavaScript załatwiło sprawę.

$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));
Martins Balodis
źródło
Dla mnie to też było rozwiązanie. Używając Angular 1.1.5, jQuery 2.2.4 i Jasmine 2.5.3. Bardzo, BARDZO dziwne, że żadne inne mechanizmy wyzwalające nie działają.
Lars-Erik
Szukałem natywnej metody JS do wyzwalania walidacji formularza podczas ustawiania danych wejściowych w skrypcie i to zadziałało, dzięki.
rozproszenie
Działa nawet z Angular 5, świetnie!
Igor
Dziękuję Ci. Szczególnie pomocny w webview.evaluatejavascript
Berry Wing
22

Nie sądzę, aby jQuery było tutaj wymagane.

Można użyć $ zegarek i ng kliknięcie zamiast

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

W kontrolerze:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});
Utopik
źródło
1
Dziękuję Utopiku, masz rację, nie powinienem mieszać jQuery z angularem, kiedy jest sposób na wykonanie tej pracy za pomocą angular.
Michal J.
17

Aby zaktualizować zakres określonego modelu wejściowego, należy użyć następującego kodu w następujący sposób

$('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
źródło
1
var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); ta porcja bardzo mi pomogła. Moim problemem była aktualizacja modelu kątowego po wywołaniu jquery ajax w funkcji sukcesu. To było powolne z $ http, ponieważ istniał zduplikowany detektor zdarzeń zmian dla elementu, który robił coś innego, więc połączyłem go z jQuery.
Emmanuel Mahuni
1
Użycie elementu element.scope () jest złym pomysłem, ponieważ działa tylko przy włączonym logowaniu. Jeśli jesteś w witrynie produkcyjnej, powinieneś wyłączyć logowanie w konfiguracji za pomocą $compileProvider.debugInfoEnabled(false);lub $logProvider.debugEnabled(false);Zobacz code.angularjs.org/1.4.0/docs/guide/production, aby uzyskać więcej informacji.
RWAM
Wypróbowałem tę metodę dla ukrytej zmiennej i zadziałała. var li_cuboid_id = $ ('# li_cuboid_id'); li_cuboid_id.val (json.cuboidId) .change (); var scope = angular.element ($ ("# li_cuboid_id")). scope (); zakres. $ zastosuj (funkcja () {scope.cuboidId = json.cuboidId;}); ukryta zmienna jest zdefiniowana jako: <input id = "li_cuboid_id" type = hidden ng-model = "cuboidId">
Rahul Varadkar,
7

Modyfikacje dokonałem tylko na inicjalizacji kontrolera, dodając odbiornik na przycisku akcji:

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

Inne rozwiązania nie działały w moim przypadku.

Ebru Yener
źródło
4

Wiem, że jest trochę za późno na odpowiedź, ale może uda mi się zaoszczędzić jeden raz dziennie.

Miałem do czynienia z tym samym problemem. Model nie zostanie wypełniony po zaktualizowaniu wartości danych wejściowych z jQuery. Próbowałem użyć zdarzeń wyzwalających, ale bez rezultatu.

Oto, co zrobiłem, co może uratować twój dzień.

Zadeklaruj zmienną w tagu skryptu w formacie HTML.

Lubić:

<script>
 var inputValue="";

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

</script>

Kiedyś to zrobiłeś, korzystając z poniższej usługi angular.

$ okno

Teraz poniżej funkcja getData wywołana z tego samego zakresu kontrolera poda żądaną wartość.

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

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

$scope.getData = function () {
    console.log("Window value " + $window.inputValue);
}}]);
Khawaja Asim
źródło
3

Napisałem tę małą wtyczkę do jQuery, która będzie wykonywać wszystkie wywołania .val(value)aktualizacji elementu kątowego, jeśli jest obecny:

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

Po prostu włóż ten skrypt po tym, jak jQuery i angular.js, a val(value)aktualizacje powinny teraz działać dobrze.


Wersja zminimalizowana:

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

Przykład:

dav_i
źródło
Przepraszam za poważne wykopywanie tego, ale masz pomysł, jak to mogłoby / mogłoby działać z polem wyboru lub selekcjami, skoro używają one .prop zamiast .val? Działa to idealnie przynajmniej w przypadku zmian wejściowych .val, więc dziękuję!
Austin
@Austin Obawiam się, że nie wiem. To jest pytanie sprzed 5 lat, dotyczące dwóch technologii, które są powszechnie uważane za przestarzałe, dlatego nie zachowałem wiedzy w głowie. Powodzenia w znalezieniu potrzebnego rozwiązania.
dav_i
2

Jeśli używasz IE, musisz użyć: input.trigger ("change");

William
źródło
2

dodać .change()po ustawieniu wartości.

przykład:('id').val.('value').change();

nie zapomnij również dodać onchangelub ng-changeoznaczyć w html

Azeez
źródło
0

Zrobiłem to, aby móc zaktualizować wartość ngModel z zewnątrz za pomocą 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");
anlijudavid
źródło