JQuery Extended Object Issue - javascript

I have 3 JQuery plugins which are similar to this
$(function() {
var Plugin1/2/3 = {
fun1:{}
fun2:{}
...
init: function()
{
o = $.extend({}, this);
}
}
$.fn.Plugin1/2/3 = function(){
return this.each(function(){
var obj = Object.create(Plugin1/2/3);
obj.init();
});
}
}
$(document).ready(function() {
$(document).Plugin1();
$(document).Plugin2();
$(document).Plugin3();
});
Everywhere i have used variable o to extend. What happens is when Plugin3 is created all the objects of above two plugins gets overwritten and all information shown are of the 3rd Plugin.
I am looking for a solution to this as well as some good guides on Jquery Advance plugin creation.
Pastebin Link: http://pastebin.com/GJTEEjyt
Result:
Thanks.

That's what happens when you take var for granted!
init: function() {
var o = $.extend({}, this);
}
And re: jQuery plugin, I have been using this for a while now. Take a look.

Related

how to write object-oriented jQuery plugins?

So I have a bit of experience writing normal plugins to do whatever, but I want to move towards an object-based event-driven system that can be more dynamic and customizable for the end user. For the sake of my question I have written up a small plugin that simply highlights text on the $(selector).hover() event.
Here is the JS/jQuery:
(function($) {
var objs = [];
var defaults = {
color: "blue",
normal: "black",
onHover: function() {},
offHover: function() {}
};
var Text = function (settings, self) {
this.self = $(self);
this.color = settings.color;
this.normal = settings.normal;
this.show = function () { this.self.css( "color", this.color); }
this.noShow = function () { this.self.css( "color", this.normal);}
this.onHover = settings.onHover;
this.offHover = settings.offHover;
};
$.fn.myPlugin = function(opts) {
this.each(function() {
var settings = $.extend({}, defaults, opts);
$(this).data('index', objs.push(new Text(settings, this)) -1);
// I feel like this should be handled differently, maybe
// attach an event to the inside of the object?
});
this.hover(
function(e) {
objs[$(e.currentTarget).data('index')].show();
objs[$(e.currentTarget).data('index')].onHover();
}, function(e) {
objs[$(e.currentTarget).data('index')].noShow();
objs[$(e.currentTarget).data('index')].offHover();
});
};
}(jQuery));
Basically, this line...
(this).data('index', objs.push(new Text(settings, this)) -1);
...could be handled much differently and more efficiently. The problem is I need a global array that holds all objects generated by the plugin. So if I call the plugin twice on two separate 'p' tags, then there should be two objects in that array, so on so forth. Right now, that aspect is 'working' but I need to store a reference to what index that object is at by attaching an 'index' data type to the DOM element. This feels like a very wrong way to have an object oriented approach. So how can I, on an event, trigger the function...
myObject.show();
...where myObject is a reference to the element in the array that I want to highlight.
I hope my question is clear, it is a weird issue to describe I feel, but also a very powerful concept if it can be applied the way I am thinking of it. Let me know if anything is unclear and I would be happy to clarify.
In doing a bit more reading and trying to understand how object oriented programming works in respect to javascript, jquery and the DOM, I stumbled upon my own answer. Here is what the code looks like for anyone that may have been as confused as I was going into plugin development:
(function($) {
var defaults = {
color: "blue",
normal: "black",
onHover: function() {},
offHover: function() {}
};
var Text = function(opts, self) {
var settings = $.extend({}, defaults, opts);
this.self = $(self);
this.color = settings.color;
this.normal = settings.normal;
this.onHover = settings.onHover;
this.offHover = settings.offHover;
this.show = function () { this.self.css( "color", this.color); };
this.noShow = function () { this.self.css( "color", this.normal); };
};
$.fn.myPlugin = function(opts) {
this.each(function() {
this.text = new Text(opts, this);
});
this.hover(
function() {
this.text.show();
this.text.onHover.call();
}, function() {
this.text.noShow();
this.text.offHover.call();
});
};
}(jQuery));
The issue I was dealing with was an appropriate understanding of name space and closure, as well as what things you can and cannot do with DOM elements. I am not sure if this is the common way or not, but it is working very well for my uses and might work for yours.

create jquery extension. problems with scope

I create a simple jQuery extension(it's my first).
(function($){
var MyClass = function(opt){
//..
};
//one of the methods of my extension
$.fn.myExtension = function(opt){
this._ext = new MyClass(opt);
return this;
};
$.fn.myExtensionOtherMethod = function(){
if(this._ext){
//do something ..
}
return this;
};
}(jQuery));
//using ..
$(document).ready(function(){
$('#selector').myExtension({
//options ..
});
$('#selector').myExtensionOtherMethod();
});
when i invoke method $('#selector').myExtensionOtherMethod();, this does not contains this._ext variable. I know that this is other scope, but i know that there is some way to access that variable in both methods.how can i do it?
This isn't really a scope issue. This is because the jQuery prototype $.fn gives you a jquery object as this. Even though you are selecting the same element each time its a new jQuery object set as the context so that property is gone. You can put that property on the DOM element and achieve the outcome you want.
(function($) {
var MyClass = function(opt) {};
//one of the methods of my extension
$.fn.myExtension = function(opt) {
this[0]._ext = new MyClass(opt);
return this;
};
$.fn.myExtensionOtherMethod = function() {
if (this[0]._ext) {
//do something ..
}
return this;
};
}(jQuery));
//using ..
$(document).ready(function() {
$('#selector').myExtension({
//options ..
});
$('#selector').myExtensionOtherMethod();
});
This is just a quick example above. If your selector finds more than one element you should loop though them. But I only grabbed the first index since you were selecting by ID.
Fiddle: https://jsfiddle.net/AtheistP3ace/gd1ehk0d/
As mentioned above by #charlietfl, I agree with that comment. Happy to explain why what you did didn't work but there may be better ways to achieve what you are looking for.

Knockoutjs nested view models

I'am using Knockoutjs and have a problem getting access to root/parent models data in a submodel. The data I get via Ajax.
The Ajax success creates a new WeekViewModel and this creates a few RowViewModels. And here is my Problem, at this time week is not defined.
After the site is rendered, I can get the Infos over week.
The only solution I've found is pasting the parent and root into the submodel.
But this works not so well cause at the initialsation, the parent is a plain js Obeject. After the site is rendered, and I will paste another rowViewModel from a click event, the parent is a knockout object.
Can anyone give me some suggestions where I'va made a mistake? Or whats a way to get this fixed?!
Here's my code:
$(function() {
var week;
var weekData;
$.when(
$.get('js/dataNew.json', function (res) {
weekData = res;
}),
// another calls ...
).then(function () {
week = new WeekViewModel(weekData);
ko.applyBindings(week, $('#content').get(0));
});
function WeekViewModel(data){
var self = this;
var mapping = {
'Rows': {
create: function(options) {
return new RowViewModel(options.data, self);
}
}
};
this.allDays = allDays;
this.cats = new ko.observableDictionary();
// more code ...
ko.mapping.fromJS(data, mapping, this);
};
function RowViewModel(row, parent){
var self = this;
var mapping = {
'RowDays': {
create: function(options) {
return new DayModel(options.data, self, parent);
}
}
};
if(row){
if(!row.DisplayName) {
// need data from the root here
// parent.cats <---
}
}
// more code ...
ko.mapping.fromJS(row, mapping, this);
}
// another submodel ...
});
Update:
fiddle:
http://jsfiddle.net/LkqTU/23750/
updated fiddle with html:
http://jsfiddle.net/LkqTU/23753/

Calling a function in a jquery plugin

I am trying to get the object of a jquery plug in I'm making use of. I want to eventually be able to add features to the plugin to suit my needs. I am currently having a problem with calling one the functions I defined in the plug in. Here is the skeleton of the code I have:
;(function($) {
$.fn.myPlugin = function(o) {
.//Implementations here
.
.
var Ex = function(e){
//implementations here
};
};
})(jQuery);
The reason I want this function inside is because I want access to some of the variables defined. I would like be able to call function Ex from my html file but whatever I tried so far hasn't worked. An example of what I have tried is:
$.fn.myPlugin.Ex("x");
No return statement anywhere. I'm not great at javascript or jquery but I'm trying to learn. Any help in explaining what I'm doing wrong is appreciated.
Your plugin design pattern is wrong.
To achieve what you want, you can use this common one :
;(function($){
var methods = {
init: function() {
//stuff
},
function1: function() {
//stuff
},
function2: function(opt) {
//stuff
}
};
$.fn.myPlugin= 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);
}
};
})(jQuery);
With this structure :
$.fn.myPlugin(); will call init()
$.fn.myPlugin("function1"); will call function1()
$.fn.myPlugin("function2",option_exemple); will call function2(opt)
Disclaimer : I use this very often, but it's not mine. Can't remember where I found it*.
edit : http://docs.jquery.com/Plugins/Authoring , thanks to Beetroot-Beetroot for the reminder !

