I want to be a javascript programmer, so I am trying to read and understand the code in chosen plugin.
I know how to create a jquery plugin, and I have read about the module pattern,
yet this code is unclear to me:
//...
attaching to jQuery object
//...
$.fn.extend({
chosen: function(options) {
return $(this).each(function(input_field) {
if (!($(this)).hasClass("chzn-done")) {
return new Chosen(this, options);
}
});
}
});
//...
//...
//...
Chosen = (function() {
__extends(Chosen, AbstractChosen);
function Chosen() {
Chosen.__super__.constructor.apply(this, arguments);
}
// ...
// attaching various events
// ...
return Chosen;
})();
If Chosen is a self invoked function - why init it using new statement?
Thanks
Chosen in the outer scope is the function/constructor returned from the inner scope that comes from the "self invoked function". That's why it's called with new.
Related
I try to work with RequireJS and AMD module definition and have write a module that do my things in object format i think.
(i went from jquery and have not study a OOP javascript well)
myModule.js
define([
jquery,
datepicker,
], function ($, datepicker) {
var myModule = {
debug: true,
lang: 'auto',
initModule: function (element) {
myModule.element = element;
},
// ... other methods
}
return myModule;
});
And it work well, but if i try to use it for more than one elements/time it override him self, and i can't use it more than one time in same page.
main.js
requirejs(['MyModule'],
function (MyModule) {
// all the elements on page
$elements = $('.element');
$elements.each(function () {
MyModule.initModule($(this));
});
});
When i have more than one <div class="element"> on page only the last one work, i think because my module is override him self.
I tried to add new MyModule() but have a error TypeError: MyModule is not a constructor
I think i need to add a constructor or something else, in any case have a instance of my module to use instead of the object (that i think are precompiled by requirejs and returned ready for work). Any helps are good, many thanks in advance!
Ok! For do that! I completely refactor my code, and instead of return a object in my module definition i prototyped a function for get after his instance and i create a constructor for reset the properties/vars:
myModule.js
define([
jquery,
datepicker,
], function ($, datepicker) {
// constructor
var myModule = function () {
// reset lang because it maybe was changed in previous instance,
// i think because javascript share this thing trough objects?
myModule.prototype.lang = 'auto';
}
myModule.prototype.debug = true
myModule.prototype.lang = 'auto';
myModule.prototype.initModule = function (element) {
myModule.element = element;
};
// ... other methods with `myModule.prototype.` prefix
return myModule;
});
Great, now i can call myModule trough new myModuel() syntax and have same functionality for different elements on page.
main.js
requirejs(['MyModule'],
function (MyModule) {
// all the elements on page
$elements = $('.element');
var p = 1, _mod = [];
$elements.each(function () {
_mod[p] = new MyModule();
_mod[p].initModule($(this));
p++;
});
});
This work for me, i not completely understand yet what i do, but my purpose are satisfated, i can reuse same module functionality for different elemnts on page.
Suggest me readings:?
I securely need to read something about OOP Javascript, prototype and how javascript manage instance/class/object/var in memory and namespaces.
I have a question regarding the structure of a jQuery plugin that I found.
For better understanding, here is a simplified example of the plugins structure:
// Regular constructor function
function MyPlugin() {
this.myValue = "My Value";
}
// Methods on the prototype
MyPlugin.prototype.showValue = function() {
alert($.myplug.getValue());
}
MyPlugin.prototype.getValue = function() {
return this.myValue;
}
// jQuery plugin
$.fn.myplug = function() {
// Why is is possible to access $.myplug here although it's not created yet?
return this.each(function() {
$(this).html($.myplug.getValue());
});
};
// Create new MyPlug instance
$.myplug = new MyPlugin();
// Calling the jQuery plugin on a DOM element
$('div').myplug();
For the most part, I get what is happening. The actual plugin logic seems to be written as a normal JavaScript "class".
This is followed by a jQuery plugin definition – I think, actually, some new method is added to jQuery's prototype. This is where things get tricky to me:
How is is possible to access the class instance inside the plugin, although the class is instantiated after the plugin definition? Is there a mechanism at work similar to variable hoisting?
In case you want to try something, here is a Fiddle of the example: http://jsfiddle.net/kq8ykkga/
$(this).html($.myplug.getValue()); isn't evaluated until you call $('selector').myplug(), executing the function body.
I try to move some common application specific actions to jQuery plug-in by:
$.fn.extpoint = function() {...}
But I don't want to declare several extension points:
$.fn.extpoint1 = function() {...}
$.fn.extpoint2 = function() {...}
...
Instead I would like to use syntax sugar like:
$("#id").extpoint.func1().extpoint.func2()
With definition:
$.fn.extpoint = {}
$.fn.extpoint.func1 = function() {
this.val();
this.data("ip");
...
return this;
}
and call:
$("#id").extpoint.func1(...)
this point to $.fn.extpoint (dictionary with func1, func2, ... elements) instead of original jQuery object, when func1 evaluated.
Is it possible to make jQuery plug-in extendible?
PS. It is possible to pass function name as first argument to $.fn.extpoint and implement $.fn.extpoint('extend', func) call to extend (save to internal dictionary association between names and implementations) extension point. In that case use-cases look like:
$("#id").extpoint('func1', ...).extpoint('func2', ...)
but I look for way to make in more syntactic sugar...
The task I ask is hard to implement.
Official docs say:
Under no circumstance should a single plugin ever claim more than one namespace in the jQuery.fn object:
(function( $ ){
$.fn.tooltip = function( options ) {
// THIS
};
$.fn.tooltipShow = function( ) {
// IS
};
$.fn.tooltipHide = function( ) {
// BAD
};
})( jQuery );
This is a discouraged because it clutters up the $.fn namespace. To remedy this, you should collect all of your plugin's methods in an object literal and call them by passing the string name of the method to the plugin.
Another approach is maintain link to this as in http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js
So your calls looks like:
$.fn.addPlugin('test2', {
__construct : function(alertText) { alert(alertText); },
alertAttr : function(attr) { alert($(this).attr(attr)); return this; },
alertText : function() { alert($(this).text()); return this; }
});
$('#test2').bind('click', function() {
var btn = $(this);
btn.test2('constructing...').alertAttr('id').alertText().jQuery.text('clicked!');
setTimeout(function() {
btn.text('test2');
}, 1000);
});
Some related links:
http://milan.adamovsky.com/2010/02/how-to-write-advanced-jquery-plugins.html
http://milan.adamovsky.com/2010/09/jquery-plugin-pattern-20.html
http://ludw.se/blog/articles/19/patching-milans-jquery-plugin-pattern-for-jquery-16
http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js
Old style plug-in extention:
http://docs.jquery.com/Plugins/Authoring
jQuery Plugin Authoring and Namespacing
http://coding.smashingmagazine.com/2011/10/11/essential-jquery-plugin-patterns/
http://mahtonu.wordpress.com/2010/09/20/jquery-plugin-authoring-step-by-step/
http://www.capricasoftware.co.uk/corp/template.php
Here is an overview of creating a plugin. I believe what you are asking about is called "chaining". It is what makes jQuery so easy to use, and it's good that you want to make sure that you are implementing it correctly.
The key thing to remember while developing your plugin in regards to chaining is to always return this; from your methods. That is what will allow you to keep the chain going.
I am using a jQuery Class plugin as so :
jQuery(document).ready(function($) {
window.SSK.calendar = new(Class.extend({
filter_by_filtered_names: function() {
console.log('foobar!');
},
init: function() {
if ( window.location.href.match(/name_filters/) ) {
SSK.calendar.filter_by_filtered_names();
};
}
}))
});
For some reason this returns on load :
SSK.calendar is undefined
Which tells me that the plugin class is not loading before its own call. Very strange indeed. Curious if anyone knew a remedy?
The behaviour seems to make perfect sense to me, even if I don't know how Class works:
Class.extend(...) creates a new constructor function (I assume). new executes the constructor which in turn calls init. The result is assigned to window.SSK.calendar. You see, init is called upon instantiation and this happens before the instance is assigned to window.SSK.calendar.
Here is a simplified example:
function MyClass() {
this.bar = 'baz';
console.log(foo.bar);
}
var foo = new MyClass();
This will fail since foo is still undefined at the moment the constructor is called. The instance is the return value of the function call, hence foo cannot contain a reference to the instance before the call.
You might be able to solve your problem by simply using this to reference the instance:
init: function() {
if ( window.location.href.match(/name_filters/) ) {
// better in this case: if(/name_filters/.test(window.location.href))
this.filter_by_filtered_names();
};
}
The documentation of the plugin should mention how you can reference the instance from inside a method.
Seems you use two onReady listeners: jQuery(document).ready(fn) and $(fn) are exactly equivalent. Effectively, you will append the inner function to the end of the function queue when the outer function executes. When trying to access SSK.calendar in any onDOMready function that is not registered after that, it won't be available.
Example:
$(function(){
console.log("A");
$(function(){
console.log("B");
});
console.log("C");
});
$(function(){
console.log("D");
});
will log:
A
C
D
B
This is common task coming from object oriented programming, I would like to change behavior of JavaScript program by overriding existing function with possible calling it as well. I remember Windows introduced that as writing hooks and chaining them. So what I want, I have a web page which calls some onload hook which finally calls function initFields. I want to redefine this function however keep previous implementation. If I simply define my JS function as
function initFields() {
// do some stuff ...
// I do not know how to call super.initFields() here
}
I read something like you can write
initFields.prototype = function() {
// do some stuff ...
// but still have no idea how to call the original one
};
Can somebody help?
One option is
var initFieldsInitial = initFields;
function initFields() {
// your stuff
initFieldsInitial.apply(this, arguments);
}
You could try the wrap() function from the underscore.js library.
http://documentcloud.github.com/underscore/#wrap
var initFields = function() {
// do something
console.log('initFields');
}
initFields = _.wrap(initFields, function(initial) {
// do some stuff
console.log('wrapper');
initial();
});
$(document).ready(function() {
initFields();
});