14

I'd just like to understand the decisions behind Backbone.Marionette's view regarding UI elements. When instantiating a Marionette.View on an existing DOM element, like this:

view = new Marionette.ItemView({
     el: "#element",
     ui : {
         whatever : "#whatever"
     }
});

I am able to access view.$el, the jquery selector inside view.initialize, so far so good. However, when I try to access view.ui.whatever, I only have access to the selector, ie the string "#whatever" instead of the actual $("#whatever") jquery selector.

The reason for this is because Marionette.View.bindUIElements() is only called on render and not before initialize.

I would like to know if you think this behaviour is logic and why?

I am only asking in the case of attaching of the view to an existing el, if the view is created with a template, I do understand why the binding is in render().

Filip Novotny
  • 397
  • 1
  • 4
  • 9
  • this is a side note - you will also experience the behavior if you click the back button to return to the page. calling `this.bindUIElements()` right before using the ui element resolved that issue – Phil Feb 18 '15 at 01:01

3 Answers3

27

Attaching a view to an existing element is the exception. The normal view lifecycle involves calling render, and without doing that there would be nothing for the UI elements to bind to.

Just call this.bindUIElements() in your initialize method when you need to attach a view to an existing element.

Derick Bailey
  • 72,004
  • 22
  • 206
  • 219
  • That's what I am doing, I was just wondering why it wasn't done by default in the case of attaching to an existing element. I didn't realize it was considered an exceptional case in Marionette's philosophy. Thanks for your answer. – Filip Novotny Mar 10 '13 at 13:07
  • Diving deeper, is there a method to use `Marionette.ItemView` and pass it an `el` of pre-existing DOM? It seems that you always have to render the `el` yourself. – Gur Dotan Sep 23 '13 at 11:56
  • calling this.bindUIElements() inside the initialzes seems to break jquery when using 'triggers' with @ui.something, because by the time delegateEvents its called, the elements in this.ui are no longer strings, breaking jquery selectos. is there a better way to do this? currently I am calling bindUIElements after constructing the view, but it doesn't feel right – Asgaroth May 08 '14 at 17:16
  • I'm calling `this.bindUIElements()` in my `initialize` method and I'm getting this error: `Cannot read property 'form' of undefined` which is a property from ui object. Any clue? – Alejandro Garcia Anglada Nov 24 '15 at 11:03
1

When I am working with Marionette, I put the code that has to access the ui elements inside the onShow method. This event is fired after the dom is ready and the elements are ready to be manipulated. Inside this method, your ui.whatever will now be pointing to an element and not a string.

Kalpers
  • 658
  • 5
  • 11
  • Yes but the onShow implies I have a render which in turn implies that I have a template. In my case I have neither so onShow won't ever be fired, right? – Filip Novotny Mar 11 '13 at 13:47
  • I am able to get an ItemView to work without the template but the UI content inside the onShow isn't loading. So I guess there isn't a good way to do it that way. My other suggestion would be to use view.$el.find("#whatever"). This should give you access to that element without a template or doing a render. – Kalpers Mar 14 '13 at 17:52
0

I think you have that problem because you have to access to the jQuery element with

this.ui.whatever

Because "this" is already a view instance. See: http://marionettejs.com/docs/v2.4.4/marionette.itemview.html#organizing-ui-elements

monikaja
  • 411
  • 3
  • 10