DOM location of ItemView when passed in CompositeView - Marionette - javascript

I have an ItemView like this:
var Userview= Marionette.ItemView.extend({
template: "#user1",
el: "#imp1"
});
Question: Does this mean that template of ItemView: #user1 will go into the (say) div with id=imp1 in the DOM, when rendered?
(If not, then I guess I can use regions to render Userview in a certain div in the DOM, so its fine!)
Now, in case of rendering a CompositeView, I use Region1.show() for CompositeView. In this case, how can I render a (childView) ItemView of the CompositeView at a specific location (say a div with an id) in the DOM.
(As I am calling Region1.show() on the CompositeView and not on the ItemView, I dont know how to render the ItemView at a specific location on the DOM)

If the ItemView is the CompositeView child, then you cannot render that at a specific location in the DOM.
You can only render on a specific location inside the CompositeView(childViewContainer), and the CompositeView will render directly into DOM via a region.
So, if you want to render an ItemView at a specific location in the DOM, you should use only a Region and the ItemView, without compositeView.
var myView = new MyView();
myRegion.show(myView);

So, the trick is to define a childViewContainer: "#some_id" inside the CompositeView definition. It will define location of the (childView) itemView.
Also, using the word itemView inside CompositeView will cause an error, we need to use childView: child_view_name

Related

Backbone.js - render a new element to the page

Say you create a new element in your View - i.e. you don't target an existing element on the page with el.
var StudentView = Backbone.View.extend({
tagName: 'article',
className: 'student-name',
template: _.template($('#name-tpl').html()),
render: function(){
var student_tpl = this.template({name: 'Rikard'});
this.$el.html(student_tpl);
}
});
You then instantiate the View and call its render method:
var student_view = new StudentView();
student_view.render();
Your HTML contains the following template:
<div class="target">
<script id="name-tpl" type="text/template">
<%= name %>
</script>
</div>
This does not print the newly created element to the page. If we set el to .target, then it would work, but then it wouldn't print your tag name or class name that you set in the View.
Is there any way to print your newly created element to the page? I thought about using jQuery append, but it seems like there should be a more backbone-oriented solution.
Unless you use the el option to attach the view to an existing element in DOM, backbone.js creates an HTMLElement in memory, detached from DOM. It's your responsibility to attach it to where you want (backbone creates a new element for you, but it doesn't know where in DOM you want it to be added).
If you already have a Backbone.View and you want to set it to a different element, you can use setElement, but in this case as well, it is your responsibility to make sure that the element is part of DOM.
If backbone gave you a way to specify the position of an element in DOM, that'd look something like:
{
tagName: 'article',
elPosition: '#container > .content+div:nth-child(3)'
}
Again, there will be confusion like whether the element should be added before elPosition, or after etc. That looks ugly, no wonder why backbone leaves it to you rather than setting up more rules. In my opinion backbone sets less rules compared to other frameworks and give you more freedom (freedom can be a pain when you don't know what to do with it :)
What we normally do is, have the main parent view point to the containing element in DOM like <body> , using the el option.
Then append the child view's to it like this.$el.appendTo(parentView.$el);

What is the default element for Backbone view?

When I use this
this.setElement($('#some-id'));
in backbone's view, what am I changing the element from? The parent DOM?
Executing new Backbone.View() shows that the default element (the wrapper for the view) is just a <div> that isn't attached to the DOM.
Not setting the el property of a view doesn't necessarily effect how your view is displayed. Ultimately, you will have to append your view to the DOM inside your render function. The el property is just a convenient way to keep track of where your view should go/is.

How can I remove line breaks between each childView when rendering a Marionette CollectionView?

In MarionetteJS, when creating a CollectionView, all the children are automatically separated by line breaks when rendered. I would like the children in a particular CollectionView that I have to be rendered in order without a line break added (effectively replacing the line break with a space).
I've looked through the source code, and am sure that I need to alter one of the functions that is called from the render method of the CollectionView. However, I can't for the life of me figure out what it is that needs to be altered.
To find the function in question, find "Render children views" on this annotated source code page: http://marionettejs.com/annotated-src/backbone.marionette.html If anybody can help me figure out what needs to be altered, I would really appreciate that!
Every view needs to either be handed a DOM element to use as a root or create one itself. You can control what tag an ItemView uses as root with the tagName property. The default is <div> which is a block element and that's why you get linebreaks.
You have a couple of options here, and none of them is editing the Marionette source.
You can either have you view use an inline element (like a <span>) as a root, which is the option I would prefer.
var ItemView = Backbone.Marionette.ItemView.extend({
template: '#template',
tagName: 'span'
});
demo
Or you could use CSS to set the root element of your ItemView to display: inline-block.

backbone remove view deletes the el

I am creating a single page application, and I am quite new to backbone. I have a problem with creating multiple views which uses the same wrapper-div.
My setup:
I have added a close function to all views:
Backbone.View.prototype.close = function(){
this.remove();
this.off();
if (this.onClose){
this.onClose();
}
}
I have a wrapper-div where I want to render views, remove them and render new ones. So my SetupView looks like this:
app.SetupView = Backbone.View.extend({
el: '#my_view_wrapper',
...
});
From the function where I swap views I close the current (open) view like this:
var v = this.model.get('view');
v.close();
Question
My problem is that I have multiple view's using the same wrapper-div. But when I close a view, this wrapper-div seems to be removed, and the next view I try to create can't find this div.
I guess there is an easy solution? I want to reuse the same wrapper, and only remove the view inside it, not the wrapper itself.
Just as an addition (for later reference) : another option is to overwrite the subviews remove so that it just empties $el instead of removing it. Eg.
remove: function() {
this.$el.empty().off(); /* off to unbind the events */
this.stopListening();
return this;
}
Personally I prefer this, as it removes the need to insert wrapper elements that have no real use.
In your scenario don't use an existing DOM element as your "el" value. Backbone will create the element for you. When you instantiate your view you can do the following to attach it to your existing wrapping element.
$(viewName.render().el).appendTo('#my_view_wrapper');

How do you dynamically create Backbone view elements?

I'd like to create some view elements in a Backbone js application dynamically. When a new view is initialized, I want it to insert the new element into the DOM, store the reference to the element in view.el, and delegate events as usual.
I understand that I can put in my html, and then setup a view with el: "#test" but this seems like overkill for modals and other views that aren't central to the web application. Is there a prescribed way to do this I'm missing in the docs? Am I just misunderstanding how views are supposed to work?
A backbone view will generate an el for you, without you having to do anything. By default, it creates a <div>. You can generate any tag name you want, though. Once you have the view instantiated, implement a render method on the view, and populate the el with your HTML.
MyView = Backbone.View.extend({});
var v = new MyView();
console.log(v.el); // => "<div></div>"
// define your own tag, and render contents for it
MyTagView = Backbone.View.extend({
tagName: "ul",
render: function(){
this.$el.html("<li>test</li>");
}
});
var v2 = new MyTagView();
v2.render();
console.log(v2.el); // => "<ul><li>test</li></ul>"
It's common practice to use a template system to render your view's HTML, like Underscore.js template, Handlebars, or any of the other dozen or more template JavaScript template engines.
Once you have the content generated from the view, you need to stick it in to the DOM somewhere before it will be visible. This is usually done with jQuery or another plugin:
$("#some-element").html(v2.el);

Categories