Render a View of Backbone Model возвращает неопределенное значение

Допустим, у меня есть такой JSON:

Пример JSON, мой json проверен на jsonlint и работает.

json_object = {
"texts_model": {
"hello": "hola",
"icon_text": "Icon!"
},
"collection_vias": {
"text": "hola",
"icon_text": "Icon!"
}
};

Я сделал коллекцию, которая анализирует содержимое json и создает модель и коллекции из этого json.

App.TemplatesCollection = Backbone.Model.extend({

    model: App.TemplateModel,
    url: TEMPLATES_SERVICE,

    initialize: function(){
        this.fetch({
            success: (function () {
                console.log(' Success ');
            }),
            error:(function (e) {
                //console.log(' Error: ' + e);
            }),
            complete:(function (e) {
                console.log(' Fetch completado con exito. ');

            })
        });
    },

    //Here i generate all my models and collections.
    parse: function(response){

        App.texts = new App.TemplateModel(response.text_model);
        App.vias = new App.ViasCollection(response.collection_vias);
        return response;
    },

    //I was trying with the get function but i the only thing i got was undefined.
    plain_texts: function(){
        return( this.get('plain_texts') ) ;
    }

});

А вид такой:

App.TemplateView = Backbone.View.extend({ el: App.$main_content, initialize: function(){ _.bindAll(this, 'render'); }, //Здесь я передаю шаблон (html-источник), который хочу для рендеринга.рендеринг: функция(шаблон){ var html = рендеринг(шаблон, this.model.toJSON()); App.$main_content.html(html); вернуть это; } });

И мой start.js, где живут все объявления моих моделей и представлений:

//приложение Приложение = {

init: function(){
    console.log('Iniciando...');

    //variables y constantes
    App.$main_content       = $('#main-content-content');
    App.$main_header        = $('#main-header-content')
    App.$main_navigation    = $('#main-navigation-content');

    //data
    App.templates = new App.TemplatesCollection();

    //views
    App.templateView = new App.TemplateView({model: App.texts});

    //router
    App.router = new App.Router();


},

start: function(){
    //init
    App.init();

    //router
    Backbone.history.start();

}

}

И роутер:

//маршрутизатор App.Router = Backbone.Router.extend({

routes:{
    "" : "index",
    ":web" : "url"

},

index: function(){
    console.log("index");

    //Here i do not know what to do, i mean do i have to instiate the View each time i go to index? or only render?
    App.templateView = new App.TemplateView({model: App.texts});
    App.templateView.render("sections/login/form");
},

url: function(web){
    console.log(web);
}

});

//on document ready
$(function(){

    App.start();


});

Моя проблема в том, что когда html загружается, единственное, что у меня есть, это: «Uncaught TypeError: невозможно вызвать метод toJSON неопределенного»

Но когда я помещаю это в консоль разработчика:

App.templateView = new App.TemplateView({model: App.texts});
App.templateView.render("sections/login/form");

Мое представление отображается правильно.

Почему мое представление не отображается при загрузке, а только тогда, когда я помещаю свой код в консоль разработчика?

Как я могу отобразить свою модель в представлении на URL-адресе маршрутизатора? Почему у меня есть undefined в html, загруженном на консоль разработчика?

----РЕДАКТИРОВАТЬ---

Хорошо,

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

Теперь моя модель выглядит так:

App.TemplatesCollection = Backbone.Model.extend({

    model: App.TemplateModel,
    url: TEMPLATES_SERVICE,

    plain_texts: function(){
        return this.get('texts')  ;
    },
    initialize: function(){
        this.fetch();
    }

});

И вид:

App.TemplateView = Backbone.View.extend({
    el: App.$main_content,
    initialize: function(){

        console.log(this.collection);
        var ea = this.collection.get('texts');
        console.log(ea);
    },
    render: function(template){
        console.log(this.collection);
        return this;
    }
});

Теперь я вижу свою коллекцию внутри своего представления.

Но когда я пытаюсь сделать это, чтобы получить только текстовую версию в моем представлении:

    var ea = this.collection.get('texts');
    console.log(ea);

Я получаю ошибку неопределенного:

Uncaught TypeError: невозможно вызвать метод «получить» неопределенного

