KnockoutJs v2.3.0: Lỗi Bạn không thể áp dụng liên kết nhiều lần cho cùng một phần tử


76

Tôi vừa nâng cấp lên 2.3.0 và bây giờ tôi đang gặp lỗi

Bạn không thể áp dụng các ràng buộc nhiều lần cho cùng một phần tử.

mà tôi không nhận được trong 2.2.1.

Tôi đang xem một phần từ bộ điều khiển MVC của mình và thêm nó vào trang sau khi nhấp vào một href. Lỗi xảy ra lần thứ hai khi tôi nhấp vào liên kết để xem một phần. Tôi đang làm điều này nhiều lần.

Có cách nào để xóa điều này và tránh lỗi mới được tạo ra không?

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

$.get(url + "GetAssignedCompaniesView?layoutId=" + layoutId + "&noCache=" + new Date().getMilliseconds(), function (result) {
              $("#editAssignedPartial").html($(result));
              showEditAssignedArea(true);
              $(window.document).ready(function () {
                 // error is thrown here
                 ko.applyBindings(self, window.document.getElementById("editAssigned"));
                 $("#layoutId").attr("value", layoutId);
                 updateTypeHiddenElement.attr("value", "companies");
      });
    });
<div id="editAssignedPartial">
</div>

$(document).ready(function () {
  'use strict';
  var vm = new Vm();
  ko.applyBindings(vm, document.getElementById("area1"));
});

stopBindings là một cách tốt hơn ... knockmeout.net/2012/05/quick-tip-skip-binding.html
— AlignedDev 29/10/14

Câu trả lời:


99

Bạn chỉ cần xóa các ràng buộc trước khi sử dụng lại 'applyBindings'.

ko.cleanNode($element[0]);

nên làm thủ thuật. HTH.


những gì tôi đang làm: Tôi tạo một liên kết tùy chỉnh và bên trong tôi liên kết động một biến với một phần tử. Xem: stackoverflow.com/a/9370953/809536
— ZiglioUK


này làm việc cho tôivar _data = $("view-data"); ko.cleanNode(_data);
— Gbolahan

12
ko.cleanNode()dường như không phải là cách được khuyến nghị để tránh lỗi "áp dụng liên kết nhiều lần". stackoverflow.com/a/15069509/538962
— mg1075

không thể làm cho nó hoạt động với $ ('view-data') hoặc $ ('# knockoutDiv') [0] .. nó tiếp tục đưa ra lỗi liên kết áp dụng. Tôi đã thêm lệnh gọi cleanNode ngay trước khi áp dụng các ràng buộc.
— Sonic Soul

27

Điều gì đó có thể xảy ra cũng như ném ra ngoại lệ này là như sau. Giả sử bạn có:

ko.applyBindings(myViewModel1, document.getElementById('element1'));
...
ko.applyBindings(myViewModel2, document.getElementById('element2'));

Bây giờ, khi cả # element1 và # element2 không tồn tại, bạn sẽ gặp lỗi. Lý do là applyBindings của Knockout rơi trở lại document.body làm phần tử gốc khi không tìm thấy # element1 và # element2. Bây giờ nó cố gắng áp dụng ràng buộc hai lần trên cơ thể ...

Không phải là một dự phòng tốt của Knockout nếu bạn hỏi tôi. Tôi muốn có một thông báo lỗi rõ ràng rằng phần tử không tồn tại trong DOM (chưa).

Hy vọng điều này sẽ giúp một số người.


Đã giải quyết vấn đề của tôi. Tôi đã làm document.getElementById('#element1'). Quên rằng # là một thứ jquery. Thực sự sẽ tốt hơn nhiều nếu loại trực tiếp xuất hiện lỗi 'phần tử không tồn tại trong DOM'.
— jkokorian

