AngularJS: ng-model binding không cập nhật khi được thay đổi bằng jQuery


98

Đây là HTML của tôi:

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

Khi tôi nhập vào ô, mô hình được cập nhật thông qua cơ chế ràng buộc 2 chiều. Ngọt.

Tuy nhiên khi tôi thực hiện việc này thông qua JQuery ...

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

Nó không cập nhật mô hình. Tại sao?


1
Tại sao bạn sẽ làm cái thứ hai để bắt đầu? Bạn đang sử dụng một khuôn khổ và sau đó quyết định bỏ qua nó và đặt giá trị thông qua thao tác DOM. Lời khuyên tốt nhất mà người ta có thể đưa ra với những người mới bắt đầu: hãy quên sự tồn tại của jquery. trong 90% trường hợp, góc là đủ và 10% còn lại có thể đạt được thông qua jqlite bên trong liên kết của chỉ thị (phần tử thực sự là một phần tử được bao bọc bằng jqlite đã sẵn sàng để được thao tác).
Void

1
câu hỏi rất quan trọng
Syed Md. Kamruzzaman

có những lý do rất chính đáng khiến bạn có thể muốn thay đổi các mô hình góc cạnh bằng thao tác dom, có thể bạn là một nhà phát triển đang làm việc với công cụ kiểm tra A / B và muốn điền vào các biểu mẫu đằng sau hậu trường hoặc bạn đang làm việc trên một tập lệnh Greasemonkey để tự động điền biểu mẫu.
Shadaez

Câu trả lời:


134

Angular không biết về sự thay đổi đó. Đối với điều này, bạn nên gọi $scope.$digest()hoặc thực hiện thay đổi bên trong $scope.$apply():

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

Xem phần này để hiểu rõ hơn về kiểm tra bẩn

CẬP NHẬT : Đây là một ví dụ


Tôi đã làm điều này giống như bạn nói: fiddle.jshell.net/AladdinMhaimeed/agvTz/8 nhưng nó không hoạt động
Aladdin Mhemed 16/10/12

1
Hãy xem fiddle.jshell.net/agvTz/38 này Bạn nên gọi function$ scope. $ Apply truyền một hàm làm đối số. Và $ apply sẽ được gọi khi bạn thực hiện các thay đổi trên $ scope, vì vậy, bên trong onSelect. Ah, tôi hy vọng rằng bạn đặt DOM bên trong thao tác của bộ điều khiển chỉ ví dụ, trong một ứng dụng thực điều này là sai;)
Renan Tomal Fernandes

sau đó tôi phải làm gì để thực hiện tốt các góc? tách thao tác DOM thành một chỉ thị?
Aladdin Mhemed 17/10/12

2
Vâng, ở đây một ví dụ fiddle.jshell.net/agvTz/39 chỉ thị có thể được sử dụng nhiều lần bạn muốn với một đơn giản datepicker="scopeKeyThatYouWant"trong đầu vào
Renan Tomal Fernandes

Chỉ cần gọi .. $ scope. $ Digan () để giải quyết. nó sẽ chậm lại?
Thant Zin

29

Chỉ dùng;

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

Tôi đã sử dụng trigger('input')với công cụ chọn ngày trong onSelectsự kiện của nó . Nó cập nhật giá trị một cách chính xác.
iman

