2011-12-27 25 views
59

Bên trong biểu thức ràng buộc knockout.js, tôi có thể sử dụng $data, $parent, and $root pseudovariables. Làm thế nào tôi có thể nhận được tương đương với những pseudovariables khi tôi đang sử dụng một số ko.computed observable được khai báo trong JavaScript?

Tôi có chế độ xem mô hình gốc với bộ sưu tập trẻ em và mô hình chế độ xem chính có số selectedChild có thể quan sát được. Cho rằng, tôi có thể sử dụng biểu thức liên kết dữ liệu để thêm một lớp CSS để bất cứ đứa trẻ hiện đang được chọn: "Tôi chọn"

<ul data-bind="foreach: children"> 
    <li data-bind="text: name, 
        css: {selected: $data === $root.selectedChild()}, 
        click: $root.selectChild"></li> 
</ul> 
<script> 
vm = { 
    selectedChild: ko.observable(), 
    children: [{name: 'Bob'}, {name: 'Ned'}], 
    selectChild: function(child) { vm.selectedChild(child); } 
}; 
ko.applyBindings(vm); 
</script> 

Nhưng viewmodels tôi sẽ nhận được phức tạp hơn, và tôi muốn để có thể làm nhiều hơn là chỉ thêm một lớp CSS vào một phần tử duy nhất. Tôi thực sự muốn tạo một thuộc tính được tính trên isSelected trên mô hình xem con, vì vậy tôi có thể thêm các thuộc tính được tính toán khác phụ thuộc vào nó.

Tôi đã cố gắng chỉ viết JavaScript mà đề cập đến $data$root, trên off-cơ hội loại trực tiếp mà có thể xác định các biến và bằng cách nào đó có chúng được trong phạm vi khi nó gọi chức năng computed đánh giá của tôi:

{ 
    name: 'Bob', 
    isSelected: ko.computed(function(){ return $data === $root.selectedChild(); }) 
} 

Nhưng không có may mắn như vậy: bên trong bộ đánh giá của tôi function, cả hai $data$rootundefined.

Tôi cũng đã thử sử dụng ko.contextFor bên trong bộ đánh giá vì nó cung cấp quyền truy cập vào $data$root. Thật không may, bên trong chức năng đánh giá của tôi, contextFor cũng luôn trả về undefined. (Tôi đã không giữ hy vọng cao cho chiến lược này anyway - nó không rõ ràng như thế nào knockout sẽ có thể theo dõi các phụ thuộc nếu tôi đã phải đi sau lưng của nó như thế này.)

Tôi luôn có thể tự thiết lập một thuộc tính trên mỗi viewmodel con tham chiếu trở lại viewmodel cha. Nhưng tôi biết rằng loại trực tiếp đó có khả năng làm điều này cho tôi, và tôi muốn ít nhất là khám phá xem liệu tôi có thể sử dụng các cơ chế của nó trước khi tôi tự viết hay không.

Nó có vẻ như nó nên có thể dịch biểu thức ràng buộc ở trên để một quan sát tính - sau khi tất cả, that's what knockout already does:

Bí quyết gọn gàng khác là ràng buộc khai báo được thực hiện đơn giản là quan sát tính toán.

Nhưng làm cách nào để xử lý các biến giả $data$root khi tôi đang viết quan sát được tính của riêng mình?

Trả lời

76

Các pseudovariables chỉ có sẵn trong ngữ cảnh ràng buộc dữ liệu. Mô hình khung nhìn chính nó lý tưởng không nên biết hoặc có bất kỳ phụ thuộc nào trên khung nhìn đang hiển thị nó.

Vì vậy, khi thêm các quan sát được tính trong mô hình khung nhìn, bạn không có kiến ​​thức về cách nó sẽ bị ràng buộc (như cái gì sẽ là $ root). Một mô hình khung nhìn hoặc một phần của một mô hình xem thậm chí có thể bị ràng buộc riêng biệt với nhiều khu vực của trang ở các cấp khác nhau, do đó các biến giả sẽ khác nhau tùy thuộc vào yếu tố mà bạn đang bắt đầu.

