jquery AMD plugin - each() does not loop? - javascript

I tried to make a jquery plugin in AMD pattern and it seems that I can't get the each() to loop. It only return the first item but I have three items.
index.html,
<body>
<div class="element">
1
</div>
<div class="element">
2
</div>
<div class="element">
3
</div>
</body>
in the html head,
$(document).ready(function(){
$(".element").plugin2().data('plugin_plugin2').someMethod();
});
plugin.js,
!function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(root.jQuery);
}
}(this, function($) {
var pluginName = 'plugin2',
defaults = {
param1: 'param1',
param2: 'param2'
};
var Plugin = function(element, options) {
this.element = element;
this.options = options;
};
Plugin.prototype = {
constructor: Plugin,
someMethod: function(options) {
var rootScope = this;
return rootScope.element.each(function(e){
console.log(e); // you get 0 only
console.log(this); // the first <div class="element"> only
});
}
};
$.fn[pluginName] = function(options) {
options = $.extend(true, {}, defaults, options);
return this.each(function() {
var $this = $(this);
$this.data('plugin_' + pluginName, new Plugin($this, options));
});
};
$.fn[pluginName].defaults = defaults;
$.fn[pluginName].Plugin = Plugin;
});
any ideas what have I done wrong?

Like all of jQuery's getter/setter methods, data is asymmetrical: When setting, it sets on all elements in a jQuery set, but when getting, it only gets from the first.
So this line:
$(".element").plugin2().data('plugin_plugin2').someMethod();
...will only give you the data from the first element in the set. If you want to see the data for all three, you need to loop there, too:
$(".element").plugin2().each(function() {
$(this).data('plugin_plugin2').someMethod();
});
But fundamentally, what your code is doing is not how you implement methods in plugins (not least for this reason). Instead, the usual way to implement methods in plugins is to have the main plugin method accept a string (the method name), e.g.:
$(".element").plugin2().plugin2("someMethod");
thanks. so how does it look for boilerplate for doing this -$(".element").plugin2().plugin2("someMethod");
Here's a very minimal example:
(function($) {
var methods = {
init: function() {
// If you have to do different things on different
// elements, use this.each(...) or similar
this.css("color", "red");
return this;
},
color: function(color) {
// If you have to do different things on different
// elements, use this.each(...) or similar
this.css("color", color);
return this;
},
increment: function(color) {
// For example, this is effectively a `this.each(...)`:
this.text(function() {
return +$(this).text() + 1;
});
return this;
}
};
var slice = Array.prototype.slice;
$.fn.foo = function(method) {
var f = methods[method || "init"];
if (!f) {
throw "Unknown method for plugin `foo`: '" + method + "'";
}
return f.apply(this, slice.call(arguments, 1));
};
})(jQuery);
setTimeout(function() {
$(".element").foo();
}, 500);
setTimeout(function() {
$(".element").foo("color", "green");
}, 1000);
setTimeout(function() {
$(".element").foo("increment");
}, 1500);
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Related

Access originally clicked element in jQuery plugin

I have the following plugin, and while I wish it to be able to be applied to multiple elements, I do not wish to create a new dialog for each element.
But in the dialog.open callback or when the button is clicked, I wish to be able to access the element which was clicked and opened the dialog.
If I wanted to create multiple dialogs, I suppose I could put this.each(function () {...} in the init method and then this would be the individually clicked element, but as stated earlier, I only one one dialog.
EDIT. I revised the code so that it does what I need it to do. It just seems like a bit of a hack using data as I did. Is there a more proper way to do so?
How is this accomplished?
(function($){
var defaults = {};
var methods = {
init : function (options) {
var settings = $.extend({}, defaults, options);
var dialog = $('<div/>').dialog({
open: function( event, ui ) {
console.log(dialog.data('elementThatWasClicked'));
},
buttons: [
{
text: 'click',
click: function() {console.log(dialog.data('elementThatWasClicked'));}
}
]
});
return this.each(function () {
var $this=$(this);
$this.click(function(){dialog.data('elementThatWasClicked',$this).dialog('open')});
});
}
};
$.fn.test = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.test');
}
};
}(jQuery));
$(function(){
$('.bla').test();
});

jQuery plugins functions overwrite

