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']);
Related
Following is my javaScript code.
var myObjfn = {
before : function(){
console.log("before");
},
loadA: function(){
console.log("loadA");
},
loadB: function(){
console.log("loadB");
},
loadC: function(){
console.log("loadC");
}
}
Whenever I call myObjfn.loadA(), it should call myObjfn.before() method before executing loadA method. Same for loadB() & loadC(). I don't want to explicitly call before() method in all loadA,loadB and loadC methods. Is there any option to achive this in javascript ?
You could do something like this. Which creates a wrapper function for each function in the object except the before function.
var myObjfn = { ... };
Object.keys(myObjfn).forEach(key => {
if (key === "before") return;
var oldFunc = myObjfn[key];
myObjfn[key] = function() {
myObjfn.before();
return oldFunc.apply(this, arguments);
};
});
myObjfn.loadA();
// "before"
// "loadA"
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());
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];
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);
}
}
}
Okay so we have a project ongoing, and it is to be passed today. But I have a problem.
This is the sample code:
output.js
var MapPrintDialog = Class.create();
MapPrintDialog.prototype = {
// 他の画面からテンプレート情報を更新するために呼ばれる。
comboReload : function() {
var val = tempComb.getValue();
tempComb.store.load({
callback: function(result, o) {
if (this.store.data.keys.indexOf(val) == -1) {
this.setValue(this.store.data.keys[0]);
this.fireEvent("select", this);
}
}.createDelegate(tempComb)
});
},
initialize : function(){
this.define();
},
define : function(){
var DrawPrintAreaFrame = function(mode, noUpdateStatusBarText){
var cs = getCurrentSetting();
if (mode == "init" || mode == "edit"){
PrintController.DrawMapPrintArea(cs.center.x, cs.center.y, cs.scale, cs.result.PrintMaps[0].Width, cs.result.PrintMaps[0].Height, cs.result.PageRowCount, cs.result.PageColumnCount, mode);
}
else if (mode == "delete"){
PrintFrameManager.ClearPrintFrame();
}
if (noUpdateStatusBarText) {
gisapp.noUpdateStatusBarText = true;
}
gisapp.refreshMap();
}
}
Now my problem is, how will I call "DrawPrintAreaFrame" from another js file?
I tried:
MapPrintDialog.prototype.define().DrawPrintAreaFrame("edit");
MapPrintDialog.prototype.define.DrawPrintAreaFrame("edit");
MapPrintDialog.define().DrawPrintAreaFrame("edit");
MapPrintDialog.define.DrawPrintAreaFrame("edit");
MapPrintDialog.DrawPrintAreaFrame("edit");
DrawPrintAreaFrame("edit");
but it gives me an error lol. How will I fix this? Please don't be too harsh, I just started learning javascript but they gave me an advanced project which isn't really "beginner" friendly XD
EDIT ----------------------
Okay now i tried to modify it like this:
var MapPrintDialog = Class.create();
MapPrintDialog.prototype = {
// 他の画面からテンプレート情報を更新するために呼ばれる。
comboReload : function() {
var val = tempComb.getValue();
tempComb.store.load({
callback: function(result, o) {
if (this.store.data.keys.indexOf(val) == -1) {
this.setValue(this.store.data.keys[0]);
this.fireEvent("select", this);
}
}.createDelegate(tempComb)
});
},
initialize : function(){
this.DrawPrintAreaFrame("edit");
}
}
function DrawPrintAreaFrame(mode, noUpdateStatusBarText){
var cs = gisapp.getCurrentView();
if (mode == "init" || mode == "edit"){
PrintController.DrawMapPrintArea(cs.center.x, cs.center.y, cs.scale, cs.result.PrintMaps[0].Width, cs.result.PrintMaps[0].Height, cs.result.PageRowCount, cs.result.PageColumnCount, mode);
}
else if (mode == "delete"){
PrintFrameManager.ClearPrintFrame();
}
if (noUpdateStatusBarText) {
gisapp.noUpdateStatusBarText = true;
}
gisapp.refreshMap();
}
But it gives me: Javascript runtime error: Object doesn't support property or method 'DrawPrintAreaFrame'
You have 2 different way:
1- you have to first change it like this:
define : function(){
var DrawPrintAreaFrame = function(mode, noUpdateStatusBarText){
//You function code
}
this.getDrawPrintAreaFrame = function(){
return DrawPrintAreaFrame;
}
}
then create your object using your class:
var obj = new MapPrintDialog();
obj.define();
obj.getDrawPrintAreaFrame().call(obj, "edit");
2- remove the define method and add your function to prototype:
MapPrintDialog.prototype.DrawPrintAreaFrame = function(){
//your function code
}
create your object and simply call your method like this:
var obj = new MapPrintDialog();
obj.DrawPrintAreaFrame("edit");
It's funny, because I said you have 2 ways, and the third one just came up:
3- as far as you use Prototype framework you can use MapPrintDialog.addMethods, which is there to be used to add new instance methods to your class, remove your define and DrawPrintAreaFrame functions and add this:
MapPrintDialog.addMethods({
DrawPrintAreaFrame: function DrawPrintAreaFrame(){
//your code
}
});
or even without removing your method you can use it like:
define : function(){
var DrawPrintAreaFrame = function(mode, noUpdateStatusBarText){
//You function code
}
MapPrintDialog.addMethods({ DrawPrintAreaFrame: DrawPrintAreaFrame });
}
and create your instance and call the method:
var obj = new MapPrintDialog();
obj.DrawPrintAreaFrame("edit");
4- try this if you need your function like a sort of static method, without needing to create a instance:
MapPrintDialog.DrawPrintAreaFrame = function(){
//You function code
}
and call it like this
MapPrintDialog.DrawPrintAreaFrame("edit");
and if you want to define it in runtime, add the whole definition to your define method like this:
define : function(){
MapPrintDialog.DrawPrintAreaFrame = function(){
//You function code
}
}