Điều này đã làm các mẹo cho tôi. Tôi đang cập nhật giá trị của đầu vào liên kết từ kiểm tra chỉ thị và gói lệnh .val('something'gọi trong $apply(hoặc gọi $digestsau đó) không hoạt động.
Tom Seldon,

2
Sau nhiều giờ tìm kiếm, đây là một trong những hoạt động! Cảm ơn bạn!
Dan

Alhamdulillah, hoàn hảo, nó làm việc cho tôi. nhờ tiết kiệm thời gian của mình
Syed Md Kamruzzaman.

Thật. Tôi đã sử dụng $('#selectedDueDate').val(dateText).trigger('change');mà không làm việc cho tôi. .trigger('input');hoạt động giống như ma thuật
jafarbtech

17

Tôi nhận thấy rằng nếu bạn không đặt biến trực tiếp vào phạm vi mà nó cập nhật sẽ đáng tin cậy hơn.

Hãy thử sử dụng một số "dateObj.selectedDate" và trong bộ điều khiển thêm Ngày đã chọn vào đối tượng dateObj như sau:

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

Điều này đã làm việc cho tôi.


4
Cái này cũng có tác dụng với tôi. Tôi đã lãng phí hơn 2 giờ để cố gắng tìm ra lý do tại sao ràng buộc hai chiều không hoạt động. Nó hoạt động tốt trên trang, nhưng phạm vi trong bộ điều khiển không được cập nhật. Sau đó, tôi đã thử cách tiếp cận của bạn vì tuyệt vọng (bởi vì tôi không có ý nghĩa gì với tôi rằng điều này phải đúng) và chết tiệt, nó đã thành công! Cảm ơn!
TMc

3
Tương tự ở đây - bất kỳ chuyên gia về góc cạnhJs nào có thể giải thích tại sao điều này lại hiệu quả không? Nó giống như quan điểm của nó có phạm vi lồng riêng và đôi khi bạn gặp khó khăn cập nhật chỉ là xem phạm vi, không phải là điều khiển-vi
Tom Carver

1
Hoạt động tốt cho tôi! Tôi tự hỏi tại sao nó không hoạt động giống nhau trên phạm vi trần.
Stephen

1
Nó không liên quan nhiều đến góc cạnh và liên quan nhiều đến cách hoạt động của javascript. Khi bạn gán biến phạm vi cho một đối tượng, bạn đang gán nó bằng tham chiếu, ngược lại với giá trị như được thực hiện khi var được đặt bằng một giá trị nguyên thủy. Tôi đã nói về nó trong bài đăng của tôi ở đây. stackoverflow.com/questions/14527377/… . Tôi đã tham khảo đoạn plunk này mà tôi đã thực hiện trong bài đăng đó để minh họa cho plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview .
Nick Brady

4

Thử cái này

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

Nó có thể sử dụng được khi bạn không có quyền truy cập vào $ scope của bộ điều khiển góc. Ví dụ: khi bạn viết script bằng Tampermonkey.
wassertim


2

Bất cứ điều gì xảy ra bên ngoài Phạm vi của Angular, Angular sẽ không bao giờ biết điều đó.

Chu kỳ tiêu hóa đưa các thay đổi từ mô hình -> bộ điều khiển và sau đó từ bộ điều khiển -> mô hình.

Nếu bạn cần xem Mẫu mới nhất, bạn cần kích hoạt chu kỳ thông báo

Nhưng có khả năng một chu trình thông báo đang diễn ra, vì vậy chúng tôi cần kiểm tra và bắt đầu chu trình.

Tốt hơn là luôn luôn thực hiện một ứng dụng an toàn.

       $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 truyền chuỗi, số và boolean theo giá trị trong khi nó truyền mảng và đối tượng bằng tham chiếu. Vì vậy, bạn có thể tạo một đối tượng trống và làm cho ngày của bạn trở thành thuộc tính của đối tượng đó. Theo cách đó, góc sẽ phát hiện những thay đổi của mô hình.

Trong bộ điều khiển

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

Trong html

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

1

Bạn phải kích hoạt sự kiện thay đổi của phần tử đầu vào vì ng-model lắng nghe các sự kiện đầu vào và phạm vi sẽ được cập nhật. Tuy nhiên, trình kích hoạt jQuery thông thường không hoạt động với tôi. Nhưng đây là thứ hoạt động như một sự quyến rũ

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

Theo dõi không hoạt động

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

Bạn có thể đọc thêm về cách tạo và điều phối các sự kiện tổng hợp .


0

Tôi đã viết plugin nhỏ này cho jQuery, nó sẽ thực hiện tất cả các lệnh gọi .val(value)cập nhật phần tử góc nếu có:

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

Chỉ cần đưa tập lệnh này vào sau jQuery và angle.js và các val(value)bản cập nhật giờ sẽ hoạt động tốt.


Phiên bản thu nhỏ:

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

Thí dụ:


Câu trả lời này đã được sao chép nguyên văn từ câu trả lời của tôi cho một câu hỏi tương tự khác .


0

Chỉ dùng:

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

thay vì:

$('#selectedDueDate').val(dateText);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.