Backbone.js: как вызывать методы коллекции внутри литерала объекта

У меня есть следующий код backbone.js. Я использую литерал объекта для организации своего кода, поэтому у меня возник вопрос о том, как лучше всего продолжить. Приложение (в упрощенной форме ниже) имеет панель управления (которая может быть отображена или скрыта), которая используется для добавления новых категорий в коллекцию. (Вопрос следует)

(function($){

    // ============================= NAMESPACE ========================================
var categoryManager = categoryManager || {};

    // ============================= APPLICATION =================================================

categoryManager.app = categoryManager.app || {

    /* Used to Initialise application*/
    init: function(){
        //this.addView = new this.addCategoryView({el: $("#add-new-category")})
        //this.collection = new this.categoryCollection();
        new this.addCategoryView({el: $("#add-new-category")})
        new this.categoryCollection();
    },

    categoryModel:  Backbone.Model.extend({
        name: null
    }),

    addCategoryView: Backbone.View.extend({

        events: {
            "click #add-new-category-button.add" : "showPanel",
            "click #add-new-category-button.cancel" : "hidePanel",
            "click #new-category-save-category" : "addCategory"
        },
        showPanel: function() {
            $('#add-new-category-button').toggleClass('add').toggleClass('cancel');
            $('#add-new-category-panel').slideDown('fast');
        },
        hidePanel: function() {
            $('#add-new-category-button').toggleClass('add').toggleClass('cancel');
            $('#add-new-category-panel').stop().slideUp('fast');
        },
        addCategory: function() {
            //categoryManager.app.collection.create({
            categoryManager.app.categoryCollection.create({ // My Problem is with this line
                name: $('#name').val()
            });
        }
    }),

    categoryCollection: Backbone.Collection.extend({
        model: this.categoryModel,
        initialize: function () {

        }
    })
}
    // ============================= END APPLICATION =============================================

    /* init Backbone */

    categoryManager.app.init();

})(jQuery);

Теперь очевидно, что проблема с вышеизложенным заключается в том, что при вызове функции addCategory пытается вызвать функцию для объекта, который не инициализирован. Я обошел проблему (см. Закомментированный код), вызвав функцию вместо для объекта, экземпляр которого создается в функции init. У меня вопрос - правильно ли это? Я чувствую запах кода. Я считаю, что содержание литерала объекта не должно полагаться на создаваемый объект, чтобы быть действительным. функция addCategory в этом случае не будет работать, если сначала функция init не была вызвана в родительском элементе. Есть ли здесь другой шаблон, который мне следует использовать?

Как еще я мог бы передать содержимое формы создания новой категории в коллекцию, чтобы ее добавить (я использую create, потому что хочу автоматически проверять / создавать / сохранять модель, и это кажется самым простым делом ). Я новичок на дне с позвоночником (это мой `` привет, мир '')

Спасибо


person calumbrodie    schedule 14.08.2011    source источник


Ответы (2)


Я думаю, что главная проблема в том, что вы относитесь к categoryCollection как к объекту. На самом деле это не объект, а функция-конструктор. Итак, сначала вам нужно создать экземпляр, как вы обнаружили.

Затем addCategoryView нужен способ ссылки на экземпляр. Похоже, у вас нет модели, связанной с представлением. Я бы предложил создать модель и сохранить экземпляр categoryCollection как свойство модели. Примерно так (предупреждение, непроверенный код):

var model = new BackBone.Model({
    categories: new categoryManager.app.CategoryCollection()
});

var view = new categoryManager.app.AddCategoryView({
    el: $("#add-new-category"),
    model: model
});

Тогда вы можете просто использовать this.model.categories изнутри addCategoryView.

Кроме того, обычным соглашением Javascript является использование заглавных букв в именах конструкторов. Вызов конструктора CategoryCollection может сделать код немного понятнее.

