【问题标题】:Render a View of Backbone Model returns undefined渲染主干模型的视图返回未定义
【发布时间】:2013-12-18 07:11:17
【问题描述】:

假设我有一个这样的 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, 初始化:函数(){ _.bindAll(this, 'render'); }, //这里我传递了我想要渲染的模板(html源代码)。 渲染:函数(模板){ var html = render(模板, this.model.toJSON() ); 应用程序.$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 时,我唯一拥有的是: “未捕获的 TypeError:无法调用未定义的方法 'toJSON'”

但是当我把它放在开发者控制台上时:

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

我的视图渲染正确。

为什么我的视图没有在加载时呈现,只有在我将代码放在开发者控制台上时才呈现?

如何在路由器 url 的视图上渲染我的模型? 为什么我在开发者控制台加载的 html 上有 undefined?

----编辑---

好吧,

我想我明白了。也许我正在产生一个不一定有问题的事情的问题。

现在我的模型是这样的:

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

我收到未定义的错误:

未捕获的类型错误:无法调用未定义的方法 'get'

知道如何解决这个问题吗?

我正在尝试自己解决这个问题。我不想看起来像我要求开发我的解决方案。

提前致谢。

【问题讨论】:

    标签: javascript backbone.js backbone-views backbone.js-collections backbone-model


    【解决方案1】:

    在您的代码中,您已将 collection 创建为:

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

    如果你想创建一个collection,你需要扩展Backbone.Collection而不是Backbone.Model

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

    【讨论】:

    【解决方案2】:

    这有点难以阅读,但快速浏览一下:您的 App.texts = 位于 Collection 的 parse() 函数中。因此,一旦集合上的 .fetch() 被执行,它就会被调用......直到那时,你的 App.texts 是未定义的!

    如果在创建 TemplateView 时 App.texts 未定义,则视图的模型实际上是未定义的,因此,在渲染中,当您使用的模板引擎执行 toJSON() 时,它会说它有一个未定义的值...

    可能还有其他问题,但这个是最明显的。这是一个快速而肮脏的修复:一旦 fetch() 完成,您的集合将触发重置事件。这是您进行渲染的提示。所以,你可以做的,不是将模型传递给视图,而是传递集合:

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

    现在,在 View 的初始化中,您可以执行以下操作:

     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);在路由器的索引函数中。

    使代码更明显的一种方法是直接在应用程序的 init 中初始化 App.texts 和 App.vias。如果您确实需要在 AppTemplates 的 fetch() 的解析中侧加载它们,请为您的 AppTemplatesCollection 提供对它们的引用。不同之处在于您可以绑定到 App.vias 集合中的事件('add'、'remove'、'reset')或 App.texts 模型('change')。

    我注意到的另一件事是,您有一个 App.TemplateModel 的集合,但您仍在创建一个 App.texts,您将获取的结果放入您自己的 App.TemplateModel 实例中?这似乎不对,也许你有这样做的理由,但在最一般的情况下,集合应该处理模型的创建,尤其是在获取之后!

    parse() 方法的常见用例是侧载数据(其他模型/集合)、更改格式(从 XML 到 JS 可以理解的格式)或删除无用的键(例如 user: {id : ..., name: ... },您将返回 response.user 以便 Backbone 可以直接使用正确的哈希)。你在这里所做的似乎不符合这种模式,所以也许这值得担心?

    【讨论】:

    • 只是为了澄清,你让我睁开了眼睛。我做错了。我已经从模型和集合中删除了获取,当我调用渲染时,我尝试获取传递的集合,并在成功的情况下渲染我的视图。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 2016-01-23
    • 1970-01-01
    相关资源
    最近更新 更多