2012-09-05 28 views
5

hướng dẫn Folliwing đưa ra trong documentation, tôi có mô hình quan điểm sau đây:vòng lặp vô hạn khi chuyển đổi đối tượng loại trực tiếp đến đối tượng JavaScript đơn giản

var newContactViewModel = function() { 
    var self = this; 

    self.Name = ko.observable(); 
    self.Address = ko.observable(); 
    self.City = ko.observable(); 
    self.State = ko.observable(); 
    self.PostalCode = ko.observable(); 

    self.Save = function() { 
     $.ajax({ 
      type: "POST", 
      url: "/contact", 
      data: ko.toJS(self), //infinite loop here 
      success: state.OnSaved 
     }); 
    }; 
}; 

Khi phương pháp self.Save được gọi, một vòng lặp vô hạn xảy ra. Chrome thực sự báo cáo các lỗi như:

Uncaught RangeError: Maximum call stack size exceeded

Nếu tôi sử dụng ko.mapping.toJS(self) thay vì ko.toJS(self), sau đó tôi nhận được một lỗi hơi hở hang hơn, nhưng không có lỗi thật "message":

infinite loop error

Nếu tôi hoán đổi ko.toJS(self) với một cái gì đó như { Name: self.Name(), Address: self.Address() /* etc */ }, sau đó mọi thứ hoạt động tốt. Có vẻ như nó đang cố gắng chuyển đổi phương thức Save và gọi lại phương thức đó.

Có lỗi trong KnockoutJS hoặc có sự cố khi tôi sử dụng nó. Tôi thích cái sau. Suy nghĩ?

Trả lời

14

Tôi đã tìm ra sự cố với mã. ko.toJS duy trì các chức năng trong đối tượng để có thể ánh xạ nó tốt. Tuy nhiên, jquery sẽ gọi tất cả các hàm trên đối tượng dữ liệu để cố gắng lấy một giá trị. Điều này lần lượt gây ra vòng lặp vô hạn.

Bạn cần gắn cờ chức năng Save để không được ánh xạ. Rất tiếc, chức năng toJS không xuất hiện để có thể thực hiện điều đó. Nó sẽ giữ tất cả các thành viên của đối tượng. Plugin bản đồ may mắn cho phép bạn làm điều đó.

Để loại trừ thành viên, hãy đặt tùy chọn ignore thành một mảng có chứa 'Save' và nó sẽ bỏ qua thành viên Save khi được ánh xạ.

var data = ko.mapping.toJS(self, { 
    ignore: ['Save'] 
}); 

Nếu bạn không sử dụng plugin ánh xạ, bạn luôn có tùy chọn xóa hàm Save khỏi đối tượng JS.

self.Save = function() { 
    $.ajax({ 
     type: "POST", 
     url: "/contact", 
     data: self.ToData(), 
     success: state.OnSaved 
    }); 
}; 
self.ToData = function() { 
    var data = ko.toJS(self); 
    delete data.Save; // remove functions 
    delete data.ToData; 
    return data; 
}; 

Mặt khác, tôi sẽ đề nghị không cố gắng sử dụng các ví dụ xem mô hình như các dữ liệu cho các cuộc gọi của bạn. Thay vào đó, tôi sẽ tạo đối tượng dữ liệu một cách rõ ràng. Chắc chắn nó có tiềm năng rất dài, nhưng đó là một cách tiếp cận rất có khả năng sẽ luôn hoạt động.

self.ToData = function() { 
    return ko.toJS({ 
     Name: self.Name, 
     Address: self.Address, 
     City: self.City, 
     State: self.State, 
     PostalCode: self.PostalCode 
    }); 
}; 
+0

Đó là thông tin thực sự hữu ích, bởi vì tôi đã gặp rắc rối với mô hình Backbone nơi tôi đang bổ sung thêm rất nhiều tài liệu tham khảo bộ sưu tập cha mẹ vv Tuy nhiên, đây chỉ là một giải pháp thực tế, tôi nghĩ rằng, nếu bạn đang tự làm chuyển đổi. Nó không giúp ích nếu ko.toJS được sử dụng trong nội bộ trong mã thư viện khác. – neverfox

+0

giải pháp tốt cho một quyết định thiết kế hoàn toàn tai hại. những gì khá thẳng thắn làm cho tôi tức giận ngay bây giờ là tôi đã không nhận ra hành vi này trong nhiều tháng và về cơ bản nó còn lại là 'theo thiết kế' https://github.com/knockout/knockout/pull/1079 - điều này cần phải được cấu hình –

Các vấn đề liên quan