2013-03-01 43 views
16

Tôi đang mắc kẹt với những gì phải là một sửa chữa đơn giản. Tôi đang sử dụng knockout.js với mô hình xem lồng nhau, và tất cả có vẻ tốt ngoại trừ chức năng loại bỏ của tôi không hoạt động chính xác. Nó dường như được ràng buộc một cách chính xác, tuy nhiên nó không được kích hoạt khi tôi nhấp vào loại bỏ.Loại bỏ chế độ xem lồng nhau

Tại sao các kiểu xem lồng nhau? Long câu chuyện, nhưng về cơ bản rất nhiều thứ được yêu cầu phải được trên một trang!

Vì vậy, đây là mã:

HTML

<section class="mini-form-container"> 
    <form data-bind="submit: repeatGuest.addDate"> 
     <input type="date" data-bind="value: repeatGuest.previousStay"/> 
     <button type="submit" class="button-secondary ">Add date</button> 
    </form> 
    <div data-bind="foreach: repeatGuest.dates, visible: repeatGuest.dates().length > 0"> 
     <div> 
      <input data-bind="value: date" disabled="disabled" /> 
      <a data-bind="click: $parent.removeDate">Remove</a> 
     </div> 
    </div> 
</section> 

<section> 
    <div data-bind="text: ko.toJSON($data)"></div> 
</section> 

Javascript

function RepeatGuest() { 
    /// <summary>Child View Model</summary> 
    this.dates = ko.observableArray(); 
    this.previousStay = ko.observable(); 
} 

RepeatGuest.prototype.addDate = function() { 
     var self = this.repeatGuest; 
     if (self.previousStay()) { 
      self.dates.push({ 
       date: self.previousStay() 
      }); 
     } 
    }; 

RepeatGuest.prototype.removeDate = function (date) { 
    this.dates.remove(date); 
} 

function ViewModel() { 
    var self = this; 
    self.repeatGuest = new RepeatGuest(); 
} 
ko.applyBindings(new ViewModel()); 

Và đây là fiddle tôi: http://jsfiddle.net/6Px4M/2/

Vậy tại sao chức năng loại bỏ của tôi không bị sa thải?

Câu hỏi phụ có thể xảy ra: là các kiểu xem lồng nhau sai đường dẫn vào loại trực tiếp, dường như không có nhiều thông tin về điều này?

Trả lời

23

Một trong những cách tốt nhất để làm việc với một mô hình lồng nhau như thế này là sử dụng with ràng buộc. Bạn có thể làm:

<div data-bind="with: repeatGuest"> 
    ... 
</div> 

Bây giờ, phạm vi là repeatGuest của bạn và bạn có thể liên kết trực tiếp chống lại các thuộc tính của nó.

Sự cố với chức năng remove của bạn có liên quan đến giá trị this và ai là lúc $parent. Các hàm được thực thi với giá trị là this bằng với phạm vi hiện tại. Khi hàm remove của bạn bị ràng buộc, phạm vi là một trong các đối tượng trong mảng date.

Cách thông thường để xử lý việc này là đảm bảo rằng chức năng của bạn bị ràng buộc luôn sử dụng giá trị chính xác của this. Điều này có thể được thực hiện trong các ràng buộc (rất xấu xí) như:

<a data-bind="click: $parent.repeatGuest.removeDate.bind($parent.repeatGuest)">Remove</a> 

Một lựa chọn tốt hơn là để ràng buộc nó trong mô hình xem, trong RepeatGuest constructor của bạn:

this.removeDate = this.removeDate.bind(this); 

Điều này cho phép thực hiện để sống trên nguyên mẫu và ghi đè lên từng trường hợp với một trình bao bọc buộc giá trị chính xác của this. Ngoài ra, nếu bạn không đặt nó trên nguyên mẫu, thì bạn có thể sử dụng mẫu var self = this; và sử dụng self trong trình xử lý.

http://jsfiddle.net/cNdJj/

+0

Tôi thích mẫu 'var self = this'. Nó dễ dàng hơn cho tôi để luôn luôn sử dụng 'self' hơn là nhớ ràng buộc các hàm. Nó cũng trông sạch hơn, imo. – Tyrsius

+0

công cụ tốt này, +1 từ tôi, nhưng có một vấn đề cơ bản hơn là chức năng này không bao giờ được chạy kể từ khi anh ta mắc kẹt nó trên nguyên mẫu. Mặc dù nếu anh ta theo tất cả các bước của bạn sẽ được giải quyết quá. –

+0

@Tyrsius - Tôi đã cố gắng thể hiện cách bạn vẫn có thể thực hiện chức năng trên mẫu thử nghiệm. 'self' là một mô hình tốt. –

4

Ràng buộc sẽ không truy cập chức năng trên mẫu thử sai. Bạn đang ràng buộc với viewModel, không phải đối tượng RepeatGuest ngay bây giờ.

Nó hoạt động nếu bạn thiết lập nó như là một chức năng địa phương:

http://jsfiddle.net/6Px4M/3/

function ViewModel() { 
    var self = this; 
    self.repeatGuest = new RepeatGuest(); 
    self.removeDate = function (date) { 
     self.repeatguest.dates.remove(date); 
    } 
} 
+0

Ah, đây là cách tôi đã có nó ban đầu. Tuy nhiên viewModel của tôi đã trở thành lớn và tôi đã cố gắng để refactor nó kích thước xuống. Có cách nào khác để lấy chức năng xóa khỏi mô hình xem không? –

+0

Chắc chắn, bạn luôn có thể kéo nó ra và chỉ cần đặt 'self.removeDate' thành tên hàm. –

+1

@ RPNiemeyer của giải pháp là hoàn chỉnh hơn mặc dù. –

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