AngularJS: прив'язка ng-моделі не оновлюється при зміні jQuery


98

Це мій HTML:

<input id="selectedDueDate" type="text" ng-model="selectedDate" />

Коли я набираю коробку, модель оновлюється через двосторонній механізм прив’язки. Солодке.

Однак коли я це роблю через JQuery ...

$('#selectedDueDate').val(dateText);

Він не оновлює модель. Чому?


1
Чому б ти зайнявся другим для початку? Ви використовуєте фреймворк, а потім вирішили обійти його і встановити значення за допомогою маніпуляції з DOM. Найкраща порада, яку можна дати новачкам: забудьте, що jquery існує. у 90% випадків кутового буде достатньо, а решта 10% можна досягти за допомогою jqlite всередині посилання директиви (елемент - це фактично елемент, обвитий jqlite, готовий до маніпулювання).
Недійсний

1
дуже важливе запитання
Syed Md. Kamruzzaman

є дуже вагомі причини, чому ви можете змінити кутові моделі з маніпуляцією з домом, можливо, ви розробник, який працює з інструментом тестування A / B і хочете заповнювати форми за кадром, або ви працюєте над сценарієм "змазка" для автозаповнення форм.
Shadaez

Відповіді:


134

Кутовий не знає про цю зміну. Для цього вам слід зателефонувати $scope.$digest()або внести зміни всередині $scope.$apply():

$scope.$apply(function() { 
   // every changes goes here
   $('#selectedDueDate').val(dateText); 
});

Дивіться це, щоб краще зрозуміти брудну перевірку

ОНОВЛЕННЯ : Ось приклад


Я зробив це так, як ви кажете: fiddle.jshell.net/AladdinMhaimeed/agvTz/8, але це не працює
Аладдін Мхемед

1
Дивіться це fiddle.jshell.net/agvTz/38 Вам слід зателефонувати в область function$. $ Застосовувати, передаючи функцію в якості аргументу. І $ apply повинен бути викликом, коли ви внесете зміни в $ range, так, всередині OnSelect. Ах, я сподіваюся, що ви поставите DOM маніпуляції всередині контролера лише для прикладу, в реальному додатку це неправильно;)
Ренан Томал Фернандес

то що мені робити, щоб зробити гарну кутову практику? окрема маніпуляція DOM в директиву?
Аладдін Мхемед

2
Так, ось приклад fiddle.jshell.net/agvTz/39 Директива може бути використана стільки разів, скільки вам потрібно, за допомогою простого datepicker="scopeKeyThatYouWant"вводу
Ренан Томал Фернандес

Просто зателефонуйте. чи сповільниться це?
Тант Зін

29

Просто використовуйте;

$('#selectedDueDate').val(dateText).trigger('input');

Я використовував trigger('input')підбірник побачень у його onSelectподії. Він правильно оновлює значення.
iman

Це зробило для мене трюк. Я поновлював значення пов'язаного вводу з тестування директиви, і завершення .val('something'виклику в $apply(або $digestпісля виклику ) не працювало.
Том Селдон

2
Після годин пошуків це працювало! Дякую!
Ден

Альхамдулілла, досконалий, це працює для мене. спасибі мої години
Syed Md. Kamruzzaman

Правда. Я використовував, $('#selectedDueDate').val(dateText).trigger('change');що не працювало для мене. .trigger('input');працює як магія
jafarbtech

17

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

Спробуйте скористатись деяким "dateObj.selectedDate" і в контролері додайте selectedDate до об'єкта dateObj так:

$scope.dateObj = {selectedDate: new Date()}

Це працювало для мене.


4
Це працювало і для мене. Я витрачав більше 2 годин, намагаючись з'ясувати, чому двостороння зв'язування не працює. Це справно працювало на сторінці, але область в контролері не оновлювалася. Тоді я спробував твій підхід з відчаю (бо мені не було сенсу, що це має бути правдою) і гаряче чорт, це спрацювало! Дякую!
TMc

3
Тут же - чи може будь-який гуру кутового пояснити, чому це працює? Це як у представлення є власна вкладена область, і іноді ви застрягаєте оновлювати лише область перегляду, а не область контролера
Том Карвер,

1
Добре працює для мене! Мені цікаво, чому у чорта не працює так само на голому просторі.
Стівен

1
Це має мало спільного з кутовим, і багато чого з тим, як працює JavaScript. Коли ви присвоюєте змінній області об єкт, ви присвоюєте його за посиланням, на відміну від значення, як це робиться, коли var встановлюється рівним примітивному значенню. Я говорив про це у своєму пості тут. stackoverflow.com/questions/14527377/… . Я посилався на цей планк, який я зробив у цій публікації, щоб проілюструвати plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview .
Нік Брейді

4

Спробуйте це

var selectedDueDateField = document.getElementById("selectedDueDate");
var element = angular.element(selectedDueDateField);
element.val('new value here');
element.triggerHandler('input');

Він може бути використаний, коли у вас немає доступу до області застосування кутового контролера. Коли ви пишете сценарій, наприклад, з Tampermonkey.
wassertim


2

Що б не траплялося за межами сфери кутових, Angular ніколи цього не дізнається.

Цикл дайджесту вносить зміни з моделі -> контролера, а потім з контролера -> моделі.

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

Але є ймовірність перетравлення циклу в процесі, тому нам потрібно перевірити та запустити цикл.

Переважно завжди виконайте безпечне застосування.

       $scope.safeApply = function(fn) {
            if (this.$root) {
                var phase = this.$root.$$phase;
                if (phase == '$apply' || phase == '$digest') {
                    if (fn && (typeof (fn) === 'function')) {
                        fn();
                    }
                } else {
                    this.$apply(fn);
                }
            }
        };


      $scope.safeApply(function(){
          // your function here.
      });

1

AngularJS передає рядок, числа та булеві значення за значенням, тоді як він передає масиви та об'єкти за посиланням. Таким чином, ви можете створити порожній об’єкт і зробити свою дату властивістю цього об'єкта. Таким чином кутові будуть виявляти зміни моделі.

У контролері

app.module('yourModule').controller('yourController',function($scope){
$scope.vm={selectedDate:''}
});

У html

<div ng-controller="yourController">
<input id="selectedDueDate" type="text" ng-model="vm.selectedDate" />
</div>

1

Вам потрібно запустити подію зміни елемента введення, оскільки ng-модель слухає події введення, і область буде оновлена. Однак звичайний тригер jQuery не працював для мене. Але ось те, що працює як шарм

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

Слідування не вийшло

$("#myInput").trigger("change"); // Did't work for me

Ви можете прочитати більше про створення та диспетчеризацію синтетичних подій .


0

Я написав цей маленький плагін для 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);

Приклад:


Ця відповідь була скопійована дослівно з моєї відповіді на інше подібне запитання .


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.