I have implemented several jQuery plugins for my current project.
Since some plugins have functions with the same name, the one called in the last one defined.
Here is the definition of my first plugin:
$(function($)
{
$.fn.initPlugin1 = function(parameters)
{
var defaultParameters = {};
$(this).data('parameters', $.extend(defaultParameters, parameters));
return $(this);
};
$.fn.function1 = function(){ console.log('Function 1.'); };
$.fn.callFunction = function(){ $(this).function1(); };
});
And here is the definition of my second plugin:
$(function($)
{
$.fn.initPlugin2 = function(parameters)
{
var defaultParameters = {};
$(this).data('parameters', $.extend(defaultParameters, parameters));
return $(this);
};
$.fn.function2 = function(){ console.log('Function 2.'); };
$.fn.callFunction = function(){ $(this).function2(); };
});
I have also this scenario :
$("#div1").initPlugin1().callFunction();
$("#div2").initPlugin2().callFunction();
For this specific scenario the consoles shows: Function 2. Function 2.
In fact, since the callFunction() is also defined in the second plugin, this is the one used.
I would like some advise on what is the best way to solve this problem.
Is it possible to create a thing similiar to a namespace ?
Thank to #syms answer, I have created the following example.
Plugin1:
$(function($) {
$.fn.initPlugin1 = function() {
console.log('Initialized Plugin1');
return $(this);
};
$.fn.initPlugin1.testFunction = function() {
$(this).append('Function 1.');
};
});
Plugin2:
$(function($) {
$.fn.initPlugin2 = function() {
console.log('Initialized Plugin2');
return $(this);
};
$.fn.initPlugin2.testFunction = function() {
$(this).append('Function 2.');
};
});
Main:
(function($)
{
$(document).ready(
function()
{
$("#div1").initPlugin1(); //Run correctly
$("#div2").initPlugin2(); //Run correctly
$("#div1").initPlugin1.testFunction(); //Fail
$("#div2").initPlugin2.testFunction(); //Fail
});
})(jQuery);
When I run my code, I got the following error: Cannot read property 'createDocumentFragment' of null.
Apparently, the this object is corrupted.
you can try this,
$(function($) {
$.fn.initPlugin1 = function() {
console.log('Initialized Plugin1');
return $(this);
};
});
$(function($) {
$.fn.initPlugin2 = function() {
console.log('Initialized Plugin2');
return $(this);
};
$.fn.callFunction = function(param) {
$(this).append(param);
};
});
(function($) {
$(document).ready(
function() {
$("#div1").initPlugin1(); //Run correctly
$("#div2").initPlugin2(); //Run correctly
$("#div1").initPlugin1().callFunction('function1');
$("#div2").initPlugin2().callFunction('function2');
});
})(jQuery);

get variable from a jQuery Plugin

