Обновите угловую модель после установки входного значения с помощью jQuery

160

У меня есть этот простой сценарий:

Входной элемент, значение которого изменяется методом val () jQuery.

Я пытаюсь обновить угловую модель со значением, установленным jQuery. Я пытался написать простую директиву, но она не делает то, что я хочу.

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

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

это часть jQuery:

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

и HTML:

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

<button>clickme</button>

Вот скрипка с моей попыткой:
http://jsfiddle.net/U3pVM/743/

Может кто-нибудь, пожалуйста, укажите мне в правильном направлении?

Михал Дж.
источник
2
Смешивать AngularJS и jQuery, вне директив, часто плохая идея. Является ли jQuery обязательным для того, что вы хотите сделать?
Blackhole
Почему бы вам не установить событие click с angular для функции в контроллере, чтобы изменить значение модели?
Джимми Кейн
@ Blackhole, я использую плагин загрузки jquery, который выполняет свою работу и помещает путь к загруженному файлу в скрытый ввод. Все, что мне нужно, это иметь доступ к этому пути в угловой модели. Поэтому я решил установить значение скрытого ввода и после его изменения обновить угловую модель.
Михал Дж.
Я не вижу вызова Jquery в вашей скрипке ... Можете ли вы проверить и указать, где вы меняете значение с помощью JQ?
Валентин Шибанов
Ваша скрипка ссылается на пример приложения Todo, которое не относится к этому вопросу.
Стьюи

Ответы:

322

ngModel прослушивает событие «input», поэтому, чтобы «исправить» ваш код, вам нужно вызвать это событие после установки значения:

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

Для объяснения этого конкретного поведения проверьте ответ, который я дал некоторое время назад: « Как AngularJS внутренне перехватывает такие события, как« onclick »,« onchange »? »


Но, к сожалению, это не единственная проблема, которая у вас есть. Как указано в других комментариях к публикации, ваш jQuery-ориентированный подход совершенно неверен. Для получения дополнительной информации взгляните на этот пост: как мне «думать в AngularJS», если у меня есть jQuery фон? ).

Стьюи
источник
5
Прохладно! За одним исключением: почему он не работает на скрытых входах? Когда я переключаю свой тип ввода на текст, он работает как положено.
Кароль
8
Это решило главную проблему при использовании плагинов календаря jquery. Взломая плагин для запуска ('input') после input.val (), событие ng-change срабатывает после выбора пользователем календарной даты. Спасибо!
Drone Brain
3
Отлично работает на скрытом вводе: element.triggerHandler («change»);
Фалько
2
это не работает для меня. $ ( "# Расстояние") Вал (данные). $ ( "# Расстояние") триггер ( 'вход').
Стас Свишов
10
В Angular 1.4.3 inputсобытие не работает в IE, включая IE11. inputсобытие работает только тогда, когда $sniff.hasEvent('input')верно, но $sniff.hasEvent('input')ложно даже в IE11! Мы можем использовать changeсобытие вместо
Шухей Кагава
61

Надеюсь, это кому-нибудь пригодится.

Я не смог получить jQuery('#myInputElement').trigger('input')событие, чтобы забрать мое угловое приложение.

Однако я был в состоянии получить, angular.element(jQuery('#myInputElement')).triggerHandler('input')чтобы меня забрали.

ginman
источник
2
пожалуйста, объясните решение, а не просто пишите код. Я получаю угловой не $ не является функцией
Thakhani Tharage
1
$ представляет здесь jQuery. Это отмечено в вопросе.
Джинман
Это тоже сработало, пока $ ('myInputElement'). Trigger ('input') был нестабильным. Иногда это казалось случайным, но не другим, и я никогда не мог установить образец. Это решение работает каждый раз.
BryanP
2
Мой работает с префиксом #:angular.element($('#myInputElement')).triggerHandler('input')
Эбру Йенер
Этот триггерHandler работал для меня также, я имел дело с textarea, а не ввода. Спасибо
Мунир
25

Принятый ответ, инициировавший inputсобытие с помощью jQuery, у меня не сработал. Создание события и диспетчеризация с нативным JavaScript сделали свое дело.

