I'm trying to bind a click event to the function below, however the entire function is currently being run when being binded in the document ready.
Is it possible to run it solely on the click event? Possibly it has something to do with the way my method is composed?
Thanks in advance
$(function() {
$("#expand-search").on("click", search.resize());
});
var search = {
element: $('#search_advanced'),
resize: function() {
search.element.slideToggle(400, 'swing', search.buttonState());
},
buttonState: function() {
if(search.element.is(':hidden')) {
console.log('hidden');
} else {
console.log('visible');
}
}
};
You are calling the function (handler) instead of passing the reference (name) of function (handler) to on().
Change
$("#expand-search").on("click", search.resize());
To
$("#expand-search").on("click", search.resize);
No parenthesis to event handlers! You want to pass the function-to-be-executed, not the result from executing it. Also, you will need to move your search object inside the ready handler since you use selectors for its initialisation.
$(function() {
var search = {
element: $('#search_advanced'),
resize: function() {
search.element.slideToggle(400, 'swing', search.buttonState);
},
buttonState: function() {
if(search.element.is(':hidden')) {
console.log('hidden');
} else {
console.log('visible');
}
}
};
$("#expand-search").on("click", search.resize);
});
Related
I am using the bPopup jquery library.. the syntax to add to the onclose event is pretty straightforward:
$('element_to_pop_up').bPopup({
onOpen: function() { alert('onOpen fired'); },
onClose: function() { alert('onClose fired'); }
})
What I want to do is add something to the onClose event after the object is created.. is it possible?
In general you can do this by creating a function that you fiddle with later:
var myOnClose = function() { alert('onClosed fired'); }
function doOnClose() { myOnClose(); }
$('element_to_pop_up').bPopup({
onOpen: function() { alert('onOpen fired'); },
onClose: doOnClose
})
// later...
myOnClose = function() { console.log("Doing something different!"); }
You can access the bPopup object which will be present inside the data of the element.
$('element_to_pop_up').bPopup({
onOpen: function() { alert('onOpen fired'); },
onClose: function() { alert('onClose fired'); }
});
$('element_to_pop_up').data('bPopup');
NOTE: There is no guarantee that the created object will be always present in element's data. But this is widely used approach. It is better to rely on the callback provided.
var realOnclose = f1;
function myOnClose(){realOnclose();}
$('element_to_pop_up').bPopup({
onOpen: function() { alert('onOpen fired'); },
onClose: myOnClose
})
function f1() { alert('onClose fired'); }
function f2() { alert('hey I am another function'); }
//when you want to change the action when onclose...
realOnclose = f2;
If you want to add to, rather than replace, the code you originally supply to the onClose option, you could trigger a custom event:
$('element_to_pop_up').bPopup({
onClose: function() {
// Do the original stuff here.
this.trigger('popup:close');
}
});
Then, at any time later, you can register a handler for the custom event:
$('element_to_pop_up').on('popup:close', function() {
// Do the additional stuff here.
});
Note: Looking at the code for the bPopup library, it looks like the context for the onClose function is the original jQuery object, but if it isn't, replace with: $('element_to_pop_up').trigger('popup:close');.
Skip to bottom for question
JQuery plugin:
$.fn.myPlugin = function( options ) {
var options = $.extend({
myOption: true,
edit: function() {},
done: function() {}
}, options);
options.edit.call(this);
options.done.call(this);
//plugin guts removed to prevent over complication
return {
edit: function(obj) {
$(obj).closest('#myParent').find('#myInput').autosizeInput(); //plugin to autosize an input
},
done: function(obj) {
$(this).closest('tr').find('td').not('.not').each(function(i) {
//do some things
});
}
}
});
Bear in mind this is a cut down version of my plugin.
Called from page:
$(document).ready(function() {
var myPlugin = $('.editable').myPlugin({
edit: $(this).on('click', '.edit-td', function(e) {
e.preventDefault();
//do some page specific stuff
myPlugin.edit( $(this) ); //call the edit returned function
}),
done: $(this).on('click', '.done-td', function(e) {
e.preventDefault();
//do some page specific stuff
myPlugin.done( $(this) ); //call the done returned function
});
});
});
This works great for the most part, however, what i really want is have functions called from inside my plugin every time a specific callback is triggered - without the need to call from outside the plugin.
I have tried including delegated events in my plugin:
$(this).on('click', '.edit-td', function(e) {
e.preventDefault();
$(this).closest('#myParent').find('#myInput').autosizeInput();
});
$(this).on('click', '.done-td', function(e) {
e.preventDefault();
$(this).closest('tr').find('td').not('.not').each(function(i) {
//do some things
});
});
But when the .edit-td is triggered it propagates and triggers the .done-td event, if i put e.stopPropagation() in the edit-td function (because it has been delegated) edit-td stops firing completely.
And non-delegated method:
$(this).find('.done-td').click(function(e, this) {});
But I can't parse the returned object (this) to the internal function before the internal function has completed. (just comes up undefined or missing formal parameter).
*Skip to here
To avoid the question becoming to localised -
I need to have functions called from inside my
plugin every time a specific callback is triggered.
Without calling it using closures
Something like:
if( $.fn.myPlugin.callback().is('edit') ) {
//fire function
}
I needed to return a function(s) like so:
return {
enable: function(arg) {
//do something
},
disable: function(arg) {
//do something
}
}
That way I can call it from inside my plugin by referencing itself like this:
this.myPlugin().disable();
I was trying to make a clean jQuery code and I put all my things inside a function that I call in a "each". The problem is that nothing happens and in console doesn't appear any error.
That's an example code:
$(function() {
$('.myElement').each(function() {
if($(this).children()) {
myFunction();
} else {
myFunction('.myOtherElement');
}
});
});
function myFunction(selector) {
if(!selector) {
$(this).html('Finish');
} else {
$(this).find(selector).html('Finish');
}
}
If I put my function content in .each it works, but in a separated function not, and I think that it should work. Why this snippet of code doesn't work?
The execution context(this) is different in this case, you can use .call() to apply it
$(function() {
$('.myElement').each(function() {
if($(this).children()) {
myFunction.call(this);
} else {
myFunction.call(this, '.myOtherElement');
}
});
});
The problem is the this in your case is not your object inside .each, but is the window object. To bind the this as a jquery object without having to apply the context everytime you want it using call . You could define it as a jquery plugin function
(function($){
$.fn.myFunction = function (selector) {
if(!selector) {
this.html('Finish'); //notice this here refer to jquery object instead of $(this)
} else {
this.find(selector).html('Finish');
}
}
})(jQuery);
$(function() {
$('.myElement').each(function() {
if($(this).children()) {
$(this).myFunction();
} else {
$(this).myFunction('.myOtherElement');
}
});
});
Ok terrible title but I couldn't think of another description.
I have the following code:
jQuery( document ).ready( function( $ )
{
$.myNamespace = {
init: function()
{
$('.button').click(function() {
this.anotherFunction();
});
},
anotherFunction: function()
{
alert('insidefunction');
}
}
$.myNamespace.init();
});
As you can see I am trying to call anotherFunction from inside init and have there the two ways I tried but didn't work. So how am I able to call that function or is my concept wrong?
jQuery( document ).ready( function( $ )
{
$.myNamespace = {
init: function()
{
var a=this;
$('.button').click(function() {
a.anotherFunction();
});
},
anotherFunction: function()
{
alert('insidefunction');
}
}
$.myNamespace.init();
});
http://jsfiddle.net/ZpAtm/2/
Absolutely calling it within the click handler changes things, as this inside any jQuery event handler is set to the element that caused the event.
Instead, try using the following pattern:
jQuery(document).ready(function($) {
$.myNamespace = (function() {
function init() {
$('.button').click(function() {
anotherFunction();
});
}
function anotherFunction() {
alert('insidefunction');
}
// return an object with all the functions you want
// available publically as properties. Don't include
// any "private" functions.
return {
init: init,
anotherFunction: anotherFunction
};
})();
$.myNamespace.init();
});
I think what I want to do is pretty simple I just don't know how to do it. I would like to fire my own event when one of my models attributes changes for the purpose of passing some data to the event handler (whether the change was an increase or decrease in value).
Basically I want my handler to do this in the view
handler: function(increased) {
if(increased) {
alert("the value increased")
}
else {
alert("the value decreased")
}
}
// ...
this.model.on("change:attr", this.handler, this);
Here you go: You basically listen for change:myvar. When a change occurs you use your model's previous() to get the old value. Depending on whether it increased or decreased you fire the appropriate event. You can listen to these events as shown in the initialize().
(function($){
window.MyModel = Backbone.Model.extend({
initialize: function () {
this.on('change:myvar', this.onMyVarChange);
this.on('increased:myvar', function () {
console.log('Increased');
});
this.on('decreased:myvar', function () {
console.log('Decreased');
});
},
onMyVarChange: function () {
if (this.get('myvar') > this.previous('myvar')) {
this.trigger('increased:myvar');
} else {
this.trigger('decreased:myvar');
}
}
});
window.mymodel = new MyModel({myvar: 1});
mymodel.set({myvar: 2});
mymodel.set({myvar: 3});
mymodel.set({myvar: 1});
})(jQuery);
Running the above will print "Increased", "Increased", "Decreased" to your console.
Just look at previousAttributes()
You can then compare:
If(this.get(attr) > this.previousAttributes()[attr]){
console.log('bigger');
} else {
console.log('smaller');
}
If you use that in your change event handler you're all set. No need for a custom trigger or a ton of code.
EDIT
This is from my Backbone.Validators project and how I obtain the list of all attributes which have changed during the validation step:
var get_changed_attributes = function(previous, current){
var changedAttributes = [];
_(current).each(function(val, key){
if(!_(previous).has(key)){
changedAttributes.push(key);
} else if (!_.isEqual(val, previous[key])){
changedAttributes.push(key);
}
});
return changedAttributes;
};
This requires Underscore 1.3.1 because it's using _.has. If you can't upgrade that's an easy thing to replace though. In your case you'd passing this.previousAttributes() and this.attributes
What if you fire your own custom event after listening to the change event?
handler: function(increased) {
this.model.trigger('my-custom-event', stuff, you, want);
},
myHandler: function(stuff, you, want){
// Do it...
}
// ...
this.model.on("change:attr", this.handler, this);
this.model.on('my-custom-event, this.myHandler, this);