Отображение knockoutjs из / в объект POCO - PullRequest
12 голосов
/ 02 августа 2011

Есть ли способ сопоставления с / в POCO и наблюдаемые нокауты?

У меня есть класс Note:

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. Обратите внимание, что идентификатор не отображается, потому что он мне не нужен.

Пока все хорошо, я вижу заметки на экране, но как мне сохранить заметки на сервере?

Я попытался преобразовать заметку (я сохраняю только новую заметку, а не всю коллекцию) в JSON и отправить ее на мой контроллер, но я не знаю, как получить доступ к заметке в контроллере. Я попробовал:

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

но не работает. Я хочу что-то вроде:

public string AddNote(Note note) {}

(Кстати, как лучше вернуть метод, который просто сохраняет данные в БД? Void?)

Итак, как мне это сделать? Я попробовал подключить плагин knockout.mapping, но он довольно запутанный, и у меня он не работает.

Спасибо.

1 Ответ

24 голосов
/ 02 августа 2011

Механизм связывания модели 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), а не только массив параметров.

Кроме того, поскольку связующие модели просматривают опубликованные значения несколькими способами. Мне посчастливилось опубликовать объекты JSON без указания имени параметра ActionMethod: вместо:

    { 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 будет в порядке, но если он немного более критичен, вы можете захотеть передать логическое значение (по крайней мере), чтобы ваш клиент знал, что ему, возможно, придется повторить попытку (особенно, если есть исключение параллелизма) .

Если вам действительно нужно сообщить клиенту, что произошло в базе данных, вы можете отправиться в мир настраиваемой обработки ошибок и , перехват исключений .

Кроме того, если вам нужно отобразить очень конкретную информацию для вашего пользователя в зависимости от успешной / неудачной фиксации базы данных, то вы можете посмотреть на создание пользовательских ActionResults , которые перенаправляют на определенные представления на основе того, что произошло в транзакция базы данных.

Наконец, что касается получения данных с сервера и использования Knockout ...

  1. снова плагин сопоставления будет работать, если имена ваших свойств совпадают или вы создаете немного более явное сопоставление
  2. Мой собственный трюк с моими объектами JS ниже. Созданная мной функция initialize должна использоваться для повторного использования во всех ваших объектах, так как она просто говорит «если имена свойств совпадают (после того, как они находятся в нижнем регистре), либо установите их, вызвав функцию (совместимость с нокаутом), либо просто присвойте значение. 1048 *

    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];
                        }
                    }
                }
            }
    };
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...