Adding a function to one jQuery/DOM element

I am authoring a plugin which instantiates a map. The map would then provide a function to move to another place on the earth.
The script makes the map just fine. However I can't "tack" the function on the element, to be used by another plugin in a callback.
Here's the approach I tried; in plugin:
(function($){
$.fn.mapDo(options){
map = new BlahMap(this.get(0));
this.moveTheMap = function(place){
map.moveItToThat(place);
}; // nope.
}
})(jQuery);
Then, in view:
$(map).mapDo();
$(otherElement).otherControl({
callback: function(place){
$(map).moveTheMap(place); // moveTheMap is not there on $(map)!
}
};
The Question
How do I add a function to the map jQuery or DOM element, if possible? If not, how can I provide that kind of functionality?
More importantly, am I going the right way here by separating the things that way? I'm a bit of a neophyte to Javascript, how are these tasks usually done while still keeping the components apart?
While that's the stab I took at it, more generally, I struggled with the concept of outputting things from a jQuery plugin while maintaining chainability. In this case, what I am trying to do is to output a callback from the plugin that will work on the called element later in the execution.
Plugins normally only add one method to the jQuery prototype, and the method calls to the plugin's instances are done with strings.
(function($) {
$.fn.mapDo = function(options) {
var args = [].slice.call(arguments, 1); //Get all the arguments starting from 2nd argument as an array
return this.each(function() {
var $this = $(this),
instance = $this.data("map-instance");
if (!instance) {
$this.data("map-instance", (instance = new BlahMap(this, options)));
}
if (typeof options == "string") {
instance[options].apply(instance, args);
}
});
};
})(jQuery);
$(elem).mapDo( "moveTheMap", place ); //This would also instantiate the plugin if it wasn't instantiated
Here's jsfiddle showing it in action:
http://jsfiddle.net/X8YA8/1/
You could store the map with .data method.
(function($){
$.fn.mapDo = funciont(options) {
this.data('map', new BlahMap(this.get(0)));
return this;
};
$.fn.moveTheMap = function(place) {
var map = this.data('map');
if (map) {
map.moveItToThat(place);
}
return this;
};
})(jQuery);

Categories

Resources