Любая идея о том, как я могу решить эту проблему?

Я пытаюсь решить это сам. Я не хочу выглядеть так, как будто я прошу разработать мое решение.

Заранее спасибо.


person DiegoKTC    schedule 02.12.2013    source источник


Ответы (2)


Это немного сложно читать, но с первого взгляда: ваш App.texts = находится в функции parse() вашей коллекции. В результате он вызывается после выполнения .fetch() для коллекции... до тех пор ваш App.texts не определен!

Если App.texts не определен при создании TemplateView, то модель представления фактически будет неопределенной, и поэтому при рендеринге, когда используемый вами механизм шаблонов выполняет toJSON(), он скажет, что имеет неопределенное значение. ...

Могут быть и другие проблемы, но эта самая вопиющая. Вот быстрое и грязное решение: после выполнения fetch() ваша коллекция вызовет событие сброса. Это ваша подсказка для выполнения рендеринга. Итак, что вы можете сделать, так это вместо передачи модели в представление вы можете вместо этого передать коллекцию:

 App.templateView = new App.TemplateView({collection: App.templates});

Теперь при инициализации вашего представления вы можете сделать что-то вроде:

 if(App.texts) {
   //Your collection has already fetched and already went through parse()
   this.model = App.texts;
   this.render("sections/login/form");
 } else {
   //Your collection hasn't done the fetch yet
   view = this;
   this.collection.one("reset", function(){
     view.model = App.texts;
     view.render("sections/login/form");
   });
 }

Если вы укажете коллекцию в качестве параметра конструкции представления, она будет сохранена в this.collection, как и в случае с моделью. Идея здесь состоит в том, чтобы использовать события, чтобы знать, когда выполнять рендеринг, а также позволить представлению сообщать вам, когда оно готово к рендерингу. Вы также можете сделать что-то в своей функции render(), чтобы проверить, определена ли модель!

Чтобы убедиться, что этот анализ верен, вы можете поместить console.log(App.texts); в вашей индексной функции в маршрутизаторе.

Один из способов сделать код немного более очевидным — это инициализировать ваши App.texts и App.vias непосредственно в файле init вашего приложения. И дайте ссылку на них в AppTemplatesCollection, если вам действительно нужно загрузить их в анализе fetch() AppTemplates. Разница заключается в том, что вы можете привязываться к событиям из коллекции App.vias («добавить», «удалить», «сбросить») или к модели App.texts («изменить»).

Еще одна вещь, которую я заметил, это то, что у вас есть коллекция App.TemplateModel, но вы все еще создаете App.texts, где вы помещаете результат выборки в свой собственный экземпляр App.TemplateModel? Это кажется неправильным, возможно, у вас есть причина для этого, но в самом общем случае коллекция должна обрабатывать создание моделей, особенно после выборки!

Обычный вариант использования метода parse() — загрузить данные (другие модели/коллекции), изменить формат (с XML на то, что может понять JS) или удалить бесполезные ключи (например, user: {id: .. ., name: ... }, вы вернете response.user, чтобы Backbone мог напрямую работать с правильным хэшем). То, что вы здесь делаете, кажется, выпадает из этого шаблона, так что, может быть, это повод для беспокойства?

person Enders    schedule 02.12.2013
comment
Просто чтобы уточнить, вы открыли мне глаза. Я делал вещи неправильно. Я удалил выборку из модели и коллекции, и когда я вызываю рендеринг, я пытаюсь получить переданную коллекцию, и в случае успеха я визуализирую свое представление. Спасибо. - person DiegoKTC; 02.12.2013

В вашем коде вы создали collection как:

App.TemplatesCollection = Backbone.Model.extend({
//rest of the code

Если вы хотите создать collection, вам нужно расширить Backbone.Collection, а не Backbone.Model.

App.TemplatesCollection = Backbone.Collection.extend({
//rest of the code
person Niranjan Borawake    schedule 02.12.2013
comment
Спасибо, я только что отрефакторил свой код. Я ошибался во многих вещах. Backbone сложно освоить в начале. Спасибо. - person DiegoKTC; 02.12.2013
comment
Это не так сложно. Для начала было бы неплохо (addyosmani.github.io/backbone-fundamentals) - person Niranjan Borawake; 02.12.2013