2010-12-01 4 views
17

Мне интересно, как я могу сделать определенные поля наблюдаемыми в knockout.js, которые я получаю от вызова 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 за большой вопрос: Нокаут + Ajax МЕТОДИЧЕСКИЕ –

ответ

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, вы можете перевести на JavaScript, нажав «Try CoffeeScript» на связанном сайте. И если вы не используете RequireJS, просто возьмите соответствующие функции из моего модуля, не обернув их в define.

+1

я не понимаю, почему вы думаете, размещение CoffeeScript было бы полезно? – badsyntax

+0

lol ya, еще в марте 2011 года это было то, что нужно сделать: P – Domenic

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, и я хотел их модифицировать, чтобы вместо этого использовать наблюдаемые.

Я создал небольшой помощник для преобразования обычных объектов в наблюдаемые объекты. Вы можете либо указать наблюдаемые поля, либо задать их в объекте (прототипе). (Я думал, что делать это автоматически, но я не мог определить, какое поле было безопасно для преобразования и который один не был.)

(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']); 
Смежные вопросы