2
votes

I have an issue with requirejs and backbone. Well, I have two views (View1 and View2). I want to call View2.render() from View1 and View1.render() from View2. In general I want each view to depends to another.

My problem is that I cannot call View2.render(). I am getting the error message "cannot call method render of undefined"

If I remove the View1 dependency from View2 then it will work.

Does anyone know how can I amend the code so it could work without issues?

EDIT

View Name-->View2

define([
'Underscore',
'Backbone',
'Handlebar',
'views/view1'
], function (_, Backbone, Handlebars, View1) {
var View2 = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, "render");
    },
    tagName: 'div',
    el: '#rightPanel',
    events: {
        'change input#createNewCategory': 'createNewItem',
        'click #saveEdits': 'saveData',
        'click #clearEdits': 'render'
    },
    render: function () {
        //do something here
    },
    clear: function () {
        this.$el.empty();
    },
    createNewItem: function (e) {
      //so something here
    },
    saveData: function () {
        //This works Fine
        View1.render();
    }
});

return new View2;
});

View Name --> View1

define([
'Underscore',
'Backbone',
'Handlebar',
'views/view2'
], function (_, Backbone, Handlebars, View2) {
var View1 = Backbone.View.extend({
    tagName: 'li',
    el: '#categoriesList',
    events: {
        'click .categoryItem': 'edit'
    },
    initialize: function () {
        _.bindAll(this, "render");
    },
    edit: function (e) {
        View2.render();
        //**ERROR (cannot call method render of undefined)**
    },
    render: function () {
        //do something here
    }
});

return new View1;
}); 

Thanks

2
are both those views in the URL root of require.js ? or you mapped them using require Path var? - Cristiano Fontes
I mapped them by passing the path. define([model/View1],function(View1){}) - profanis
Is the code complete ? because it looks wierd ? where is the new Backbone.View.extend ? Where is the function after the Define ? can you update with a more detailed code ? - Cristiano Fontes
Well, by adding View2 = require("views/view2") will work, but it doesn't seem to be an optimum solution - profanis
I guess you can't have circular dependencies in define, but do you really want them? I would go with events and maybe an application wide mediator to carry them... - David Palita

2 Answers

4
votes

First add EventBus module. This is basically Event Aggregator Pattern:

define([
    'Underscore',
    'Backbone'
], function(_, Backbone){
    var EventBus = {
    };
    _.extend(EventBus, Backbone.Events);
    return EventBus;
});

Next, use EventBus module for sending messages between modules. This also lets you subscribe for these events in multiple modules and helps to keep Single responsibility principle.:

define([
'Underscore',
'Backbone',
'Handlebar',
'EventBus',
], function (_, Backbone, Handlebars, Vent) {
var View2 = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, "render");
        Vent.on("View1:edit", this.render, this);
    },
    tagName: 'div',
    el: '#rightPanel',
    events: {
        'change input#createNewCategory': 'createNewItem',
        'click #saveEdits': 'saveData',
        'click #clearEdits': 'render'
    },
    render: function () {
        //do something here
    },
    clear: function () {
        this.$el.empty();
    },
    createNewItem: function (e) {
      //so something here
    },
    saveData: function () {
        Vent.trigger("View2:save");
    }
});

return new View2;
});


define([
'Underscore',
'Backbone',
'Handlebar',
'EventBus'
], function (_, Backbone, Handlebars, Vent) {
var View1 = Backbone.View.extend({
    tagName: 'li',
    el: '#categoriesList',
    events: {
        'click .categoryItem': 'edit'
    },
    initialize: function () {
        _.bindAll(this, "render");
        Vent.on("View2:save", this.render, this);
    },
    edit: function (e) {
        Vent.trigger("View1:edit");
    },
    render: function () {
        //do something here
    }
});

return new View1;
}); 
0
votes

Circular dependencies is covered in the require.js documentation here: http://requirejs.org/docs/api.html#circular

You need to include require in your dependency list (as a param to Define function), and then use require() to call the other view, e.g.:

define([
'require'
'Underscore',
'Backbone',
'Handlebar',
'views/view1'
], function (require, _, Backbone, Handlebars, View1) {
var View2 = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, "render");
    },
    tagName: 'div',
    el: '#rightPanel',
    events: {
        'change input#createNewCategory': 'createNewItem',
        'click #saveEdits': 'saveData',
        'click #clearEdits': 'render'
    },
    render: function () {
        //do something here
    },
    clear: function () {
        this.$el.empty();
    },
    createNewItem: function (e) {
      //so something here
    },
    saveData: function () {
        //This works Fine
        require("View1").render();
    }
});

return new View2;
});