2011-08-02 9 views
12

Czy istnieje sposób na mapowanie z/do obserwowanego obiektu POCO i knockoutjs?Mapowanie knockoutjs z/do obiektu POCO

Mam klasy Uwaga:

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

i to jest mój 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); 
     } 
    }); 
} 

ignorować faktu, że funkcja oszczędzania nie jest używany (w celu uproszczenia kodu tutaj).

Tak więc, po załadowaniu strony nazywam serwer i pobieram listę obiektów Note i mapuję je w javascript. Zwróć uwagę, że identyfikator nie jest odwzorowany, ponieważ nie potrzebuję go w moim widoku.

Na razie dobrze widzę notatki na ekranie, ale jak mogę zapisać notatki z powrotem na serwer?

Próbowałem przekonwertować notatkę (Im zapisuję tylko nową notatkę, a nie całą kolekcję) na JSON i wysłać ją do kontrolera, ale nie wiem, jak uzyskać dostęp do notatki w kontrolerze. Próbowałem:

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

, ale nie działa. Chcę mieć coś takiego:

public string AddNote(Note note) {} 

(Btw, co jest najlepszym sposobem powrotu na które po prostu zapisać dane na DB unieważnić?)

tak, to jak to zrobić? Próbowałem wtyczki knockout.mapping, ale jest to dość dezorientujące i nie działa to dla mnie.

Dziękuję.

Odpowiedz

24

Spoiwo modelu ASP.NET MVC będzie szukać właściwości, w których rozróżniana jest wielkość liter. Musisz przekazać obiekt JSON z powrotem do serwera z nazwami właściwości pasującymi do twojego obiektu poco.

zwykle zrobić 1 z 2 rzeczy:

  1. Bądź mój kapitał nazwy właściwości obiektu JavaScript (w ten sposób w JS, wiem, że ten obiekt będzie w pewnym momencie być DTO na serwerze)

    function Note(date, content, category, color, background) { 
        this.Date = date; 
        this.Content = content; 
        this.Category = category; 
        this.Color = color; 
        this.Background = background; 
    }; 
    
  2. W moim wywołania AJAX będzie po prostu utworzyć anonimowy obiekt, aby przejść z powrotem do serwera (uwaga ta nie wymaga 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) { } 
    }); 
    

    (zwróć uwagę na inny parametr contentType również)

będziemy chcieli dokonać ActionMethod podjąć w (Note note) a nie tylko szereg parametrów.

Ponadto, ponieważ modelbinders przegląda zaksięgowane wartości na kilka różnych sposobów.Miałem szczęście Piszesz obiektów JSON z obecnie określenie ActionMethod nazwę parametru: zamiast:

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

prostu zrobić:

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

(ale to może się ryzykowny z tablicami wiązania do zbiorów i kompleksu type ... etc)

Jeśli chodzi o "Najlepszy" podpis dla zwrotu z metody, która wykonuje wywołanie bazy danych, zazwyczaj wolimy widzieć wartość logiczną, ale zależy to również od Twoich potrzeb. Oczywiście, jeśli są to trywialne dane, void będzie w porządku, ale jeśli jest nieco bardziej krytyczny, możesz przekazać wartość boolean (przynajmniej), aby poinformować klienta, że ​​może potrzebować ponownej próby (szczególnie, jeśli istnieje wyjątek współbieżności) .

Jeśli naprawdę chcesz poinformować klienta, co stało się w bazie danych, możesz wypróbować w świecie custom error handling i exception catching.

Ponadto, jeśli chcesz wyświetlać użytkownikowi bardzo szczegółowe informacje w zależności od udanego/niepomyślnego zatwierdzenia bazy danych, możesz spojrzeć na tworzenie custom ActionResults przekierowujących do niektórych widoków na podstawie tego, co się stało w transakcji bazy danych.

Wreszcie, jeśli chodzi o pobieranie danych z serwera i korzystania Knockout ...

  1. ponownie wtyczki mapowania będą działać, jeśli nazwy właściwości są takie same przypadek lub utworzyć nieco bardziej wyraźne odwzorowanie
  2. Moja sztuczka z moimi obiektami JS znajduje się poniżej. Funkcja initialize jest czymś, co stworzyłem i powinno być możliwe wielokrotne użycie we wszystkich twoich obiektach, ponieważ mówi "jeśli nazwy właściwości pasują (po tym, jak są małe), ustaw je, wywołując funkcję (nokaut kompatybilny) lub po prostu przypisz wartość:

    .
    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

Niesamowite zwrotna Epic działa idealnie ale: czy możesz wyjaśnić mi ostatni akapit a .. jak załadować z serwera Ręczne mapowanie jak tu robi Im albo muszę spróbować wtyczki mapowania?? –

+1

Tak, +1 za wspaniałą odpowiedź, jest bardzo wyraźny z doskonałymi przykładami –

+0

Wow - świetna robota. –