Tùy thuộc vào những gì bạn đang cố gắng hoàn thành, nhưng nếu bạn muốn con mình có một số quan sát được cho phép xem mục này có giống với mục đã chọn trên mô hình chế độ xem gốc hay không, bạn sẽ cần phải tìm một cách để làm cho phụ huynh có sẵn cho đứa trẻ.

Một tùy chọn là chuyển phụ huynh vào hàm hàm tạo của con bạn. Bạn thậm chí không cần phải thêm con trỏ vào cha mẹ như là một tài sản của đứa trẻ và chỉ có thể sử dụng nó trong của bạn có thể quan sát trực tiếp.

Cái gì như:

var Item = function(name, parent) { 
    this.name = ko.observable(name); 
    this.isSelected = ko.computed(function() { 
     return this === parent.selectedItem();   
    }, this); 
}; 

var ViewModel = function() { 
    this.selectedItem = ko.observable(); 
    this.items = ko.observableArray([ 
     new Item("one", this), 
     new Item("two", this), 
     new Item("three", this) 
     ]); 
}; 

mẫu ở đây: http://jsfiddle.net/rniemeyer/BuH7N/

Nếu tất cả các bạn quan tâm là tình trạng chọn, sau đó bạn có thể tinh chỉnh nó để vượt qua một tham chiếu đến selectedItem quan sát để các nhà xây dựng con như : http://jsfiddle.net/rniemeyer/R5MtC/

Nếu mô hình chế độ xem gốc của bạn được lưu trữ trong biến toàn cục, bạn có thể xem xét không chuyển nó cho trẻ và sử dụng trực tiếp như: http://jsfiddle.net/rniemeyer/3drUL/. Tôi thích truyền tham chiếu cho đứa trẻ.

+0

cảm ơn bạn vì ví dụ thứ hai của bạn! – vittore

+0

làm thế nào bạn sẽ gọi một hàm trên root cũng như nhấp chuột: $ root.selectedItem, trong cùng một ràng buộc? – FutuToad

+0

ví dụ, điều này không hoạt động: click: function() {$ parent.openAlertDialogueEdit ($ data)} // $ data có vẻ là một bản sao, chứ không phải tham chiếu thực tế – FutuToad

-7

Sử dụng $context thay vì $parent khi ở trong ràng buộc foreach.

1

Theo kinh nghiệm của tôi, cách tiếp cận trong câu trả lời của @RP Niemeyer là tốt nếu sống trong khoảng thời gian của ứng dụng là Item. Nhưng nếu không, nó có thể dẫn đến rò rỉ bộ nhớ, bởi vì quan sát được tính toán của Item thiết lập một sự phụ thuộc ngược từ ViewModel. Một lần nữa, đó là ok nếu bạn không bao giờ thoát khỏi bất kỳ đối tượng Item. Nhưng nếu bạn cố gắng loại bỏ các số Item thì chúng sẽ không bị thu gom rác bởi vì loại trực tiếp sẽ vẫn có tham chiếu phụ thuộc ngược.

Bạn thể hãy chắc chắn để định đoạt() của tính toán, có lẽ trong một phương pháp làm sạch() trên Item đó được gọi là khi mục sẽ biến mất, nhưng bạn cần phải nhớ để làm điều đó bất cứ khi nào loại bỏ Item s.

Thay vào đó, tại sao không làm cho Item ít thông minh hơn và có ViewModel cho biết khi nào được chọn? Chỉ cần thực hiện isSelected() một mức độ thường xuyên cũ có thể quan sát được và sau đó trong ViewModel, hãy đăng ký selectedItem và cập nhật bên trong đăng ký đó.

Hoặc sử dụng @RP Niemeyer's pub/sub solution. (Để công bằng, giải pháp này xuất hiện sau câu trả lời của anh ấy ở đây.) Bạn vẫn cần phải dọn dẹp, bởi vì nó cũng tạo ra sự phụ thuộc ngược lại. Nhưng ít nhất có ít khớp nối hơn.

Xem câu trả lời cho my recent question về cùng chủ đề này để biết thêm chi tiết.

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