2010-12-01 29 views
17

Tôi tự hỏi làm thế nào tôi có thể thực hiện một số trường quan sát trong knockout.js mà tôi nhận được từ cuộc gọi ajax mà không cần phải xác định toàn bộ đối tượng trong viewmodel của tôi. Điều này có thể không? Dưới đây là những gì tôi có cho đến nay:làm cho các trường quan sát được sau khi truy xuất ajax trong knockout.js

var viewModel = { 
    lines: new ko.observableArray([]) 
}; 
function refreshList(ionum) { 
    var data = {}; 
    data['IONum'] = ionum; 
    $.ajax({ 
    url: 'handlers/getlines.ashx', 
    data: data, 
    cache: false, 
    dataType: 'json', 
    success: function(msg) { 

     viewModel.lines(msg); 
     //here is where I am attempting to make the email address field observable 
     /*for (var i = 0; i < msg.length; i++) { 
      viewModel.lines()[i].emailAddress = new ko.observable(msg[i].emailAddress); 

     }*/ 

     //alert(viewModel.lines[0].emailAddress); 
     //ko.applyBindings(viewModel); 


    } 

}); 
} 
+2

+1 cho câu hỏi hay: knockout + ajax howto –

Trả lời

3

Tôi cố định vấn đề này, phát hiện ra nó là tốt hơn để khai báo các lĩnh vực quan sát được trên đối tượng của tôi trước khi đặt nó vào quan điểm của tôi, giống như

for (var i=0;i<msg.lenth;i++){ 
msg[i].emailAddress=ko.observable(msg[i].emailAddress); 
} 
viewModel.lines(msg); 
1

Đây là CoffeeScript tôi RequireJS module để chuyển đổi những gì tôi gọi là "xem dữ liệu" (máy chủ có nguồn gốc từ các giá trị JSON) để ViewModels KO:

define "infrastructure/viewModels", [], (viewModels) -> 
    exports = {} 

    isDate = (x) -> 
     typeof x is "string" and 
     x.startsWith "/Date(" 

    deserializeDate = (dateString) -> 
     new Date(parseInt(dateString.substr(6))) 

    isScalar = (x) -> 
     x is null or 
     typeof x is "string" or 
     typeof x is "number" or 
     typeof x is "boolean" 

    exports.fromViewData = (viewData) -> 
     if isDate viewData 
      return ko.observable deserializeDate viewData 
     if isScalar viewData 
      return ko.observable viewData 

     viewModel = {} 
     for own key, value of viewData 
      if key is "id" then continue 

      viewModel[key] = 
       if Array.isArray value 
        ko.observableArray (exports.fromViewData el for el in value) 
       else 
        exports.fromViewData value 

     return viewModel 

    return exports 

sử dụng mẫu:

require ["infrastructure/viewModels"], (viewModels) -> 
    $.getJSON "/url/to/data", (viewData) -> 
     viewModel = viewModels.fromViewData viewData 
     ko.applyBindings viewModel 

Tất nhiên, nếu bạn không làm CoffeeScript, bạn có thể dịch sang JavaScript bằng cách nhấp vào "Thử CoffeeScript" trên trang web được liên kết. Và nếu bạn không sử dụng RequireJS, thì chỉ cần lấy các hàm liên quan từ mô-đun của tôi mà không cần gói chúng trong define.

+1

Tôi không hiểu tại sao bạn cho rằng CoffeeScript sẽ hữu ích? – badsyntax

+0

lol ya, vào tháng 3 năm 2011 đó là điều cần làm: P – Domenic

8

Với the mapping plugin for Knockout bạn có thể xác định mô hình nhìn của bạn từ một đối tượng Javascript đơn giản, như trở về từ một cuộc gọi Ajax:

var viewModel = ko.mapping.fromJS(data); 
// Every time data is received from the server: 
ko.mapping.updateFromJS(viewModel, data); 

Tôi đã có một tình huống gần như tương tự, nơi các đối tượng của tôi là trường hợp của các lớp học Javascript. Các lớp học được định nghĩa mà không có Knockout trong tâm trí, và tôi muốn thay đổi chúng để sử dụng các quan sát để thay thế.

Tôi đã tạo một trình trợ giúp nhỏ để chuyển đổi các đối tượng thông thường thành các đối tượng quan sát được. Bạn có thể chỉ định các trường quan sát được, hoặc đặt chúng trong đối tượng (prototype). (Tôi nghĩ để làm điều này tự động, nhưng tôi không thể xác định lĩnh vực là an toàn để chuyển đổi và cái nào không.)

(function() { 
    ko.observableObject = function(object, ko_fields) { 
     ko_fields = ko_fields || object._ko_fields; 
     if (!ko_fields) { 
      return object; 
     } 
     for (var f_idx = 0; f_idx < ko_fields.length; f_idx++) { 
      var field_name = ko_fields[f_idx]; 
      if (object[field_name] && object[field_name].__ko_proto__ !== undefined) { 
       continue; 
      } 
      if (object[field_name] instanceof Array) { 
       var field_array = object[field_name]; 
       for (var a_idx = 0; a_idx < field_array.length; a_idx++) { 
        field_array[a_idx] = ko.observableObject(field_array[a_idx]); 
       } 
       object[field_name] = ko.observableArray(field_array); 
      } else { 
       object[field_name] = ko.observable(object[field_name]); 
      } 
     } 

     return object; 
    }; 
})(); 

Bạn có thể sử dụng nó với các lớp học hoặc với các đối tượng đơn giản.

// With classes. We define the classes without Knockout-observables 
// User.subscriptions is an array of Subscription objects 
User = function(id, name) { 
    this.id = id; 
    this.name = name; 
    this.subscriptions = []; 
}; 

Subscription = function(type, comment) { 
    this.type = type; 
    this.comment = comment; 
}); 

// Create some objects 
var jan = new User(74619, "Jan Fabry"); 
jan.subscriptions.push(new Subscription("Stack Overflow", "The start")); 
jan.subscriptions.push(new Subscription("Wordpress Stack Exchange", "Blog knowledge")); 
var chris = new User(16891, "Chris Westbrook"); 

// We would like to convert fields in our objects to observables 
// Either define the fields directly: 
ko.observableObject(jan, ['id', 'name', 'subscriptions']); 
ko.observableObject(chris, ['id', 'name', 'subscriptions']); 
// This will only convert the User objects, not the embedded subscriptions 
// (since there is no mapping) 

// If you define it in the class prototype, it will work for embedded objects too 
User.prototype._ko_fields = ['id', 'name', 'subscriptions']; 
Subscription.prototype._ko_fields = ['type', 'comment']; 
ko.observableObject(jan); 
ko.observableObject(chris); 

// It also works with objects that are not created from a class, like your Ajax example 
var observable = ko.observableObject({'id': 74619, 'name':'Jan'}, ['id', 'name']); 
Các vấn đề liên quan