I have modularized my Javascript code in this style:
var groupHandler = function( constructorOptions )
{
"use strict";
var init = function( optionsToSet )
{
jQuery.extend( options, optionsToSet);
return this;
};
var newGroup = function()
{
}
var call = {
init: init,
options: options,
newGroup: newGroup
};
if(typeof myPublicTestNamespace == "undefined"){//http://stackoverflow.com/a/9172377/123594
return {
init: init,
newGroup: newGroup
};
}else{
return call;
};
init( constructorOptions );
};
In one of my modules I have a list of functions from other modules to call like this:
validatorFunctions = call.getLocalStorageArray( 'validatorFunctions', model);
for (var f=0;f < validatorFunctions.length;f++){
if (callFunction = call.getFunction( validatorFunctions[f] )){
valid = callFunction( loopRowId, fields, call );
if (!valid) break;
}
}
I'd like to be able to call functions in other modules by using a "." syntax in my function call name:
var getFunction = function( functionName )
{
if (functionName.indexOf( '.' ) != -1){
var functionParts = functionName.split( '.' );
var classFunction = functionParts[1];
if (typeof window[functionParts[0]] === "function") {
var obj = new window[functionParts[0]]();
return obj['classFunction']; <!----- how to return function here?
}
}else{
if (typeof (window[functionName]) === "function") {
return window[functionName];
}
}
return false;
};
but I can't figure out how to return the function based on the class object and the function name?
It's possible that part or all of the problem is this:
return obj['classFunction'];
// ^^ Equivalent to obj.classFunction. In other words, reading a property
// called `classFunction`, not reading a property whose name is the value
// of the `classFunction` variable you set.
I haven't analyzed the code enough to fully understand it, but based on the context it seems that you'd mean this:
return obj[classFunction];
Related
Lets say I have a javascript object with the the following
var Settings = function () {
this.timelimit = 0;
this.locked = false;
this.expires = null;
this.age = null;
};
And then I set some get/set functions like:
Settings.prototype = {
getAllAges: function () {
return self.age;
},
getTimeLimit: function () {
return self.timelimit;
},
load: function() {
data_from_local_storage = LoadLocalStorage();
}
}
In data_from_local_storage I have JSON variables that match the above variables (timelimit, locked etc .. )
Issue is, the object var settings_ref = Settings() have all these 4 variables - but also have these 3 functions assigned in settings_ref - due to this OO behavior I need to write inside the load() function:
this.timelimit = data_from_local_storage.timelimit
this.age = data_from_local_storage.age
this.locked = data_from_local_storage.locked
Because if I'll write
this = data_from_local_storage it will destroy my object.
So how can I avoid writing all these variables one-by-one ?
w/o a for loop inside a function
in this example are just 4 but there are much much more and I cannot write it everywhere everytime
I'm looking for some .update() function like in Python or something ..
Any quick shortcut that someone know ?
You can use Object.assign() in ES2015:
load: function() {
Object.assign(this, LoadLocalStorage());
}
It's apparently not supported yet in IE, but there's a polyfill on the MDN page:
if (typeof Object.assign != 'function') {
(function () {
Object.assign = function (target) {
'use strict';
// We must check against these specific cases.
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
})();
}
(Personally I would use Object.defineProperty() to add the method, but that's verbatim from MDN.)
(edit though I guess if you don't have Object.assign() you may not have Object.defineProperty() either :)
If you store the data inside another object literal, it makes persisting things to localstorage and back a lot easier.. Here is an example..
//pretend local storage loader
function LoadLocalStorage() {
return {
timelimit: 100,
locked: true,
expires: new Date(),
age:40
}
}
var Settings = function () {
this.data = {
timelimit: 0,
locked: false,
expires: null,
age:null
}
};
Settings.prototype = {
getAllAges: function () {
return this.data.age;
},
getTimeLimit: function () {
return this.data.timelimit;
},
load: function() {
this.data = LoadLocalStorage();
}
}
var settings = new Settings;
console.log('Age before our load');
console.log(settings.getAllAges());
settings.load();
console.log('Age after our load');
console.log(settings.getAllAges());
Recently I came across a simple Command pattern implementation in JavaScript that uses function as an object instead of pure object to define functionality:
var CommandManager = (function() {
function CommandManager() {}
CommandManager.executed = [];
CommandManager.unexecuted = [];
CommandManager.execute = function execute(cmd) {
cmd.execute();
CommandManager.executed.push(cmd);
};
CommandManager.undo = function undo() {
var cmd1 = CommandManager.executed.pop();
if (cmd1 !== undefined){
if (cmd1.unexecute !== undefined){
cmd1.unexecute();
}
CommandManager.unexecuted.push(cmd1);
}
};
CommandManager.redo = function redo() {
var cmd2 = CommandManager.unexecuted.pop();
if (cmd2 === undefined){
cmd2 = CommandManager.executed.pop();
CommandManager.executed.push(cmd2);
CommandManager.executed.push(cmd2);
}
if (cmd2 !== undefined){
cmd2.execute();
CommandManager.executed.push(cmd2);
}
};
return CommandManager;
})();
and the usage:
CommandManager.execute({
execute: function(){
// do something
},
unexecute: function(){
// undo something
}
});
//call unexecute of prev. command
CommandManager.undo();
//call execute of prev. command
CommandManager.redo();
My question would be, is there any advantages in defining CommandManager function this way, instead of directly defining properties on object literal and assigning it back to var CommandManager
The only use for that would be that you have a function that does absolutely nothing:
CommandManager(); // does nothing, returns undefined
Other than that, you can just as well write the code as an object literal and use this to avoid it being dependant on its own name:
var CommandManager = {
executed: [],
unexecuted: [],
execute: function execute(cmd) {
cmd.execute();
this.executed.push(cmd);
},
undo: function undo() {
var cmd1 = this.executed.pop();
if (cmd1 !== undefined){
if (cmd1.unexecute !== undefined){
cmd1.unexecute();
}
this.unexecuted.push(cmd1);
}
},
redo: function redo() {
var cmd2 = this.unexecuted.pop();
if (cmd2 === undefined){
cmd2 = this.executed.pop();
this.executed.push(cmd2);
this.executed.push(cmd2);
}
if (cmd2 !== undefined){
cmd2.execute();
this.executed.push(cmd2);
}
}
}
(function( $ ){
var methods = {
init : function( options ) {
var settings = $.extend({ //Объявление настроек по умолчанию, которые можно переопределить в вызове плагина
code: 7,
listHeight: 160,
placeholder: "925000000",
phoneNumber: ""
}, options);
},
getCode : function( ) {
return $(this).settings.code;
}
};
$.fn.telephoneNumber = 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 + ' не существует.' );
}
};
})( jQuery );
I need to refer to a variable code from a function getCode.
Function getCode returns nothing, how fix?
Since this in the call to your plugin will refer to the jQuery instance on which it was called, you can't use it to refer directly to your plugin's information.
The usual way to handle this is to store any information your plugin needs using jQuery's data function. Here's a simple example (this is loosely based in your code, but not an exact update of it; it's just an example):
(function ($) {
var methods = {
init: function (options) {
// Save settings using `data`
this.data("myplugin", $.extend({/*...*/}, options));
},
doSomething: function () {
// Get settings using `data`
var settings = this.data("myplugin");
// Use them...
}
};
var slice = Array.prototype.slice;
$.fn.myplugin = function (command) {
if (typeof command === "string") {
methods[command].apply(this, slice.call(arguments, 1));
} else {
methods.init.apply(this, arguments);
}
return this;
};
})(jQuery);
Live Example
Note that your code requires that the user call the plugin to initialize it, and then again to call a method on it, which I've reproduced above. So:
$("some selector").myplugin(); // Init
$("some selector").myplugin("doSomething"); // Use
You could auto-init with defaults if the user doesn't do that, by changing the plugin function like this:
$.fn.myplugin = function (command) {
if (typeof command === "string") {
if (!this.data("myplugin")) { // Not initialized?
methods.init.call(this); // Init with defaults
}
methods[command].apply(this, slice.call(arguments, 1));
} else {
methods.init.apply(this, arguments);
}
return this;
};
Here's that in action
settings has scope limited to init method as you've defined it there only. getCode function has no access to this variable.
Just define the settings globally, and you can access it in getCode.
Overview
I am trying to find the jQuery function that matches a selection attribute value and run that function on the selection.
Example.
$('[data-store="' + key + '"]').each(function() {
var $callback = $(this).attr('data-filter');
if($callback != null) {
var fn = window['$.fn.nl2br()'];
if(jQuery.isFunction(fn)) {
$(this).fn();
}
}
$(this).setValue(value);
});
Problem 1
I'm not sure how to create a jQuery function call from string.
I know I can call the function like this, $(this)'onclick'; however I have no way to check if it exists before trying to call it.
Normally I could do this:
var strfun = 'onclick';
var fn = body[strfun];
if(typeof fn === 'function') {
fn();
}
This seems to fail:
var fn = window['$.fn.nl2br()'];
if(jQuery.isFunction(fn)) {
$(this).fn();
}
EDIT:
I seem to be having success doing this:
if($callback != null) {
var fn = $(this)[$callback]();
if( typeof fn === 'function') {
$(this)[$callback]();
}
}
Problem 2
Using jQuery.isFunction() how do you check if a methods exists? can you do this with jQuery.isFunction()?
Example
Declare function:
$.fn.nl2br = function() {
return this.each(function() {
$(this).val().replace(/(<br>)|(<br \/>)|(<p>)|(<\/p>)/g, "\r\n");
});
};
Test if function existe, these options fail:
jQuery.isFunction($.fn.nl2br); // = false
jQuery.isFunction($.fn['nl2br']()); //false
Functions in JavaScript are referenced through their name just like any other variables. If you define var window.foobar = function() { ... } you should be able to reference the function through window.foobar and window['foobar']. By adding (), you are executing the function.
In your second example, you should be able to reference the function through $.fn['nl2br']:
$.fn.nl2br = function() {
return this.each(function() {
$(this).val().replace(/(<br>)|(<br \/>)|(<p>)|(<\/p>)/g, "\r\n");
});
};
console.log(jQuery.isFunction($.fn['nl2br']));
See a working example - http://jsfiddle.net/jaredhoyt/hXkZK/1/
var fn = window['$.fn.nl2br']();
and
jQuery.isFunction($.fn['nl2br']);
I am using custom javascript functions provided at this link (http://km0.la/js/mozXPath/) to implement particular XML functionality in FireFox.
Here is the code:
// mozXPath
// Code licensed under Creative Commons Attribution-ShareAlike License
// http://creativecommons.org/licenses/by-sa/2.5/
if( document.implementation.hasFeature("XPath", "3.0") ) {
if( typeof XMLDocument == "undefined" ) { XMLDocument = Document; }
XMLDocument.prototype.selectNodes = function(cXPathString, xNode) {
if( !xNode ) { xNode = this; }
var oNSResolver = this.createNSResolver(this.documentElement);
var aItems = this.evaluate(cXPathString, xNode, oNSResolver,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var aResult = [];
for( var i = 0; i < aItems.snapshotLength; i++) {
aResult[i] = aItems.snapshotItem(i);
}
return aResult;
}
XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode) {
if( !xNode ) { xNode = this; }
var xItems = this.selectNodes(cXPathString, xNode);
if( xItems.length > 0 ){ return xItems[0]; }
else{ return null; }
}
Element.prototype.selectNodes = function(cXPathString) {
if(this.ownerDocument.selectNodes) {
return this.ownerDocument.selectNodes(cXPathString, this);
}
else { throw "For XML Elements Only"; }
}
Element.prototype.selectSingleNode = function(cXPathString) {
if(this.ownerDocument.selectSingleNode) {
return this.ownerDocument.selectSingleNode(cXPathString, this);
}
else { throw "For XML Elements Only"; }
}
}
Assuming the XML object has been defined and loaded with XML content, here is an example of how one would access a an XML tag named "cd_rank":
var cd_rank_XMLObj = XMLObj.selectSingleNode("cd_rank");
What I want to do is add the property "nodeTypedValue" to the selectSingleNode() function, but I'm not sure how to do this. In the Element.prototype.selectSingleNode function, I tried adding:
this.prototype.nodeTypedValue = this.textContent;
However, it's giving me an error saying it's undefined. I even tried adding it outside of the function, just to dumb it down and get the concept, and it also says it's undefined:
var XMLObj.selectSingleNode.prototype.nodeTypedValue = XMLObj.textContent;
alert(XMLObj.selectSingleNode("cd_rank").nodeTypedValue);
Essentially what I'm trying to do, I suppose, is add a prototype property to a prototype function. But I need some help with this. How can i add "nodeTypedValue" such that I write "XMLObj.selectSingleNode(Path).nodeTypedValue"?
Okay, I think I figured out how to add it inside the function, probably due more to luck than logic:
Element.prototype.selectSingleNode = function(cXPathString){
if(this.ownerDocument.selectSingleNode) {
var result = this.ownerDocument.selectSingleNode(cXPathString, this);
if (result != null) {
result.nodeTypedValue = result.textContent;
}
return result;
}
else{throw "For XML Elements Only";}
}