2011-08-02 67 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

哇 - 伟大的工作。 –