$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));
Мартинс Балодис
источник
Это было решением для меня тоже. Используя Angular 1.1.5, jQuery 2.2.4 и Jasmine 2.5.3. Очень, ОЧЕНЬ странно, что никакие другие триггерные механизмы не работают.
Ларс-Эрик
Я искал собственный метод JS для запуска проверки формы при настройке ввода в сценарии, и это сработало для меня, спасибо.
разойтись
Работает даже с Angular 5, отлично!
Игорь
Спасибо. Особенно полезно в webview.evaluatejavascript
Berry Wing
22

Я не думаю, что здесь требуется jQuery.

Вместо этого вы можете использовать $ watch и ng-click

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

В вашем контроллере:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});
Utopik
источник
1
Спасибо, Утопик, вы правы, я не должен смешивать jquery с angular, когда есть способ выполнить работу, используя angular.
Михал Дж.
17

Вы должны использовать следующий код, чтобы обновить область действия конкретной модели ввода следующим образом

$('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
источник
1
var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); эта часть мне очень помогла. Моя проблема заключалась в обновлении угловой модели после вызова jjery ajax в функции успеха. Это было медленно с $ http, потому что там был дубликат слушателя события изменения для элемента, который делал что-то еще, поэтому я слил его в jQuery.
Эммануэль Махуни
1
Использование element.scope () - плохая идея, потому что он работает только с включенным ведением журнала. Если вы работаете на производственном сайте, вам следует отключить вход в свою конфигурацию с помощью $compileProvider.debugInfoEnabled(false);или $logProvider.debugEnabled(false);см. Code.angularjs.org/1.4.0/docs/guide/production для получения дополнительной информации.
RWAM
Я попробовал этот метод для скрытой переменной, и он работал. var li_cuboid_id = $ ('# li_cuboid_id'); li_cuboid_id.val (json.cuboidId) .Кнопка (); var scope = angular.element ($ ("# li_cuboid_id")). scope (); scope. $ apply (function () {scope.cuboidId = json.cuboidId;}); скрытая переменная определяется как: <input id = "li_cuboid_id" type = hidden ng-model = "cuboidId">
Рахул Варадкар
7

Я внес изменения только в инициализацию контроллера, добавив слушателя на кнопку действия:

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

Другие решения не работали в моем случае.

Эбру Йенер
источник
4

Я знаю, что здесь уже поздно отвечать, но, возможно, я смогу сэкономить один раз.

Я имел дело с той же проблемой. Модель не будет заполняться после обновления значения ввода из jQuery. Я пытался использовать триггерные события, но безрезультатно.

Вот что я сделал, чтобы спасти твой день.

Объявите переменную в вашем теге скрипта в HTML.

Подобно:

<script>
 var inputValue="";

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

</script>

Однажды вы сделали это, используя нижеприведенный сервис angular.

$ окно

Теперь ниже функция getData, вызываемая из той же области видимости контроллера, даст вам желаемое значение.

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

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

$scope.getData = function () {
    console.log("Window value " + $window.inputValue);
}}]);
Хаваджа Асим
источник
3

Я написал этот небольшой плагин для jQuery, который будет делать все вызовы для .val(value)обновления углового элемента, если он присутствует:

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

Просто вставьте этот скрипт после jQuery и angular.js, и val(value)обновления теперь должны играть хорошо.


Минимизированная версия:

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

Пример:

dav_i
источник
Прошу прощения, что могу раскопать это, но есть идеи, как это может / могло бы работать с флажком или выбором, поскольку они используют .prop вместо .val? Это работает идеально для ввода .val изменений, по крайней мере, так что спасибо!
Остин
@ Остин, боюсь, я не знаю. Это пятилетний вопрос о двух технологиях, которые широко считаются устаревшими, поэтому я не держал знания в голове. Желаем удачи в получении необходимого вам решения.
dav_i
2

Если вы используете IE, вы должны использовать: input.trigger ("change");

Уильям
источник
2

добавить .change()после установки значения.

пример:('id').val.('value').change();

Также не забудьте добавить onchangeили ng-changeпометить в HTML

Azeez
источник
0

Я сделал это, чтобы иметь возможность обновить значение ngModel извне с помощью 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
источник