在主干的一个视图中使用两个模型时出现问题

Trouble using two models in one view for backbone

本文关键字:两个 模型 问题 视图 一个      更新时间:2023-09-26

我在backbone.js中尝试使用具有相同视图的两个模型时遇到了问题。不知何故,在触发触发器开始渲染函数之前,视图已经被渲染。

以下是型号:

APP.Models.FamilyPreferences = Backbone.Model.extend({
    initialize: function( attributes, options ) {
        _.bindAll(this, 'success_handler', 'populate');
        this.url = options.url;
    },
    populate: function(){
        this.fetch({success: this.success_handler});
    },
    success_handler: function(){
        this.trigger("change");
    }
});
APP.Models.Preferences = Backbone.Model.extend({
    initialize: function( attributes, options ) {
        _.bindAll(this, 'success_handler', 'error_handler', 'populate');
        this.url = options.url;
    },
    populate: function(){
        this.fetch({success: this.success_handler, error:this.error_handler}); 
    },
    success_handler: function(){
        this.exists = true;
        this.trigger("change");
    },
    error_handler: function(){
        this.exists = false;
        this.trigger("change");
    }
});

以下是视图中的相关代码:

APP.Views.PreferencesFormView = Backbone.View.extend({
templates: [{name:"preferences_template", file_path:"preferences_form.html"}],
initialize: function(options){
    _.bindAll(this, 'render', 'renderPrereq');
    var family_url = "services/family/" + options.family_id;
    var preferences_url = "services/preferences/familyID/" + options.family_id;
    var ctx = this;
    this.alreadyRendered = false;
    this.modelsCurrentlyLoaded = [];
    this.models = {};
    this.models.family = new APP.Models.FamilyPreferences({}, {url: family_url});
    this.models.family.on('change', function(){ctx.renderPrereq("family");});
    this.models.family.populate();
    this.models.preferences = new APP.Models.Preferences({}, {url:preferences_url});
    this.models.preferences.on('change', function() {ctx.renderPrereq("preferences");});
    this.models.preferences.populate();
},
renderPrereq: function(newmodel){
    var inside = ($.inArray(newmodel, this.modelsCurrentlyLoaded)>-1) ? true : false;
    if (!(inside)){this.modelsCurrentlyLoaded.push(newmodel);}
    var total = Object.keys(this.models).length;
    if(this.modelsCurrentlyLoaded.length == total && !this.alreadyRendered){
        this.alreadyRendered = true;
        this.render();
    }
},
render: function(){
    var family_data = {
        id: this.models.family.attributes.id,
        familyGroup: this.models.family.attributes.groupNum,
        familyId: this.models.family.attributes.familyId,
        probandDob: this.models.family.attributes.childDob,
    }
    var preferences_data = {
        mother: this.models.preferences.attributes[0],
        father: this.models.preferences.attributes[1],
        exists: this.models.preferences.exists
    }
    this.$el.html(this.compiledTemplates.preferences_template(family_data));
    //bunch of javascript making the page work
}
});

模板正在通过其他地方的另一个js函数加载,据我所知,该函数工作正常。不知怎的,在成功处理程序之前调用了render函数。我不知道怎么做。它唯一的副作用是Preferences模型没有得到exists属性,因此是未定义的,这会导致各种问题。此外,options.family_id设置正确。如有任何帮助,我们将不胜感激。提前谢谢。

编辑:它似乎也会渲染Prereq多达六次,我也不知道。

JSON-系列模型

{
    "id": 1,
    "familyId": "family01",
    "collectionDate": "2013-01-01",
    "childDob": "2001-05-‌​06",
    "groupNum": "Two",
    "probands": [],
    "mother": null,
    "father": null,
    "siblings": []
}

JSON-首选项模型的第一部分

[{
    "main": "illness-only",
    "obesity": "No",
    "bloodPressure": "No",
    "diabetes": "No",
    "hea‌​rt": "No",
    "alzheimers": "No",
    "parkinsons": "No",
    "mentalHealth": "No",
    "breastOvarianCa‌​ncer": "No",
    "prostateTesticularCancer": "No",
    "otherCancer": "No",
    "childSickleCell": "‌​No",
    "childCysticFibrosis": "No",
    "childMuscularDystrophy": "No",
    "childAutism": "No"
}, 
{
    "main":"more-questions",
    "obesity":"No",
    "bloodPressure":"Yes",
    "diabetes":"No",
    "heart":"Unsure",
    "alzheimers":"No",
    "parkinsons":"Yes",
    "mentalHealth":"No",
    "breastOvarianCancer":"No",
    "prostateTesticularCancer":"No",
    "otherCancer":"No",
    "childSickleCell":"No",
    "childCysticFibrosis":"No",
    "childMuscularDystrophy":"No",
    "childAutism":"No"}]