Tôi có một điều kiện chủng tộc? hoạt động khác với Chrome / FF / IE. Giải pháp của tôi là gói nó trong một thử nghiệm để loại bỏ các triệu chứng và làm cho trang hoạt động. Sau khi đọc câu trả lời này, tôi cũng đã kiểm tra xem điều khiển có tồn tại trước applyBindings hay không và có thể thấy sự khác biệt giữa các trình duyệt.
— LosManos

Đó là vấn đề của tôi, tôi đã cố gắng để chạy thử nghiệm đơn vị Jasmine và tự hỏi tại sao lỗi này đã đưa ra (các yếu tố các viewmodels được gắn vào không được bao gồm trong các thử nghiệm html)
— kiwicomb123

13

Hai điều quan trọng để các giải pháp trên hoạt động:

  1. Khi áp dụng các ràng buộc, bạn cần xác định phạm vi (phần tử) !!

  2. Khi xóa các ràng buộc, bạn phải chỉ định chính xác phần tử được sử dụng cho phạm vi.

Mã bên dưới

Đánh dấu

<div id="elt1" data-bind="with: data">
    <input type="text" data-bind="value: text1" >
</form>

Chế độ xem ràng buộc

var myViewModel = {
  "data" : {
    "text1" : "bla bla"
  }
}:

Javascript

ko.applyBindings(myViewModel, document.getElementById('elt1'));

Rõ ràng ràng buộc

ko.cleanNode(document.getElementById('elt1'));

Tôi đã sử dụng giải pháp này trong một ứng dụng di động DevExtreme. Vì DevX chạy ko.applyBindings tự động nên đầu tiên tôi phải ko.cleanNode rồi đến ko.applyBindings. Cảm ơn Mitja!
— Patrick

Tại sao bạn sử dụng jQuery selector trong cleanNode()?
— Blaise

Đó là một bộ chọn jquery, nhưng ký hiệu [0] lấy đối tượng DOM của đối tượng jQuery. Tôi đồng ý rằng điều này là không cần thiết và tốt hơn nên sử dụng đối tượng DOM thuần túy hoặc đối tượng jQuery.
— Mitja Gustin

@MitjaGustin tại sao mọi người khuyên không nên sử dụng ko.cleanNode? (và điều này nhờ làm việc cho tôi)
— Tanya Gupta

13

Bạn không bao giờ nên áp dụng các ràng buộc nhiều hơn một lần cho một chế độ xem. Trong 2.2, hành vi không được xác định, nhưng vẫn không được hỗ trợ. Trong 2.3, bây giờ nó hiển thị chính xác một lỗi. Khi sử dụng loại trực tiếp, mục tiêu là áp dụng liên kết một lần cho (các) chế độ xem của bạn trên trang, sau đó sử dụng các thay đổi đối với các chế độ có thể quan sát trên mô hình xem của bạn để thay đổi giao diện và hành vi của (các) chế độ xem trên trang của bạn.


EditAssignedPartial được thêm động vào trang, trong một sự kiện khác với lần tải trang. Nếu tôi xóa applyBidndings khỏi sự kiện nhấp chuột của mình, nó sẽ không hiển thị. Có cách nào tốt hơn để thực hiện thêm động không?
— AlignedDev

20
Đôi khi, việc liên kết một máy ảo với một chế độ xem nhiều lần là hợp lý. Ví dụ: trong giao diện người dùng có thanh điều hướng và div để hiển thị nội dung của từng phần tử thanh điều hướng có thể nhấp, bạn có thể có X số lượng div cho X phần tử thanh điều hướng hoặc chỉ có một div và liên kết các máy ảo với div đó dựa trên những gì phần tử được nhấp.
— vprasad

3
Tôi gặp phải vấn đề tương tự. Tôi có nội dung động mà tôi cần phải kết hợp lại.
— Mike Flynn

2
Một cách tiếp cận khác là sử dụng các mẫu. Bạn có thể thêm động một mẫu <script type='text/html'>...</script>vào trang để kiểm soát nội dung động.
— x0n