person minimalis    schedule 15.08.2011
comment
Насколько я понимаю, коллекции содержат модели, а не наоборот. Нормально ли (не нормально, как в «будет работать», но нормально, как в «правильное действие»), чтобы модель содержала коллекцию, которая сама содержит модели (как моя коллекция)? Спасибо за вклад. - person calumbrodie; 16.08.2011
comment
Я думаю, что это нормально, и это помогает с инкапсуляцией - общая идея архитектур типа MVC заключается в том, что модель содержит все данные, которые представление необходимо для рендеринга. - person minimalis; 16.08.2011
comment
Спасибо - вы увидите, что я назначил за это вознаграждение, поэтому я оставлю его открытым, чтобы посмотреть, смогу ли я получить еще несколько ответов. Мне не удалось заставить ваш код работать (первая строка), поэтому я сделал это вместо этого. AddViewModel: Backbone.Model.extend ({инициализировать: функцию () {this.categories = new categoryManager.app.CategoryCollection;}, Categories: null}). Если я опущу функцию инициализации, произойдет сбой - я не смогу напрямую назначить конструктор свойству «категории». - person calumbrodie; 16.08.2011
comment
Пример кода был не совсем правильным - надеюсь, теперь он лучше - person minimalis; 16.08.2011
comment
Нет - я получаю следующую ошибку, если пытаюсь напрямую инициализировать коллекцию. 'categoryManager.app не определен'. Если я инициализирую коллекцию в методе инициализации модели, она работает должным образом. - person calumbrodie; 16.08.2011
comment
Я долго работал над этим, и теперь мне интересно - зачем мне передавать коллекцию в модель перед добавлением в представление. Я могу просто добавить коллекцию прямо в представление, не так ли? - person calumbrodie; 17.08.2011
comment
По сути, разделение забот. Лучше разделить данные, поместив их в модель, а не устанавливать значения непосредственно в представлении. В будущем вы можете получить большую модель с большим количеством данных - с ней будет легче работать, если вы будете держать ее отдельно от представления, а не смешивать ее со всеми событиями и действиями, которые являются частью представления. - person minimalis; 18.08.2011
comment
Но мои модели (которые содержат данные) являются частью коллекции, которая сама передается в представление - проблемы по-прежнему разделены. Наличие модели, которая будет иметь только одно свойство (коллекцию), кажется мне излишним - возможно, я что-то упускаю. - person calumbrodie; 18.08.2011
comment
Что ж, это оба подходящих подхода. Если вы уверены, что единственные данные, которые потребуются вашему представлению, - это коллекция, вы можете использовать коллекцию как модель. Но, на мой взгляд, одна из сильных сторон базовых представлений - возможность многократного использования. Предположим, вам нужно несколько CategoryView на одной странице, и вы хотите, чтобы каждый из них отображал разные заголовки и, возможно, вел себя немного по-разному, например, при выборе категории. Затем вам потребуются дополнительные свойства модели, чтобы управлять этим поведением - использование отдельной модели дает вам такую ​​гибкость. - person minimalis; 19.08.2011
comment
Я буду держать это в уме - я уверен, что столкнусь с такой ситуацией. Спасибо за вашу помощь. - person calumbrodie; 20.08.2011

Перед созданием нового экземпляра модели необходимо инициализировать коллекцию.

addCategory: function() {
    var collection = categoryManager.app.categoryCollection;

    !collection.create && (collection = new collection);
    collection.create({
        name: $('#name').val()
    });
}
person ant_Ti    schedule 16.08.2011
comment
Привет. Я это уже знаю (см. Закомментированные строки в моем коде). Какова цель третьей строки кода в вашем примере? - person calumbrodie; 16.08.2011
comment
!collection.create убедитесь, что collection не инициализирован, и если нет, он инициализирует коллекцию и присваивает ее collection переменной - person ant_Ti; 16.08.2011
comment
!collection.create && (collection = new collection); равно if(!collection.create) { collection = new collection } - person ant_Ti; 16.08.2011