I want to dynamically call the method of a custom class much like the below javascript. Except, the javascript below only calls a function that exists in my code. I want to call (dynamically) the function of a class. So I would remove window{value](target, event, self); and use something else that would call the method of a custom created class such as "mycustomclass.anythingcouldbethismethod(target, event, self);" after it had been instantiated of course.
var functions = [
'ajaxify_overlay',
'ajaxify_overlayCancel',
'ajaxify_overlaySubmit',
'ajaxify_rollout',
'ajaxify_rolloutCancel',
'ajaxify_rolloutSubmit',
'ajaxify_upload',
'ajaxify_contentArea',
'ajaxify_itemToggler',
'ajaxify_closer',
'ajaxify_submit',
'ajaxify_inputActivate',
'ajaxify_executeAndRefresh',
'ajaxify_empty'
];
$(document).bind('ready', function(event) {
$('body').live('click', function (event){
var target = $(event.target);
var self = this;
$.each(functions, function(index, value){
if($(target).hasClass(value)) {
window[value](target, event, self);
}
});
});
});
var myClass = { /* your class definition */ };
var methodName = 'myMethod';
myClass[methodName](p1,p2,...,pN);
You mean like this?
function methodCaller( methodName, target, event, self ) {
mycustomclass[ methodName ](target, event, self);
}
methodCaller( "someMethodName" );
Related
I'm converting a mootools class to Jquery, but I'm with a problem at the moment.
I've the following code (mootools)
var ListaItens = new Class({
...
...
initialize: function(element){
....
this.btnAdd = this.tabela.getElement('.add_linha button');
if(this.btnAdd){
this.btnAdd.addEvent('click', this.addLinha.bindWithEvent(this));
this.checkAdd();
}
...
},
addLinha: function(){
}
});
Now in Jquery I've this
var ListaItens = function(element, maxLinhas){
...
this.btnAdd = this.tabela.find('.add_linha button')[0];
if(this.btnAdd){
//$(this.btnAdd).proxy('click', this.addLinha);
$(this.btnAdd).on("click", this.addLinha);
this.checkAdd;
}
...
this.addLinha = function(){
}
})
My problem is how to bind the addline function to btnAdd. My code isn't work because the element 'this' change. And I don't know how to convert the function bindWithEvent to jquery.
Any solution?
Thanks in advance
As far as I know, jQuery does not provide a similar concept of classes as mootools does, so one thing you can do is to use the »classic JS approach« to create classes like so:
function ListaItens () {
var that = this;
this.tabela = $(…);
this.btnAdd = this.tabela.find(…);
if (this.btnAdd) {
this.this.btnAdd.on('click', function (e) {
that.addLinha();
})
}
}
ListaItens.prototype.addLinha = function () {
}
var instance = new ListaItens();
So, to answer your question: What you basically need to do is to keep a reference to the »original this«
I'm making a jquery plugin in which you can set the event for something to happen.
$.fn.makeSomething = function(options) {
var defaults = {
activationEvent: "mouseover"
};
options = $.extend(defaults, options);
this.each(function() {
var elem = $(this);
elem.one(options.activationEvent, function(){
// some code to be called at the event (in which I use elem)
// but by default should be called immediately on load
});
});
return this;
}
I would like the default to be that it just happens without any needed interaction. Is this possible?
A little more info:
I have several divs in which some extra content should be loaded. By default I want the content to be loaded when the page loads. However, on some pages I don't want all the content to be loaded with the page, but I want each piece to be loaded only when you hover your mouse over its div.
Thanks!
If you separate the function definition from the binding:
$.fn.makeSomething = function(options) {
// ...
function doSomething() {
// ...
}
$(this).one(options.activationEvent, doSomething);
};
You can test the activationEvent for a default value that isn't an event, such as null, providing the that same function to .each():
$.fn.makeSomething = function(options) {
var defaults = {
activationEvent: null
};
options = $.extend(defaults, options);
function doSomething() {
var $elem = $(this);
// ...
}
if (!options.activationEvent)
this.each(doSomething);
else
this.one(options.activationEvent, doSomething);
};
// act immediately
$('...').makeSomething();
// act on mouseover
$('...').makeSomething({ activationEvent: 'mouseover' });
Both .one() and .each() will invoke doSomething() with this referring to the DOM Element. (Note: the arguments provided to doSomething() will, however, be different.)
Let's say I have a class laid out like so:
function slider() {
this.init = function(options, title, content) {
var self = this;
$('body').append('<button type="button">' + title + '</button>')
},
this.create = function(title, content, options) {
var self = this;
self.init(options, title, content);
},
this.closeSlider = function(elem) {
var self = this;
self.assignPositions();
},
this.assignPositions = function() {
alert('assign positions called from button?');
}
}
To create the 'slider', I use this:
var slider = new slider();
Then I call the create function:
slider.create('title', 'content');
My question is, how can I bind the closeSlider function to the button, but it's only linked to the instance that created it? If that makes sense?
Basically, I'll have many buttons with the 'closeSlider' function, and I don't want them all to fire at once, I only want it linked to the instance that created it.
This is also a VERY trimmed down version of my class, just trying to figure this little problem out :)
Cheers
Use bind on the callback function when setting the event callback
this.init = function(options, title, content) {
var btn = $('<button type="button">' + title + '</button>');
btn.click(this.closeSlider.bind(this));
$('body').append(btn)
},
This will make it so when the closeSlider function is called it retains the context of the slider instance that made it. But note this will no longer be the context of the html element that triggered the event. So you would need to get the target from event.target
There might be another way of doing this without losing the context of the html element i will have to look and re-edit.
Edit
Using event.target
this.init = function(options, title, content) {
var btn = $('<button type="button">' + title + '</button>');
btn.click(this.closeSlider.bind(this));
$('body').append(btn)
},
this.closeSlider:function(event){
//`this` will refer to slider instance
//and event.target will be the button dom object
var element = event.target;
});
Passing the button object as an argument in bind
this.init = function(options, title, content) {
var btn = $('<button type="button">' + title + '</button>');
btn.click(this.closeSlider.bind(this,btn));
$('body').append(btn)
},
this.closeSlider:function(btn,event){
//`this` will refer to slider instance
//btn will refer to the jQuery wrapped button dom object
//event.target will still refer to the button dom object
});
Instead of simply appending a string to the body, create a live element with document.createElement and attach the onclick event before releasing it into the wild.
Here's an example:
function slider() {
this.init = function(options, title, content) {
var myButton = document.createElement("button");
myButton.setAttribute("type", "button");
myButton.innerHTML = title;
myButton.onclick = this.closeSlider;
$('body').append(myButton);
},
//Other object definitions
}
First of all, you should add methods onto the prototype rather than on each instance (saves memory).
Secondly, you can use jQuery's .proxy() to create an anonymous function that will "hardwire" this to a particular value when it calls your method.
// empty constructor
function slider()
{
}
// define prototype
$.extend(slider.prototype, {
init: function(options, title, content) {
$('<button>', { text: title })
.on('click', $.proxy(this, 'closeSlider'))
.appendTo('body');
},
create: function(title, content, options) {
this.init(options, title, content);
},
closeSlider: function(event) {
// event.target is the HTML element
this.assignPositions(event.target);
},
assignPositions: function(elem) {
alert('assign positions called from button?');
}
});
I am trying to work out how to call functions within my jQuery plugin from outside the plugin. The code I have tried is not working. I'm sure I will have to restructure my plugin to allow this, but I'm not sure how to. In this example, I'm trying to access the underline() function.
jsFiddle
jQuery plugin
(function($) {
"use strict";
$.fn.testPlugin = function(options) {
// Settings
var settings = $.extend({
newText : "Yabadabado"
}, options);
return this.each(function(i, el) {
var init = function(callback) {
if( $(el).attr("class") === "red" ) {
$(el).css("color","red");
}
$(el).text(settings.newText);
if( callback && typeof(callback) === "function" ) {
callback();
}
};
var underline = function() {
$(el).addClass("underline");
};
init();
});
};
}(jQuery));
Assign the plugin to selectors
var doTest = $("#testItem").testPlugin({
newText: "Scoobydoo"
});
var doNewTest = $("#newTestItem").testPlugin({
newText: "kapow!"
});
Call a function that is located within the plugin
$("#underline").click(function(e) {
e.preventDefault();
doTest.underline();
});
Take a look at closures.
Here is a basic example of what a closure looks like in a jQuery plugin.
$.fn.plugin = function() {
return {
helloWorld: function() {
console.log('Hello World!');
}
}
};
// init plugin.
var test = $('node').plugin();
// call a method from within the plugin outside of the plugin.
test.helloWorld();
You can see another example at the following jsfiddle.
http://jsfiddle.net/denniswaltermartinez/DwEFz/
First thing first we need to understand each step in building a jQuery plugin, its like build a javascript plugin (class) but we have in addition to it a jQuery class.
//We start with a function and pass a jQuery class to it as a
//parameter $ to avoid the conflict with other javascript
//plugins that uses '$ as a name
(function($){
//We now append our function to the jQuery namespace,
//with an option parameter
$.fn.myplugin = function(options) {
//the settings parameter will be our private parameter to our function
//'myplugin', using jQuery.extend append 'options' to our settings
var settings = jQuery.extend({
param:'value',
}, options);
//Define a reference to our function myplugin which it's
//part of jQuery namespace functions, so we can use later
//within inside functions
var $jquery=this;
//Define an output object that will work as a reference
//for our function
var output={
//Setup our plugin functions as an object elements
'function1':function(param){
//Call jQuery reference that goes through jQuery selector
$jquery.each(function(){
//Define a reference of each element of jQuery
//selector elements
var _this=this;
});
//This steps is required if you want to call nested
//functions like jQuery.
return output;
},
//If we want to make our plugin to do a specific operations
//when called, we define a function for that
'init':function(){
$jquery.each(function(){
var _this=this;
//Note that _this param linked to each jQuery
//functions not element, thus wont behave like
//jQuery function.
//And for that we set a parameter to reference the
//jQuery element
_this.$this=$(this);
//We can define a private function for 'init'
//function
var privatefun=function(){}
privatefun();
//We can now do jQuery stuffs on each element
_this.$this.on('click',function(){
//jQuery related stuffs
});
});
//We can call whatever function we want or parameter
//that belongs to our plugin
output.function1("value");
}
};
//Our output is ready, if we want our plugin to execute a
//function whenever it called we do it now
output.init();
//And the final critical step, return our object output to
//the plugin
return output;
};
//Pass the jQuery class so we can use it inside our plugin 'class'
})(jQuery);
Using our function now is very easy
<div class="plugintest">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
</div>
<script>
$(function(){
var myplugin=$(".plugintest > span").myplugin({
param:'somevalue'
});
myplugin.function1(1).function1(2).function1(3);
});
</script>
In short, jQuery plugins and any Javascript plugins are simply about parameters scope.
Fiddle version
https://jsfiddle.net/eiadsamman/a59uwmga/
I am setting some setInterval values on my widget's controller code as follows:
define(['durandal/widget'],function (widget) {
var count = 0;
var intervals = [],
ctor = function (element, settings) {
this.settings = settings;
};
ctor.prototype.updateCount = function( ){
var interval = setInterval(function () {
count = count + 1;
return count;
}, 1000);
intervals.push(interval);
}
return ctor;
}
The above code is being run inside a forEach loop inside the view like:
<div data-bind="foreach: {data: settings.items}">
<span class="count" data-bind="text:$parent.updateCount()"></span>
</div>
What I would like to do is call the clearInterval method on all the items in the intervals array when the widget is destroyed or essentially removed from the dom. I know I could do this using the deactivate on a viewModel but from a reusability point of view, I would like the widget itself to handle the clearing of interval. Is there any way I could achieve this with the widget module in Durandal.
For anyone else looking into the same issue, there's a knockout way of achieving the same. Have a look at the following links https://github.com/BlueSpire/Durandal/issues/139 and https://groups.google.com/forum/#!topic/durandaljs/NqUkY-9us2g . The suggestion is to use:
ko.utils.domNodeDisposal.addDisposeCallback(element, callback)
As long as the widget is removed with JQuery's "remove" function, adding a custom event handler on this "remove" function should go like this:
var self = this;
var self.count = 0;
var self.intervals = [];
self.ctor = function (element, settings) {
$(element).on("remove", function () {
$.each(self.intervals, function(index, ival) {
clearInterval(ival);
});
});
this.settings = settings;
};
The problem is that if the widget is removed without JQuery, simply by manipulating the DOM, the event will not be fired. You could then implement the code for the DOMNodeRemoved event, but it's not gonna work for IE...
Edit: if you're using JQuery pre-1.9.1, you might want to check out the other answers to this question.