标头

Accept: application / json, text / javascript, /; q=0.01
Accept-Encoding:gzip,deflate,sdch 
Accept-Language:en-US,en;q=0.8  
Cache-Control:no-cache Connection:keep-alive     
Cookie:csrftoken=bDIpdvAPBdWF6dZe9BkpsFSF4wiGl2qX 
Host:localhost:8080 Pragma:no-cache  Referer:localhost:8080/CSER / index.html 
User - Agent: Mozilla / 5.0(Macintosh; Intel Mac OS X 10_8_3) AppleWebKit /
537.36(KHTML, like Gecko) Chrome / 27.0.1453.110 Safari / 537.36 X - Requested - With: XMLHttpRequest

尝试此代码

APP.Models.FamilyPreferences = Backbone.Model.extend({
    initialize: function (attributes, options) {
        _.bindAll(this, 'success_handler', 'populate');
        this.url = options.url;
    },
    populate: function () {
        this.fetch();
    },
    // This is not required
    // It will automatically render it as we are listening to the sync event
    success_handler: function () {
        // Not required 
        // sync event will take care of it
    }
});
APP.Models.Preferences = Backbone.Model.extend({
    initialize: function (attributes, options) {
        _.bindAll(this, 'success_handler', 'error_handler', 'populate');
        this.url = options.url;
    },
    populate: function () {
        this.fetch({
            success: this.success_handler,
            error: this.error_handler
        });
    },
    success_handler: function () {
        this.exists = true;
        // Not required 
        // sync event will take care of it
    },
    error_handler: function () {
       // Do something else
    }
});
APP.Views.PreferencesFormView = Backbone.View.extend({
    templates: [{
        name: "preferences_template",
        file_path: "preferences_form.html"
    }],
    initialize: function (options) {
        _.bindAll(this, 'render', 'renderPrereq');
        var family_url = "services/family/" + options.family_id;
        var preferences_url = "services/preferences/familyID/" + options.family_id;
        var ctx = this;
        this.alreadyRendered = false;
        this.modelsCurrentlyLoaded = [];
        this.models = {};
        // Family Model
        this.models.family = new APP.Models.FamilyPreferences({}, {
            url: family_url
        });
        this.listenTo( this.models.family, 'change', function () {
            ctx.renderPrereq("family");
        });
        // This will take care of rendering it on Sync with server
        // No need to triggereing the event explicitly..
        this.listenTo( this.models.family, 'sync', function () {
            ctx.renderPrereq("family");
        });        
        this.models.family.populate();
        // Family Preference Model
        this.models.preferences = new APP.Models.Preferences({}, {
            url: preferences_url
        });
        this.listenTo( this.models.preferences, 'change', function () {
            ctx.renderPrereq("family");
        });
        // This will take care of rendering it on Sync with server
        // No need to triggereing the event explicitly..
        this.listenTo( this.models.preferences, 'sync', function () {
            ctx.renderPrereq("preferences");
        });  
        this.models.preferences.populate();
    },
    renderPrereq: function (newmodel) {
        var inside = ($.inArray(newmodel, this.modelsCurrentlyLoaded) > -1) ? true : false;
        if (!(inside)) {
            this.modelsCurrentlyLoaded.push(newmodel);
        }
        var total = Object.keys(this.models).length;
        if (this.modelsCurrentlyLoaded.length == total && !this.alreadyRendered) {
            this.alreadyRendered = true;
            this.render();
        }
    },
    render: function () {
        var family_data = this.models.family.toJSON());
        var preferences_data = {
            mother: this.models.preferences.attributes[0],
            father: this.models.preferences.attributes[1],
            exists: this.models.preferences.get('exists') ? this.models.preferences.get('exists') : false
        }
        this.$el.html(this.compiledTemplates.preferences_template(family_data);
        //bunch of javascript making the page work
    }
});

看起来问题在于它的构造方式。。。我不认为render是在success_handler之前调用的。

如果你看看renderPrereq方法,两个关于变化的模型会在成功时调用这个方法。

但是fetch方法是异步的。因此,您永远不知道将首先调用哪个处理程序。

以及当模型上的change被触发时。这将调用renderPrereq方法内部的render方法。