Function name from a variable in Javascript - javascript

I create a context-menu from an array like this:
var menu1 = [
{
'OPTION1':function(menuItem,menu) {
// code for OPTION1
}
},
{
'OPTION2':function(menuItem,menu) {
// code for OPTION2
}
}
];
When the user right-clicked on my webpage, a menu appears with the options OPTION1 and OPTION2.
I need to change dynamically the function name, because it's the context-menu option text. Is there any way to declare the function name as a variable?
This is what I want:
var optionsletters = {};
optionsletters['option1'] = 'option_one';
optionsletters['option2'] = 'option_two';
var menu1 = [
{
optionsletters['option1']:function(menuItem,menu) {
// code for OPTION1
}
},
{
optionsletters['option2']:function(menuItem,menu) {
// code for OPTION2
}
}
];
EDIT#1: This is the plugin I've been using jQuery ContextMenu Plugin
EDIT#2: I need this to allow change language from spanish to english and viceversa.

You can't use the object literal notation to set arbritrary properties as you seem to try in the second example. This doesn't stop you from setting the property manualy:
function make_menu_item(name, func){
var item = {}; //Create an empty object
item[name] = func; //Assign the property with the name you choose
//(obj['option1'] is equivalent to obj.option1 in Javascript)
return item;
}
var menu = [
make_menu_item('option1', function () {...}),
make_menu_item('option2', function () {...})]

What about something like:
var name = 'option_one',
optionsletters = {};
optionsletters[name] = function() { ... };

Are you asking if you can change the key from 'OPTION1' : function() {} to 'option1' : function() {} ? If so you can just copy the function to a new variable onclick. If what you're asking is to be able to call something 'option1' as a string like option1 but actually call OPTION1(){} you can try a few different things. One you could make your array like so arr[{'name' : 'option1', 'func' : function(){} }] Then you could reference array[0].name and array[0].func.
With your current code it looks like you're blowing out your functions with strings.
JS is super expressive so there are a million ways to do anything. Functions are first-class objects so can be passed as parameters and even returned from functions.

Related

Square brackets after object creation

I have a problem with the following code:
// At the beginning
var prog = {}
// some attributes of prog and other methods
// ...
prog.stateChange = function(state)
{
var functionOfState =
{
onState1: function()
{
// some code
},
onState2: function()
{
// some code
}
}['on'+state]()
}
Which purpose have these square brackets after the creation of the object functionOfState? Is this an array of possible methods?
Sorry, I'm a total newbie in JS and I haven't found any information about this.
I really appreciate any help.
This code does almost the same as:
var functionOfState =
{
onState1: function()
{
// some code
},
onState2: function()
{
// some code
}
}
functionOfState['on'+state]();
It simply creates an object which stores different functions. Then, it calls one of them according to the current value of state.
Maybe, this one will be even easier:
var functionOfState = {};
functionOfState['onState1'] = function() {
// someCode
};
functionOfState['onState2'] = function() {
// someCode
};
functionOfState['on'+state](); // when state is 'State2', 'onState2' will be called
The difference that in your code it doesn't store this object with functions, but calls it directly.
This is (not the most clear) way to extract field from an object.
in JS, the subscript operator ([]) can extract a property out of an object just like the dot operator (.), so the following expressions are equal:
var obj = { field : value };
obj.field == obj["field"]; //returns true
on your example an object with the fields onState1, onState2 is created. then, using the subscript operator the correct property is extract. it is equivilant on writing
prog.stateChange = function(state)
{
var temp =
{
onState1: function()
{
// some code
},
onState2: function()
{
// some code
}
};
var functionOfState = state == onState1 ? temp.onState1 : temp.onState2;
functionOfState();
}
This is not a legit way to extract a property/method out of an object. basically if someone changes the name of the method, the code breaks. it is much better to simply use a switch case.

jQuery style getter and setters