Tôi thích ý tưởng sử dụng các mẫu thay vì cách tiếp cận cleanNode. Cảm ơn vì gợi ý đó.
— AlignedDev

9

Có rất nhiều câu trả lời tuyệt vời cho vấn đề này nhưng tôi có một câu trả lời dành cho người khác.

Tôi thấy rằng tôi đã vô tình thêm cùng một Tập lệnh ở hai nơi và nó đang cố gắng liên kết hai lần. Vì vậy, trước khi nhổ tóc vì một lỗi đơn giản, hãy chắc chắn rằng bạn đã kiểm tra vấn đề này.


5

Nếu bạn đang sử dụng lặp đi lặp lại một phần tử (Trong trường hợp của tôi là hộp thoại phương thức bootstrap), thì việc gọi ko.applyBindings(el)nhiều lần sẽ gây ra sự cố này.

Thay vào đó, chỉ cần làm điều đó một lần như sau:

if (!applied) {
    ko.applyBindings(el);
    applied = true;
}

Hoặc như thế này:

var apply = function (viewModel, containerElement) {
    ko.applyBindings(viewModel, containerElement);
    apply = function() {}; // only allow this function to be called once.
}

Tái bút: Điều này có thể xảy ra với bạn thường xuyên hơn nếu bạn sử dụng plugin lập bản đồ và chuyển đổi dữ liệu JSON của mình thành có thể quan sát được.


5

Cuối cùng tôi giải quyết của tôi bằng cách trả lại { controlsDescendantBindings: true }trong initchức năng của bộ xử lý ràng buộc. Xem này


2

Cập nhật câu trả lời

Bây giờ chúng ta có thể sử dụng dataFor()để kiểm tra xem ràng buộc đã được áp dụng chưa, tôi muốn kiểm tra ràng buộc dữ liệu hơn là cleanNode()và applyBindings().

Như thế này:

var koNode = document.getElementById('formEdit');
var hasDataBinding = !!ko.dataFor(koNode);
console.log('has data binding', hasDataBinding);
if (!hasDataBinding) { ko.applyBindings(vm, koNode);}

Câu trả lời gốc.

Rất nhiều câu trả lời rồi!

Đầu tiên, hãy nói rằng chúng ta cần thực hiện ràng buộc nhiều lần trong một trang là khá phổ biến. Giả sử, tôi có một biểu mẫu bên trong phương thức Bootstrap, biểu mẫu này sẽ được tải đi tải lại. Nhiều đầu vào biểu mẫu có ràng buộc hai chiều.

Tôi thường đi theo con đường dễ dàng: xóa ràng buộc mọi lúc trước khi ràng buộc.

var koNode = document.getElementById('formEdit');
ko.cleanNode(koNode);
ko.applyBindings(vm, koNode);

Chỉ cần đảm bảo rằng ở đây koNodelà bắt buộc, đối với, ko.cleanNode()yêu cầu một phần tử nút, mặc dù chúng ta có thể bỏ qua nó ko.applyBinding(vm).


Có vẻ như việc sử dụng ko.cleanNode () không được khuyến khích vì nó được Knockout sử dụng nội bộ và không phải là tài liệu cho nó. stackoverflow.com/questions/15063794/… . Vì vậy, 'dataFor' trông an toàn hơn khi sử dụng. knockoutjs.com/documentation/unobtrusing-event-handling.html
— darmis

1

Tôi đã có lỗi này xảy ra vì một lý do khác.

Tôi đã tạo một mẫu cho các nút lưu / hủy mà tôi muốn xuất hiện ở đầu và cuối trang. Lúc đầu, nó hoạt động khi tôi xác định mẫu của mình bên trong phần tử <script type = "text / html"> .... nhưng sau đó tôi nghe nói rằng bạn có thể tùy chọn tạo mẫu từ phần tử DIV thông thường.

