I have defined a Marionette View, and I need to reflect the model change event. I have my initialize function like so:
initialize: function(){
_.bindAll(this,"render");
this.model.on('change',this.render);
},
Later, I have defined my jquery-ui element initializers in onDomRefresh method. It is a draggable and resizable element, which can be writeable when you click on it. When clicking outside the element, the text is saved.
onDomRefresh: function(){
var self = this;
if(this.$el.resizable()){
this.$el.resizable('destroy');
}
this.$el.resizable({ handles: "n, e, s, w, se, sw, nw, ne" });
this.$el.on('resize', function (e) {
e.stopPropagation();
});
this.$el.draggable().click(function(e){
$(".selected").removeClass("selected");
$(this).addClass("selected");
$(this).draggable( "option", "disabled", true );
$(this).attr('contenteditable','true');
$(this).css({cursor:'text'});
$(this).css({opacity:'100'});
}).blur(function(){
$(this).draggable( 'option', 'disabled', false);
$(this).attr('contenteditable','false');
$(this).css({cursor:'move'});
self.textchange(); //update and save the text in the model
});
}
The problem comes, when the model has nested some model change events, and the click function is firing more and more times. I have been looking for jquery click event solutions, and none of them seems to work for me.
Tried solutions:
this.$el.draggable().unbind("click").click(function(e){});
this.$el.draggable().off("click").on('click',function(e){});
this.$el.draggable().one('click', function(e){});
//with jquery sparkle
this.$el.draggable().once('click', function(e){});
I also notice that sometimes onDomRefresh method fires two times. Don't know how to fix that. Any ideas are more than welcomed.
I have added this call at the beggining of onDomRefresh() function, which unbinds all the events on the element:
this.$el.unbind();
Now, the click event fires just once after rerendering the view.
Related
Adding my bindings to the pageinit event like so:
$('#mypage').on("pageinit", function () {
$('#login-sumbit').on('click', function () {
console.log('button clicked');
});
});
I would expect pageinit to bind the click event once only. But what happens in my single page app is that the button is binding every time the page is loaded even when clicking back.
This results in undesirable multiple duplicate binds. Any ideas on what event to use to bind only once in my single page app, so that loading the page again (back button, loading inline page) in the same session doesn't re-bind?
Looks like I found the answer myself, turns out quite rightly pageinit fires every time the page is loaded even though it's not reloading from the server, otherwise what would fire when a new page is shown.
pageinit is the right event but I need to use .one not .on, .one will bind one time only.
$('#mypage').on("pageinit", function () {
$('#login-sumbit').one('click', function () {
console.log('button clicked');
});
});
Now everything works as expected. Better still I've found you can use .one with the pageinit event for even more control over your bindings and data loads perfect for my requirements.
http://api.jquery.com/one/
You could use:
$('#login-sumbit').off('click').on('click', function(e) {
console.log('button clicked');
});
I fill list dynamically, and after that on click I have multiple calls of event. 1st time it is repeated 1 time, 2nd time 2 times, 3rd time 3 times, etc...
First, more about this problem can be found in my other answer: jQuery Mobile: document ready vs page events
Prevent multiple event binding/triggering
Because of interesting jQM loading architecture, multiple event triggering is a constant problem. For example, take a look at this code snipet:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/CCfL4/
Each time you visit page #index click event will is going to be bound to button #test-button. There are few ways to prevent this problem:
Solution 1:
Remove event before you bind it:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die().live('click', function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
In case you have different events bound to an object:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die('click').live('click', function(e) {
alert('Button click');
});
});
Solution 2:
Use a jQuery Filter selector, like this:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/
In a nutshell, if speed is your main concern then Solution 2 is much better then Solution 1.
Solution 3:
A new one, probably an easiest of them all.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more then once
{
alert('Clicked');
e.handled = true;
}
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/
Tnx to the sholsinger for this solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
More info
If you want to find more about this problem take a look at this article, working examples are included.
We have a rails 3.2.8 app with jquery autocomplete. The app should fire an event after user selects a customer name from the list (#invoice_customer_name_autocomplete). After selecting, an ajax change event is fired. That's all the app should do. However the following code does not do the job (error: "t.item.customer is undefined"). A user can not even select. The text box won't take customer name and the screen gets stuck:
//for autocomplete
$(function() {
return $('#invoice_customer_name_autocomplete').autocomplete({
minLength: 1,
source: $('#invoice_customer_name_autocomplete').data('autocomplete-source'),
select: function(event, ui) {
$('#invoice_customer_name_autocomplete').val(ui.item.customer.name);
},
});
});
$(document).ready(function (){
$('#invoice_customer_name_autocomplete').change(function (){
//ajax call
$.get(window.location, $('form').serialize(), null, "script");
return false;
});
});
If manually changing the customer name, the .change event will fire. However it does not fire after selecting. What's wrong with the code above?
UPDATE:
If the select can trigger a change event on invoice_customer_name_autocomplete, then this is what we want. Tried the code below without success (no change event fired):
select: function(event, ui) {
$(this).trigger('change');
}
You may be using the jQuery Autocomplete plugin I can't be sure, but you're calling it the way you would call the jQuery UI autocomplete.
In case you are using the first
Suggestions:
Use autocomplete in jQuery UI instead of the autocomplete plugin. The latter is deprecated.
Using the correct framework here is a example of it working:
jsFiddle
It is no different from yours, so the thing is that you should log the ui object in order to understand why you are accessing a null object, the easiest way to do it is to log on console the whole object and watch it.
console.log(ui)
Edit:
Regarding the onChange you may check this post: trigger onchange event manually
Hope it helps!
I have a drag and drop interface with JQueryUI, and when a user drags an element into one of its containers and drops it, I want to display some information about the selected item.
$(document).ready(function()
{
$( ".element" ).draggable({snap: ".elementContainer"});
$( ".elementContainer" ).droppable({
drop:function(){
$("table").append('<tr><td class="elementContainer ui-droppable"></td></tr>');
}});
});
So it's creating a new element with the UI droppable class. My question is, why won't it fire a "drop" event on the newly created element?
It won't fire because when you run $(".elementContainer").droppable(...) it binds the droppable widgets to the .elementContainer elements that exist at that time, s you'll need to run the plugin again for newly created elements with the class.
Something like this:
$(document).ready(function() {
$( ".element" ).draggable({snap: ".elementContainer"});
$.fn.bindDroppable = function() {
return this.droppable({
drop:function(){
$('<tr><td class="elementContainer"></td></tr>')
.find(".elementContainer").bindDroppable().end().appendTo("table");
}
});
};
$(".elementContainer").bindDroppable();
});
This is the plugin version to cut down on code...but the basic premise is you need to call .droppable(...options...) on all the new <td> elements as well, since the widget code wasn't run on them before...because they didn't exist yet.
I've searched everywhere, but I can't seem to find any help...
I have some textboxes that are created dynamically via JS, so I need to bind all of their classes to an autocomplete. As a result, I need to use the new .live() option.
As an example, to bind all items with a class of .foo now and future created:
$('.foo').live('click', function(){
alert('clicked');
});
It takes (and behaves) the same as .bind(). However, I want to bind an autocomplete...
This doesn't work:
$('.foo').live('autocomplete', function(event, ui){
source: 'url.php' // (surpressed other arguments)
});
How can I use .live() to bind autocomplete?
UPDATE
Figured it out with Framer:
$(function(){
$('.search').live('keyup.autocomplete', function(){
$(this).autocomplete({
source : 'url.php'
});
});
});
jQuery UI autocomplete function automatically adds the class "ui-autocomplete-input" to the element. I'd recommend live binding the element on focus without the "ui-autocomplete-input"
class to prevent re-binding on every keydown event within that element.
$(".foo:not(.ui-autocomplete-input)").live("focus", function (event) {
$(this).autocomplete(options);
});
Edit
My answer is now out of date since jQuery 1.7, see Nathan Strutz's comment for use with the new .on() syntax.
If you are using the jquery.ui.autocomplete.js try this instead
.bind("keydown.autocomplete") or .live("keydown.autocomplete")
if not, use the jquery.ui.autocomplete.js and see if it'll work
If that doesn't apply, I don't know how to help you bro
Just to add, you can use the .livequery plugin for this:
$('.foo').livequery(function() {
// This will fire for each matched element.
// It will also fire for any new elements added to the DOM.
$(this).autocomplete(options);
});
To get autocomplete working when loaded dynamically for the on() event used in jQuery > 1.7, using the syntax Nathan Strutz provides in his comment:
$(document).on('focus', '.my-field:not(.ui-autocomplete-input)', function (e) {
$(this).autocomplete(options)
});
where .my-field is a selector for your autocomplete input element.
.live() does not work with focus.
also keyup.autocmplete does not make any sense.
Instead the thing I have tried and working is this
$(document).ready(function(){
$('.search').live('keyup' , function()
{
$(this).autocomplete({ source : 'url.php' });
});
})
This works perfectly fine.
You can't. .live() only supports actual JavaScript events, not any custom event. This is a fundamental limitation of how .live() works.
You can try using this:
$('.foo').live('focus.autocomplete', function() {
$(this).autocomplete({...});
});
After reading and testing everyone else's answers I have updated it for the current version of JQuery and made a few tweaks.
The problem with using keydown as the event that calls .autocomplete() is that it fails to autocomplete for that first letter typed. Using focus is the better choice.
Another thing I have noticed is that all of the given solutions result in .autocomplete() being called multiple times. If you are adding an element dynamically to the page that will not be removed again, the event should only be fired once. Even if the item is to be removed and added again, the event should be removed and then added back each time the element is removed or added so that focusing on the field again will not unnecessarily call .autocomplete() every time.
My final code is as follows:
$(document).on('focus.autocomplete', '#myAutocomplete', function(e){
$(this).autocomplete(autocompleteOptions);
$(document).off('focus.autocomplete', '#myAutocomplete');
});
autocomplete is not an event rather a function that enables autocomplete functionality for a textbox.
So if you can modify the js that creates the textboxes dynamically to wrap the textbox element in as a jquery object and call autocomplete on that object.
I just noticed you edited your post with this answer. It was obvious to me so I'm posting it below for others. Thank you.
$(function()
{
$('.search').live('keyup.autocomplete', function()
{
$(this).autocomplete({ source : 'url.php' });
});
});
This works for me:
$(function()
{
$('.item_product').live('focus.autocomplete', function()
{
$(this).autocomplete("/source.php/", {
width: 550,
matchContains: true,
mustMatch: false,
selectFirst: false,
});
});
});
You can just put the autocomplete inside input live event, like this:
$('#input-element').live('input', function(){
$("#input-element").autocomplete(options);
});