I need to know how is possible to get a plugin variable outside the plugin, to test it with some test framework.
So this is my simplified plugin:
(function ($) {
$.fn.extend({
myPlugin: function (argumentOptions) {
var defaults = {
image: 'img/default.png',
};
this.textSend = '';
var options = $.extend(defaults, argumentOptions);
var globalHere = this;
return this.each(function () {
obj.mouseup(function(e) {
globalHere.textSend = 'test';
});
});
}
});
})(jQuery);
I need to the variable this.textSend outside the plugin.
I have tried in this way:
$(document).ready(function(){
var testfield = $('.txt');
testfield.myPlugin({
image:"../img/twitter.png"
});
testfield.focus();
testfield.trigger($.Event( "mouseup"));
console.log($.fn.myPlugin.textSend);
});
but the console.log return me undefined
How can i get that variable outside?
Thanks
You will want to make sure you are returning this like so:
(function($) {
$.fn.extend({
myPlugin: function(argumentOptions) {
var self = this;
self.textSend = 'something';
self.inc = 0;
self.mouseup(function(e) {
self.textSend = 'new thing #' + self.inc;
self.inc++;
});
return self;
}
});
})(jQuery);
var instantiated = $('button').myPlugin({});
$('input').val(instantiated.textSend);
$('button').click(function(e) {
$('input').val(instantiated.textSend);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<label>Current textSend:</label>
<input />
<br/>
<button>Change textSend</button>
Hopefully will get you on the right track.
Update
Try new code.
You can store it inside the closed scope you created around your plugin and expose it through another function. Of course it'll need some refactoring, but this is the general idea:
(function ($) {
var whateverNameYouWant; //here
$.fn.extend({
myPlugin: function (argumentOptions) {
var defaults = {
image: 'img/default.png',
};
this.textSend = '';
whateverNameYouWant = this.textSend; //here
var options = $.extend(defaults, argumentOptions);
var globalHere = this;
return this.each(function () {
obj.mouseup(function(e) {
globalHere.textSend = 'test';
whateverNameYouWant = this.textSend; //here
});
});
}
});
$.extend({
getWhateverNameYouWant: function() {
return whateverNameYouWant;
}
})
})(jQuery);
var value = $.getWhateverNameYouWant();
At line console.log($.fn.myPlugin.textSend);
use testfield.textSend . now it has become proprty of selector via myplugin.

JQuery plugin - callback breaks other features

I'm trying to build a basic color picker plugin (mainly as an exercise to learn about plugin development). I have a callback called "onSelected" that fires when you pick a color, but it breaks another feature of the plugin (the ability to toggle the visibility of the swatch list).
I am new to plugin development so I'm sure it's a simple mistake I'm making...
jsfiddle
Plugin:
(function ($) {
$.colorPicker2 = function (el, options) {
// the wrapper around the colors
var $pickerContainer = $("<div>");
// To avoid scope issues, use 'base' instead of 'this'
// to reference this class from internal events and functions.
var base = this;
// Access to jQuery and DOM versions of element
base.$el = $(el);
base.el = el;
// Add a reverse reference to the DOM object
base.$el.data("colorPicker2", base);
base.init = function () {
console.log("base.init");
base.options = $.extend({}, $.colorPicker2.defaultOptions, options);
// Put your initialization code here
// code goes here
$.each(base.options.colors, function (index, value) {
var $item = $('<div class="colorPicker-colorOption">').css({
"background-color": "#" + value
})
$item.click(function () {
console.log("item.click");
base.selectColor(value);
})
$pickerContainer.append($item);
});
//$pickerContainer.hide();
base.$el.append($pickerContainer);
if (base.options.toggleElement != null) {
base.options.toggleElement.click(function (e) {
base.togglePicker();
e.preventDefault();
});
}
};
base.togglePicker = function()
{
$pickerContainer.toggle();
}
base.selectColor = function (color) {
base.togglePicker();
if (typeof base.options.onSelected == 'function') {
base.options.onSelected.call(this, color);
}
}
// Sample Function, Uncomment to use
// base.functionName = function(paramaters){
//
// };
// Run initializer
base.init();
};
$.colorPicker2.defaultOptions = {
colors: [
'000000', '993300', '333300', '000080', '333399', '333333', '800000', 'FF6600',
'808000', '008000', '008080', '0000FF', '666699', '808080', 'FF0000', 'FF9900',
'99CC00', '339966', '33CCCC', '3366FF', '800080', '999999', 'FF00FF', 'FFCC00',
'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0', 'FF99CC', 'FFCC99',
'FFFF99', 'CCFFFF', '99CCFF', 'FFFFFF'
],
toggleElement: null,
onSelected: function (color) { }
};
$.fn.colorPicker2 = function (options) {
return this.each(function () {
(new $.colorPicker2(this, options));
});
};
})(jQuery);
How I hook into the onSelected event:
$(function () {
$('#primaryColorPicker').colorPicker2({
toggleElement: $('#selectPrimaryColor'),
onSelected: function (color) {
$('#selectedPrimaryColor').html("(#" + color + ")");
}
});
});
The HTML:
<a id="selectPrimaryColor">Toggle Color Picker</a>
<span id="selectedPrimaryColor" />
<div id="primaryColorPicker"></div>
You just have to learn how to write valid HTML
replace
<span id="selectedPrimaryColor" />
with
<span id="selectedPrimaryColor"></span>
FIDDLE

jQuery retrieve parameter from function call

$(document).ready(function(){
$('#cumulative-returns').graph({
width: 400,
height: 180,
graphtype: 'bar'
});
});
I have a binded a function on click to #cumulative-returns and I want to be able to get the graphtype value like..
$('#cumulative-returns').click(function() {
alert(this.graphtype)
});
Is this possible or how else would you go about it? Maybe have some code in the graph function that stores the parameters in some global array (messy but feasable)?
*edit: here is the graph function:
(function($) {
$.fn.graph = function(options) {
return this.each(function() {
var defaults = {
name: $(this).attr('id')
};
var opts = $.extend(defaults, options);
var img = this;
$.post('../generate_graph.php', opts);
});
};
})(jQuery);
(function($) {
$.fn.graph = function(options) {
return this.each(function() {
var defaults = {
name: $(this).attr('id')
};
var opts = $.extend(defaults, options);
var img = this;
$(this).data('graphtype', opts.graphtype); // Addition!
$.post('../generate_graph.php', opts);
});
};
})(jQuery);
Then just do:
$('#cumulative-returns').click(function() {
alert($(this).data('graphtype'));
});
You do get the dom element that has been clicked stored in this. Then I don't know if it has the graphtype method linked to it, it all depends on how .graph() behaves.

Categories