I have a constructor Dropdown which will take an array as a parameter. This parameter will be used by a method attached to the prototype. The parameter is an array which should be turned into a parameter of jQuery option objects, which should be the drop down menu options for the select element. Currently I have:
function Dropdown(data) {
this.sel = $('<select>');
}
Dropdown.prototype.options = function (options) {
var self = this; //using $(this) doesn't work either
if ( !options ) {
//if null return the current values of
return self.sel.html();
} else {
//make a jQuery option object out of every item in the array
//set the sel property's html to that
self.sel.html = ($.map(options, function (val) {
return $('<option>').text(val).val(val);
}));
}
}
var testArray = ['one', 'two', 'three'];
var dropdown = new Dropdown(testArray);
dropdown.sel.appendTo($('body'));
console.log(dropdown.options()); //nothing outputted to the console
by passing testArray into the Dropdown constructor this should set the html property of sel, but it doesn't and trying to use the jQuery style getter prints nothing to the console. dropdown is appended to the page, just with no options.
To start with, you're not calling the options function in the prototype. After calling it, some other bugs showed up.
self.sel.html = ($.map(options, function (val) {
return $('<option>').text(val).val(val);
}));
This turns self.sel.html into an array filled with jQuery option elements, which you're doing nothing with.
I changed it a little bit to get it working. See if it works for you. I believe it's easy to understand.
function Dropdown(data) {
this.sel = $('<select>');
this.options(data);
}
Dropdown.prototype.options = function (options) {
var sel = this.sel;
options && options.forEach(function ( val ) {
$('<option>').val(val).text(val).appendTo(sel);
});
}
Fiddle: http://jsfiddle.net/b7pvS/
Right now your constructor does nothing other than to create a select element in jQuery. You pass in the data parameter and do nothing with it. You simply need to add this.options(data); in the constructor and you should be good to go.
function Dropdown(data) {
this.sel = $('<select>');
this.options(data);
}

how to get a property name which represent a function in JS

This is some JS code
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr)
{
window[methodName] = function()
{
console.log(methodName);
}
}
My problem is that how to get the name of a function in JS.
In JS, use this.callee.name.toString() can get the function name. But in this situation, it is a null value. How can i get the 'funName' string?
Sorry, I didn't make it clear.
I want to create functions in a for loop, all these functions has almost the same implementation which need its name. But others can call these functions use different name.I want to know what methodName function is called.
it seems a scope problem.
Try this:
var methodArr = ['firstFunc','secondFunc','thirdFunc'];
for(var i in methodArr) {
var methodName = methodArr[i]; // <---- this line missed in your code?
window[methodName] = (function(methodName) {
return function() {
console.log(methodName);
}
})(methodName);
}
window['secondFunc'](); // output: secondFunc

Preset Options in Object and see if it doesn't exist in allowed properties

I am trying to make a preset list of options that are allowed in my object list. Here is code
var a = function(cmd, options){
var objList = [options.search ,options.demand];
if(!(options in objList)){
console.warn('Not an Allowed * in the options Property');
}
};
or should I do
var a = function(cmd, options){
var objList = [search , demand];
if(!(options in objList)){
console.warn('Not an Allowed option in the options Property');
}
};
Basically what I want to do is set that search and demand are allowed options in the options Property so later than can do
a('cmd',{
search:'',
demand:function() {
alert('Hello');
},
//warn that the next option is not allowed
quote: function() {
alert('quote of user');
}
});
If you are having trouble understanding what I am asking please ask and I will do my best to explain a bit more.
maybe writing it like so would be better?
var a = function(cmd, options){
options = {
theme: function(color) {
$('body').css('backgroundColor',color);
},
color:''
};
};
a('cmd',{
theme:'#000'//though this is not working?
});
You could check each property in options against an array of allowed options like this:
var a = function(cmd, options){
var allowedOptions = ["search", "demand"];
var hasDisallowedOptions = false;
for (option in options) {
if(allowedOptions.indexOf(option) === -1 ) {
hasDisallowedOptions = true;
break;
}
}
// if hasDisallowedOptions is true, then there is a disallowed option
};
jsfiddle with a couple test cases/examples
A one idea of passing arguments in an object is, that it allows you to choose which argument you want to use in a function, you can simply ignore extra properties in the options object. Hence you don't need to "filter" the properties of the argument either.
Let's assume you've a function like this:
var a = function (cmd, options) {
var theme = {
backgroundColor: options.bgColor,
color: options.color
}
// Do something with theme
// Notice also, that there was no use for options.extra in this function
}
Then you invoke a like this:
a('cmd', {
bgColor: '#ff0',
color: '#000',
extra: 'This is an extra property'
});
Now you can see, extra is not used in a at all, though it was a property of the anonymous object passed to a as an argument. Also all arguments passed to a are garbage collected, unless you're not going to create a closure, i.e. returning a local value or a function from a.

