2010-12-01 9 views
17

Ich frage mich, wie ich bestimmte Felder Observablen in knockout.js, die ich von einem Ajax-Aufruf erhalten, ohne das gesamte Objekt in meinem Viewmodel definieren müssen. Ist das möglich? Hier ist, was ich bisher:machen Felder beobachtbar nach Ajax Abruf in 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 für große Frage: Knockout + Ajax Howto –

Antwort

3

ich dieses Problem behoben, fand heraus, dass es besser war, die beobachtbaren Felder auf meine Aufgabe zu erklären, bevor es meiner Ansicht nach wie

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

hier Einstellung ist mein CoffeeScriptRequireJS module zum Umwandeln, was ich "view-Daten" (Server-derived JSON-Werte) zu KO Viewmodels nennen:

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 

Verwendungsbeispiel:

Natürlich, wenn Sie CoffeeScript nicht tun, können Sie in JavaScript übersetzen, indem Sie auf der verlinkten Seite auf "Try CoffeeScript" klicken. Und wenn Sie RequireJS nicht verwenden, nehmen Sie einfach die relevanten Funktionen von meinem Modul, ohne sie in define zu verpacken.

+1

Ich verstehe nicht, warum Sie denken, Coffeescript Posting wäre hilfreich? – badsyntax

+0

lol ya, im März 2011 war das das Richtige: P – Domenic

8

Mit the mapping plugin for Knockout Sie der Ansicht Modell aus einem einfachen Javascript-Objekt festlegen können, wie aus einem Ajax-Aufruf zurückgegeben:

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

Ich hatte eine fast ähnliche Situation, wo meine Objekte Instanzen von Javascript-Klassen sind. Die Klassen sind ohne Knockout definiert und ich wollte sie modifizieren, um stattdessen Observables zu verwenden.

Ich habe einen kleinen Helfer erstellt, um reguläre Objekte in beobachtbare Objekte umzuwandeln. Sie können entweder die beobachtbaren Felder angeben oder sie im Objekt (Prototyp) festlegen. (Ich dachte, dies automatisch tun, aber ich konnte nicht bestimmen, welches Feld sicher war zu konvertieren und welches nicht.)

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

Sie es mit Klassen verwenden können, oder mit einfachen Objekten.

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