2010-12-01 45 views
17

後察覺察覺如何我可以使knockout.js中的某些字段observables,我從ajax調用獲得,而無需在我的viewmodel中定義整個對象。這可能嗎?以下是我迄今爲止:使ajax在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問題:knockout + ajax howto – 2010-12-09 09:08:46

回答

3

我解決了這個問題,發現這是更好地將其設置爲我的觀點之前宣佈我的對象上可觀察到的領域裏,如

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

這裏我CoffeeScriptRequireJS module轉換就是我所說的 「查看數據」(服務器衍生JSON值)KO的ViewModels:

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 

用法示例:

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

當然,如果您沒有使用CoffeeScript,您可以通過單擊鏈接站點上的「Try CoffeeScript」來轉換爲JavaScript。如果您不使用RequireJS,那麼只需從我的模塊中取得相關的功能,而不用將它們包裝在define中。

+1

我不明白你爲什麼認爲張貼CoffeeScript會有幫助嗎? – badsyntax 2013-06-12 12:45:38

8

隨着the mapping plugin for Knockout你可以從一個普通的JavaScript對象定義您的視圖模型,從Ajax調用返回:

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

我有一個幾乎類似的情況,我的對象是JavaScript類的實例。這些類在沒有Knockout的情況下被定義,我想修改它們來使用observables。

我創建了一個小型助手,將常規對象轉換爲可觀察對象。您可以指定可觀察的字段,或者將它們設置在對象(原型)中。 (我想自動這樣做的,但我不能確定哪些領域是安全的轉換,哪一個不是。)

(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; 
    }; 
})(); 

您可以使用類或普通的對象使用它。

// 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']);