(Điều này hoạt động tốt hơn đối với tôi vì tôi đang sử dụng ASP.NET MVC và không cú pháp @variableName Razor nào của tôi đang được thực thi trong thời gian chạy từ bên trong phần tử tập lệnh. Vì vậy, bằng cách thay đổi thành DIV thay thế, tôi vẫn có thể có công cụ Razor MVC tạo HTML bên trong mẫu KnockoutJs của tôi khi trang tải.)

Sau khi tôi thay đổi mẫu của mình để sử dụng DIV thay vì phần tử SCRIPT, mã của tôi trông như thế này .... hoạt động tốt trên IE10. Tuy nhiên, sau đó khi tôi thử nghiệm nó trên IE8 , nó đã bị lỗi ...

"Bạn không thể áp dụng liên kết nhiều lần cho cùng một phần tử"Lỗi .....

HTML

<div id="mainKnockoutDiv" class="measurementsDivContents hourlyMeasurements">

  <div id="saveButtons_template" style="display: none;">
    ... my template content here ...
  </div>

  <!--ko template: { name: 'saveButtons_template' } -->
  <!--/ko-->

  Some_HTML_content_here....

  <!--ko template: { name: 'saveButtons_template' } -->
  <!--/ko-->

</div>

JavaScript

ko.applyBindings(viewModel, document.getElementById('mainKnockoutDiv'));

GIẢI PHÁP :

Tất cả những gì tôi phải làm là di chuyển saveButtons_template DIV của tôi xuống dưới cùng, để nó nằm ngoài mainKnockoutDiv. Điều này giải quyết các vấn đề đối với tôi.

Tôi cho rằng KnockoutJs đang cố gắng liên kết DIV mẫu của tôi nhiều lần vì nó nằm bên trong vùng mục tiêu của applyBindings ... và không sử dụng phần tử SCRIPT .... và đang được tham chiếu như một mẫu.


Đúng vậy. Di chuyển tập lệnh của tôi bao gồm từ trước HTML mục tiêu sang sau HTML mục tiêu đã thực hiện thủ thuật cho tôi.
— Griffin

1

Tôi đã gặp lỗi tương tự trong IE7 / IE8. Hoạt động tốt trên tất cả các trình duyệt khác bao gồm IE9 / IE10.

Những gì tôi thấy hiệu quả với tôi là loại bỏ các thẻ tự đóng.

Xấu

<div>
    <span data-bind="text: name"/>
</div>

Tốt

<div>
    <span data-bind="text: name"></span>
</div>

1

Trong trường hợp của tôi, tôi đã thêm vào một phần tử không tồn tại hoặc, tôi đang thêm các ràng buộc vào một phần tử có thể tồn tại, nhưng phần tử gốc thì không. Tương tự như thế này:

var segDiv =  $("#segments"); //did not exist, wrong id
var theDiv = segDiv.html("<div></div>");

ko.applyBindings(someVM, theDiv);

Theo như tôi có thể nói, lỗi này có vẻ hơi quá tải theo nghĩa là nó sẽ kích hoạt rất nhiều lỗi khác nhau có thể xảy ra với phần tử, giống như nó không tồn tại. Do đó, mô tả lỗi có thể mang tính lừa đảo cao. Nó có lẽ nên đọc:

"Không thể liên kết các liên kết với phần tử. Các lý do có thể bao gồm: nhiều lần thử liên kết, phần tử không tồn tại, phần tử không có trong phân cấp DOM, các lỗi trong trình duyệt, v.v."


0

tôi đã có cùng một vấn đề và tôi đã giải quyết nó.

var vm = new MessagesViewModel()
ko.applyBindings(vm)

function ShowMessagesList() {
   vm.getData("MyParams")
}

setInterval(ShowMessagesList, 10000)

0
ko.cleanNode($("#modalPartialView")[0]);
ko.applyBindings(vm, $("#modalPartialView")[0]);

hoạt động đối với tôi, nhưng như những người khác lưu ý, đó cleanNodelà kochức năng bên trong , vì vậy có lẽ có một cách tốt hơn.

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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.