2011-08-02 64 views
12

有沒有一種方法可以映射POCO和knockoutjs的可觀察性?從/到POCO對象的knockoutjs映射

我有一個註釋類:

public class Note 
{ 
    public int ID { get; set; } 
    public string Date { get; set; } 
    public string Content { get; set; } 
    public string Category { get; set; } 
    public string Background { get; set; } 
    public string Color { get; set; } 
} 

,這是我的javascript:

$(function() { 
    ko.applyBindings(new viewModel()); 
}); 

function note(date, content, category, color, background) { 
    this.date = date; 
    this.content = content; 
    this.category = category; 
    this.color = color; 
    this.background = background; 
} 

function viewModel() { 
    this.notes = ko.observableArray([]); 
    this.newNoteContent = ko.observable(); 

    this.save = function (note) { 
     $.ajax({ 
       url: '@Url.Action("AddNote")', 
       data: ko.toJSON({ nota: note }), 
       type: "post", 
       contentType: "json", 
       success: function(result) { } 

      }); 
    } 

    var self = this; 
    $.ajax({ 
     url: '@Url.Action("GetNotes")', 
     type: "get", 
     contentType: "json", 
     async: false, 
     success: function (data) { 
      var mappedNotes = $.map(data, function (item) { 
       return new note(item.Date, item.Content, item.Category, item.Color, item.Background); 
      }); 
      self.notes(mappedNotes); 
     } 
    }); 
} 

忽視的事實是,保存功能不使用(這裏簡化代碼)。

所以,當我加載頁面時,我打電話給服務器,我檢索了一個Note對象列表,並將它映射爲javascript。注意ID是如何映射的,因爲我不認爲它在我看來。

到目前爲止,我看到屏幕上的筆記,但我如何將筆記保存回服務器?

我試圖將筆記(即保存新筆記而不是整個集合)轉換爲JSON併發送給我的控制器,但我不知道如何訪問控制器中的筆記。我試過了:

public string AddNote(string date, string content, string category, string background, string color) 
    { 
     // TODO 
    } 

但是不起作用。我想有這樣的:

public string AddNote(Note note) {} 

(順便說一句,什麼是對,只是節省DB數據的方法最好的回報無效?)

那麼,如何做到這一點?我試過knockout.mapping插件,但它很混亂,我不明白它爲我工作。

謝謝。

回答

24

ASP.NET MVC的模型聯編程序將查找區分大小寫的屬性。您需要將您的JSON對象傳遞迴服務器,使其屬性名稱與您的poco對象匹配。

我通常做1 2的東西:

  1. 讓我的JavaScript對象的屬性名稱資本(以JS這樣,我知道,這個對象會在某個時刻是DTO服務器)

    function Note(date, content, category, color, background) { 
        this.Date = date; 
        this.Content = content; 
        this.Category = category; 
        this.Color = color; 
        this.Background = background; 
    }; 
    
  2. 在我的AJAX調用我只是將創建一個匿名對象傳遞迴服務器(注意,這並不需要ko.toJSON):

    $.ajax({ 
         url: '@Url.Action("AddNote")', 
         data: JSON.stringify({ note: { 
           Date: note.date, 
           Content: note.content, 
           Category: note.category, 
           Color: note.color, 
           Background: note.background 
           } 
          }), 
         type: "post", 
         contentType: "application/json; charset=utf-8", 
         success: function(result) { } 
    }); 
    

    (注意不同的contentType參數以及)

你想使你的ActionMethod參加一個(Note note),而不僅僅是參數數組。

此外,因爲模型綁定者以幾種不同的方式查看發佈的值。我有運氣在張貼出指定2.actionmethod屬性名稱JSON對象: 代替:

{ note: { 
     Date: note.date, 
     Content: note.content, 
     Category: note.category, 
     Color: note.color, 
     Background: note.background 
     } 
    } 

只是做:

{ 
     Date: note.date, 
     Content: note.content, 
     Category: note.category, 
     Color: note.color, 
     Background: note.background 
    } 

(但是也會冒險與數組結合集合和複雜類型等等)

就db調用方法返回的'最佳'簽名而言,我們通常更喜歡看到布爾值,但這也取決於您的需求。顯然,如果數據不重要,void將會很好,但如果它更重要一點,您可能需要傳遞一個布爾值(至少)以讓您的客戶端知道它可能需要重試(特別是如果存在併發異常) 。

如果您確實需要讓您的客戶知道數據庫中發生了什麼,您可以進入custom error handlingexception catching的世界。另外,如果您需要根據成功/不成功的數據庫提交將非常特定的信息顯示回給用戶,則可以根據數據庫事務中發生的事情,創建custom ActionResults重定向到某些視圖。

最後,儘可能從服務器獲取數據備份和採用淘汰賽......

  1. 再次映射插件會工作,如果你的屬性名稱相同的情況下,或創建一個稍微更明確的映射
  2. 我自己的詭計與我的JS對象如下。初始化函數是我創建的,應該可以在所有對象中重用,因爲它只是說「如果屬性名稱匹配(在小寫後),或者通過調用函數(敲除兼容)來設置它們,或者只是賦值:

    function Note(values){ //values are what just came back from the server 
        this.date; 
        this.content; 
        this.category; 
        this.color; 
        this.background; 
    
        initialize(values); //call the prototyped function at the bottom of the constructor 
    }; 
    
    Note.prototype.initialize = function(values){ 
        var entity = this; //so we don't get confused 
         var prop = ''; 
         if (values) { 
          for (prop in values) { 
           if (values.hasOwnProperty(prop.toLowerCase()) && entity.hasOwnProperty(prop.toLowerCase())) { 
            //the setter should have the same name as the property on the values object 
    
            if (typeof (entity[prop]) === 'function') { 
             entity[prop](values[prop]); // we are assuming that the setter only takes one param like a Knockout observable() 
            } else {// if its not a function, then we will just set the value and overwrite whatever it was previously 
             entity[prop] = values[prop]; 
            } 
           } 
          } 
         } 
    }; 
    
+1

真棒史詩回答它的工作完美,但是:你能解釋一下我的最後一段。如何爲Im做此處從服務器加載手動映射或我要嘗試映射插件??? –

+1

是的,對於偉大的答案+1。這是非常清楚的例子。 –

+0

哇 - 偉大的工作。 –