Below is my html and I have given ids to my all li's ..
<ul id="color_wrap">
<li id="block4"></li>
</ul>
I'm novice to backbone.js. In my js file and in backbone.view part I have declared my code as shown below.
I have given width and height to that li and when I click on it does not work. I want to make all li's clickable please help me where it is wrong, why its not working.
When I click on li having id block4 it should call chooseColor function.
var SearchView = Backbone.View.extend({
el: $("#search_container"),
events: {
"click #block4": "chooseColor",
"focusout #search_input": "setDefaults"
},
chooseColor:function() {
alert("hi");
}
});
As per your JSFiddle, it's not working because you are binding your events to SearchView that has search_container as root element. block4 is not a child of search_container and will never be matched. I would suggest to create another View that represent color_wrap. Your click event, if declared in such a view, will work.
The problem is that all events added in the events block only listen to the element of the view not all elements in the page. So in your case # block4 is not a child element in the view.el element.
Take a look at the documented source code of backbone. There can you see that it use jQueries $el.on on the views element to bind the events.
Related
I'm injecting some HTML into my page using this code:
<script>
window.onload = function() {
addHeader();
};
</script>
<script>function addHeader(){$("#header-nav-studio").after('<li id="header-nav-products" class="has-subnav"> Pricing <span class="arrow-down"></span> <div class="header-subnav"> <ul> <li> Apparel Pricing</li><li> Sticker Pricing</li><li> Pinback Button Pricing</li></ul> </div></li>')}</script>
It works, loads everything directly after the "#header-nav-studio" DIV. Only problem is, it's not rendering the HTML within the script properly. It's supposed to generate a "Pricing" dropdown menu. Instead it only works as a link. You can see the example HERE
Is there a way to load the html properly within the script tag or load it from an external source? Thanks so much!
Looks like you need to bind mouseover event on DOM element you have dynamically added that triggers your submenu appearance.
On li element with class has-subnav, there is mouseover event listener, that toggles css class active on it.
You need to change your javascript, so the event is attached even for dynamically created elements. You can use $.on() on parent selector to attach handler.
$('body').on('mouseover', '.has-subnav', function() {
$(this).addClass('.active');
});
//and to remove class on mouseout
$('body').on('mouseover', '.has-subnav', function() {
$(this).removeClass('.active');
});
In the example you shared, the pricing menu item has id same as products menu item. Two nodes having same id can have unexpected results. I would say change the id first to say 'header-nav-pricing' and try your code again.
I'm using agile toolkit, a framework that generates javascript code from PHP. I have a div element (I'll call it "top-element") that contains some other div elements, some buttons.
I want to move the "top-element" to another element, to change it's parent.
I tried something like:
$('#top-element').appendTo($('#new-parent'));
But the problem is that the "top-element" have some childrens that have click events, some buttons. After I append the "top-element" to a new element (after changing it's parent), the click events are triggered twice.
I tried to clone the element and append the cloned element to the new parent:
var cloned_top_element = $('#top-element').clone(true);
cloned_top_element.appendTo($('#new-parent'));
I got the same problem, the click event on "top-element" childrens was called twice.
The way to prevent double click is to use:
unbind('click') or off('click')
I tried something like:
$('#new-parent').find('.children-class').unbind('dblclick').unbind('click');
But still no results.
The binding for child buttons is like this:
$('.children-class').bind('click',function(ev){ ev.preventDefault();ev.stopPropagation(); other stuff });
The bind function appears only once. There aren't duplicates in the js code.
Any ideas? Anticipated thanks.
Remove the true in the clone function .clone(); this will not copy the event handlers
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);
I have a method to dynamically add a container which is attached to the target container . When the action has been performed i removed the action container but now I have to add a class to parent container but problem is it is getting set (class name to parent container ) but it gets removed itself. For more clarification I am adding an sample code
<div class="main">
<ul>
<li>some contents</li>
................
................
</ul>
<ul class="dynamic_container">
<li>actions</li>
................
</ul>
</div>
dynamic_container is added when user mouseover the main class container and this get removed once action has been executed . But now it gets added(class name) but it gets removed too .
I believe this is basically because $(e.target) get removed ....
Any advice/suggestion will be appreciated . Thanks in advance.
edit :
$(e.target).parents('.main').addClass('current'); (this code does not able to add class to .main div) . This code is executed from ul.dynamic_container (which is added to the dom on mouseover on div.main)
edit 2:
jsfiddle link: this is the structure (not the actual code)
http://jsfiddle.net/CASy6/
Thanks for posting the fiddle. Now we can identify some problems that are preventing it from working.
The first problem is that when you try to move the mouse over the buttons, they disappear. If you add some console.log statements to the mouseover and mouseout handler functions, you will see that they get called way too much. This is due to the way these events work in a situation with nested elements.
jQuery provides a good solution to this problem: the mouseenter and mouseleave events. Read about them in the API docs, specifically the section describing the difference between mouseover and mouseenter.
See this fix implemented in this version of the jsFiddle: http://jsfiddle.net/CASy6/1/. With this, you can now actually click on the buttons, and also, a whole bunch of unnecessary .append() and .remove() calls are avoided.
The next problem is that no handler is called when you click a button.
The reason for this is that you set up the handlers by calling e.g.
$('li.first').on('click', function(e){ ... });
when the page loads, but at that moment, the selector li.first matches nothing, because you haven't appended the buttons to one of the divs yet. So handlers are only attached at page load, and they have nothing to attach to.
One solution for this problem is to use delegated events (see docs). This means we attach a handler to a container element (which is always present, including at page load), and handle events that bubble up from a descendant element.
In this case, we can attach a delegated event handler to the .main divs, which handles a click coming from one of the buttons:
$('div.main').on('click', 'button.first', function(e){
$(this).closest('.main').addClass('current');
alert('first action');
});
The second argument button.first is a selector which determines which descendant events will be handled by this handler. (I fixed the appended html so the class attribute is attached to the button element instead of the li element; it was inconsistent between the two buttons.)
See these fixes in action here: http://jsfiddle.net/CASy6/2/
I am appending manually the view to a dom element in my template with the following code:
appendHtml: function(collectionView, itemView, index){
collectionView.$("ul#search_list_container").append(itemView.el);
}
In my template I have:
<script id='search-list-grid-template' type='text/x-handlebars-template'>
<ul id="search_list_container"></ul>
</script>
Despite I am appending the view to the ul#search_list_container I have the default div wrapping the template:
<div>
<ul id="search_list_container">
<a href="#">
<span id="search_list_item">
id
invoice_number
</span>
</a>
</li>
</ul>
</div>
is there a way to avoid displaying the default tag "div"?, I have no problem with this but this doubt has always come to my mind whenever I come up with this example.
Note: I have an itemView for the ul compositeView, and some other stuff not shown here.
Backbone Views are designed to have their own DOM element stored as the view's el property.
It is not recommended to remove the view's element as suggested by Steven-Farley, because events might be bound to it.
The best way would be to change the tagName property of your collectionView to ul.
See also: Extra divs in itemviews and layouts in Backbone.Marionette
With jQuery you could use .unwrap().
Try this:
Change:
collectionView.$("ul#search_list_container").append(itemView.el);
To:
collectionView.$("ul#search_list_container").append(itemView.el).unwrap();
Couple of things about this Collection View does not need a template, it either renders the empty view
Or The Item View depending on whether the collection has anything or not.
that being said if you dont want the "div" in each item. try
adding
var yourItemView= Backbone.Marionette.ItemView.extend({
tagName: "li",
//OTHER STUFF HERE
});
then remove the wrapping <li> from your item template.
You shouldnt need to modify appendHtml att all for this use case.