Jamie Hutber
Jamie Hutber

Reputation: 28076

Backbone.js using el doesn't work but using $('selector') does. Why?

So, I admit that it might be tricky for somebody to follow my design and build patterns. But I will try best to describe the issue, although I feel this might be easier than getting you to understand my project :) But hell I've spent 3 days trying to figure this one out.

Summery of technical layout

Brief overview - To give you a idea of how my views are set up and what extends what

  1. GV - Loads: login, Home, Global Navigation
  2. DV - Loads: the navigation for this section.
    • DV extends GV: SD.defaultView.extend
  3. OV - Loads: h2, icon for the option and buttons
    • each OV extends DV so that I can keep all the click events in one view and not have to paste code all over: SD.defaultSexView.extend

The problem

OV loads into an element that is inside DV. GV and DV all load perfectly. I can click from, login -> home -> navigation -> through which would then load in the DV. This is where the interactions break down. All that is loaded is whatever was inside the JST for DV

Build

Just to give some background information:

Outline

I know that for OV to load it must have the element that its loading into available. This is el: 'sexdetails'. This element gets loaded from the DV. So I realise that DV needs to be in the DOM for the OV to load. Otherwise it has no element to load into. enter image description here

This is a console load. page is from the GV sexdetails gets loaded in from the DV and this is where the OV gets loaded into. all these consoles are out put in loading order. So from the top to the bottom.

The bottom seems to be seen in the last console.log which is greyed out as the element has been built with all the correct information. But for whatever reason it not output onto the page.

JS

Now the exciting parts :p

DV - This is the second defaultView, the one that handles the menu and where the click events are bound.

SD.defaultSexView = function(){
    //set up homeview
    var sexView = SD.defaultView.extend({
        el: 'page',
        jstemplate: JST['app/www/js/templates/sex/sexTemplate.ejs'],
        events:{
            "click sexoptions > *" : 'changeSex'
        },
        changeSex: function(elem){

            var me = elem.currentTarget.localName;

            $('.selected').removeClass('selected');// #update selected from bottom navigation
            $(me).addClass('selected');

            SD.pageLoad(elem); // #Call function that will re-render the page
        },
        render: function () {
            var compiled = this.jstemplate();
            this.$el.html(compiled);
        }
    });
    SD.DSV = new sexView();
    SD.DSV.render();
    return sexView;
}();

Own View - each of the 5 files has one of these

//set up homeview
var wank = SD.defaultSexView.extend({
    el: 'sexdetails',
    jstemplate: JST['app/www/js/templates/sex.ejs'],
    data: {
        url: SD.HTTP+'stats/add',
        sextype: 'wank',
        header: 'SOME LOUD STRING!!!',
        image: '/img/path.jpg'
    },
    render: function () {
        c($('sexdetails'));
        c(this.$el);
        var compiled = this.jstemplate(this.data);
        this.$el.html(compiled);
    }
});
return wank;

All the code in full working order can be found here: http://m.sexdiaries.co.uk/ - don't be put off by the URL, I assure you its SFW. Everything is done with cartoons and in no crude.

Interestingly if I update the code to use: $('sexdetails').html(compiled); it will indeed display correctly, but none of the events will be bound correctly.

Sorry there is so much to take in, I'll be very very impressed if anybody takes the time out to read or understand this :)

Upvotes: 4

Views: 507

Answers (2)

Josh Sullivan
Josh Sullivan

Reputation: 1176

After taking a look at your code, I noticed that in your "Wank" view, that you are setting el to sexdetails, which doesn't fly. I wasn't able to dig into the details of why this is, but I assume it has something to do with lack of DOM specificity.

Setting el to "body content page" however, allowed to view to render without any issues, as this allowed to view to hook directly into the body of the page and lets the render function do the rest of the work for you.

Hope this helps!

Upvotes: 1

Ravi Hamsa
Ravi Hamsa

Reputation: 4721

I couldn't look into full code. But from my past experience I can say that you are rendering view on a element which might have been removed from page DOM. When you update this.$el.html() of a view, it will take away element from DOM but still maintain elements if referred in a closure. I can see that you are passing

SD.pageLoad(elem)

to some function which does rendering. Since elem is an object, it's passed by reference. even after you update view's template later with

var compiled = this.jstemplate();
this.$el.html(compiled);

element that is send to rendering function remains in memory, but not in DOM, so any element rendered on this element will not be displayed on page. Also you are using $ inside a view, but you should be using this.$. this will make sure that, code from a view will never change elements outside that view.

Upvotes: 1

Related Questions