Creating methods on the fly

Hi I'm trying to author a jQuery plugin and I need to have methods accessible to elements after they are initialized as that kind of object, e.g.:
$('.list').list({some options}); //This initializes .list as a list
//now I want it to have certain methods like:
$('.list').find('List item'); //does some logic that I need
I tried with
$.fn.list = function (options) {
return this.each(function() {
// some code here
this.find = function(test) {
//function logic
}
}
}
and several other different attempts, I just can't figure out how to do it.
EDIT:
I'll try to explain this better.
I'm trying to turn a table into a list, basically like a list on a computer with column headers and sortable items and everything inbetween. You initiate the table with a command like
$(this).list({
data: [{id: 1, name:'My First List Item', date:'2010/06/26'}, {id:2, name:'Second', date:'2010/05/20'}]
});
.list will make the <tbody> sortable and do a few other initial tasks, then add the following methods to the element:
.findItem(condition) will allow you to find a certain item by a condition (like findItem('name == "Second"')
.list(condition) will list all items that match a given condition
.sort(key) will sort all items by a given key
etc.
What's the best way to go about doing this?
If you want these methods to be available on any jQuery object, you will have to add each one of them to jQuery's prototype. The reason is every time you call $(".list") a fresh new object is created, and any methods you attached to a previous such object will get lost.
Assign each method to jQuery's prototype as:
jQuery.fn.extend({
list: function() { .. },
findItem: function() { .. },
sort: function() { .. }
});
The list method here is special as it can be invoked on two occasions. First, when initializing the list, and second when finding particular items by a condition. You would have to differentiate between these two cases somehow - either by argument type, or some other parameter.
You can also use the data API to throw an exception if these methods are called for an object that has not been initialized with the list plugin. When ('xyz').list({ .. }) is first called, store some state variable in the data cache for that object. When any of the other methods - "list", "findItem", or "sort" are later invoked, check if the object contains that state variable in its data cache.
A better approach would be to namespace your plugin so that list() will return the extended object. The three extended methods can be called on its return value. The interface would be like:
$('selector').list({ ... });
$('selector').list().findOne(..);
$('selector').list().findAll(..);
$('selector').list().sort();
Or save a reference to the returned object the first time, and call methods on it directly.
var myList = $('selector').list({ ... });
myList.findOne(..);
myList.findAll(..);
myList.sort();
I found this solution here:
http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html
This seems to do exactly what I need.
(function($) {
var TaskList = function(element, options)
{
var $elem = $(element);
var options = $.extend({
tasks: [],
folders: []
}, options || {});
this.changed = false;
this.selected = {};
$elem.sortable({
revert: true,
opacity: 0.5
});
this.findTask = function(test, look) {
var results = [];
for (var i = 0,l = options.tasks.length; i < l; i++)
{
var t = options['tasks'][i];
if (eval(test))
{
results.push(options.tasks[i]);
}
}
return results;
}
var debug = function(msg) {
if (window.console) {
console.log(msg);
}
}
}
$.fn.taskList = function(options)
{
return this.each(function() {
var element = $(this);
if (element.data('taskList')) { return; }
var taskList = new TaskList(this, options);
element.data('taskList', taskList);
});
}
})(jQuery);
Then I have
$('.task-list-table').taskList({
tasks: eval('(<?php echo mysql_real_escape_string(json_encode($tasks)); ?>)'),
folders: eval('(<?php echo mysql_real_escape_string(json_encode($folders)); ?>)')
});
var taskList = $('.task-list-table').data('taskList');
and I can use taskList.findTask(condition);
And since the constructor has $elem I can also edit the jQuery instance for methods like list(condition) etc. This works perfectly.
this.each isn't needed. This should do:
$.fn.list = function (options) {
this.find = function(test) {
//function logic
};
return this;
};
Note that you'd be overwriting jQuery's native find method, and doing so isn't recommended.
Also, for what it's worth, I don't think this is a good idea. jQuery instances are assumed to only have methods inherited from jQuery's prototype object, and as such I feel what you want to do would not be consistent with the generally accepted jQuery-plugin behaviour -- i.e. return the this object (the jQuery instance) unchanged.

Categories

Resources