Реализация составного шаблона с использованием MVC / Backbone.js - PullRequest
10 голосов
/ 17 января 2012

Мое веб-приложение имеет составную структуру, т. Е. Каждая коллекция категорий может содержать смесь отдельных элементов и других категорий в качестве строк / узлов / дочерних элементов (не уверен в правильной терминологии здесь).На самом деле, это немного проще, чем то, что каждая коллекция представлена ​​моделью Category, поэтому, по сути, каждая коллекция Category имеет как модели Item, так и модели Category в качестве своих дочерних элементов.

В целом это рекомендуетсяспособ реализовать эту структуру с помощью MVC?Более конкретно, в Backbone.js возможно ли для коллекции иметь фабрику моделей (принимая json и вычисляя, какую модель генерировать на основе структуры json) вместо свойства статической модели?

Ответы [ 4 ]

5 голосов
/ 20 января 2012

Я предполагаю, что вы получаете список категорий / элементов в JSON, который выглядит примерно так ...

{
    'id': 1,
    'name': 'My 1st Category',
    'children': [
        {
            'id': 2,
            'name': 'My 2nd Category',
            'children': []
        },
        {
            'id': 1,
            'name': 'An Item',
            'price': 109.99
        }
    ]
}

Backbone.js не имеет ничего из коробки, который поддерживает несколькомодели в коллекции, но она также не имеет каких-либо ограничений на типы моделей, которые вы помещаете в коллекцию.

Указание типа модели в определении коллекции делает только одно, это позволяет Backbone знать, какая модельтип для создания, если вы передаете сырой JSON в коллекцию вместо объекта Backbone.Model.Если вы добавите модель Item в коллекцию, которая уже содержит несколько моделей Category, у Backbone не возникнет проблем с ее вставкой в ​​список моделей;он не выполняет никакой проверки типов.

Итак, помня об этом, вы можете использовать практически все, что предлагает коллекция, за исключением передачи в необработанном виде JSON;вам придется справиться с этим самостоятельно.Таким образом, вы можете либо заранее построить свои модели, превратив их в Backbone.Model объекты, либо создать что-то, что будет выполнять анализ для вас.

Для второго варианта, парсера, я бы предложилпередавая специальную переменную в коллекцию, содержащую ваш необработанный JSON, затем обрабатывая это в вашей функции initializeВот пример:

var CategoryCollection = Backbone.Collection.extend({
    initialize: function(m, models) {
        _.each(models, function(model) {
            var modelObject = null;
            if (model.price !== undefined) {
                modelObject = new Item(model);
            } else {
                modelObject = new Category(model);
            }

            this.add(modelObject);
        }, this);
    }
});

Так что это немного странно, но вы определяете тип модели на основе того, имеет ли оно определенное поле (price в моем примере), создаете объект модели, затемдобавьте это в коллекцию.

Затем вы бы назвали это следующим образом:

var myCollection = new CategoryCollection([], myJSON);

Обратите внимание, что вы должны передать пустой массив в качестве первого аргумента, так как обычно вы передаетенабор моделей для коллекции.

Позже, используя коллекцию, вы можете определить, имеете ли вы дело с Item или Category, используя простой instanceof чек:

_.each(myCollection.models, function(model) {
    if (model instanceof Item) {
        console.log("It's an Item! Price: ", model.get("price"));
    } else {
        console.log("It's a Category!");
    }
});
1 голос
/ 26 января 2012

Да, вы можете использовать шаблон Factory Method для создания модели в коллекциях магистрали. Предполагая структуру данных, предложенную в ответе @ kpeel , вы можете определить

// Factory method
var CategoryOrItemFactory = function(data, options) {
    if (data.children) {
        return new Category(data, options);
    } else {
        return new Item(data, options);
    }
};

// Model definitions
var Item = Backbone.Model.extend();

var Category = Backbone.Model.extend({
    initialize: function() {
        this.children = new Children(this.get("children"));
    }
});

var Children = Backbone.Collection.extend({
    model: CategoryOrItemFactory
});

Затем вы создадите свой корневой элемент (категорию) и создадите полную структуру данных:

// create the root item
var rootItem = new Category(rawData);

Доступ к дочерним элементам категории: children свойство, например,

  rootItem.children.get(2).get("name");

Вот jsFiddle с кодом выше для игры.

1 голос
/ 25 января 2012

Это довольно просто достигается перезаписью встроенных общедоступных методов parse и toJSON , используемых внутренне магистралью при извлечении и сохранении данных модели.

Во-первых, когда вы извлекаете данныеМодель из базы данных вы должны переписать метод модели parse для создания моделей, представляющих заданные элементы из вашего примера.

Затем при сохранении метод toJSON используется для сериализации данных обратно на то, что может серверпонять - там вы бы просто вызвали метод toJSON в модели каждого элемента, чтобы сериализовать его в формат, который распознает бэкэнд.Если вы посмотрите на код для Backbone.sync, вы увидите, что модель всегда сериализуется с использованием toJSON, если не передаются пользовательские данные.

Дайте мне знать, если вам нужна более подробная информация, хотя я считаю, что вам следуетв состоянии забрать его отсюда!

1 голос
/ 19 января 2012

Да, вы можете.Я делал это раньше.Я думаю, что эти ссылки могут помочь вам: http://documentcloud.github.com/backbone/#Collection-model

Вот один из основных сценариев, которые я использовал для своего проекта: https://gist.github.com/b65893e0c2e3c46d3dc1

...