How to chain methods in javascript? - javascript

Assuming I have the following object.
myobj = {
'item1'{'key1':'value1'},
'item2'{'key2':'value2'}
}
How can I define a function such that I could call:
var value = getMyObjItem('item2').getValue();
in order to get 'value2'? I would like to avoid defining a 'getItem' (takes item parameter) and 'getItemByValue' (takes two parameters of item and key).

It wasn't clear what you wanted, but I did the best I could with the information I had. The following function operates in the exact manner you asked for, and is probably a good example of giving you what you asked for rather than what you needed. Nonetheless:
myobj = {
'item1': {'key1':'value1'},
'item2': {'key2':'value2'}
};
function getMyObjItem(key) {
return {
value: myobj[key]["key" + key.replace("item", "")],
getValue: function() {
return this.value;
}
};
}
var value = getMyObjItem('item2').getValue(); // will return "value2"
Note that this will only work if you maintain the exact property scheme that you demonstrated in the example.

Related

Possible to have a JavaScript method to handle undefined properties?

What works:
Having a JavaScript object like e.g.
var obj = {
var1: "one"
};
I can call it like one of the following ways:
console.log(obj.var1);
console.log(obj['var1']);
What fails:
This one would fail:
console.log(obj.var2);
because var2 is no property/variable of the anonymous object, thus, undefined is printed in the console log.
My goal:
What I would love to have is a fallback function that would be called automatically when no matching property/variable is found.
E.g. something like:
var obj = {
var1: "one",
__propertyNotFound__: function (name) {
if ( name=="var2" ) return "two";
else return null;
}
};
Unfortunately I found no whatsoever close solution.
My question:
Being a rather JavaScript newbie, is my question a dumb question and the complete wrong approach or could it make sense and is there actually a solution to solve this?
Well, won't be really automatic but you could do something like this:
var obj={
a:2,
b:5,
get:function(index){
if(this.hasOwnProperty(index)){
return this[index];
}else{
return this.notFound(index);
}
},
notFound:function(index){
if ( index=="var2" ) return "two";
else return null;
}
}
console.log(obj.get('var2')) // two
You will have to use .get to access properties, but you can handle not found with that way
Instead of directly referring to the property when you try to retrieve its value, implement a getter function that will be able to return a requested property, as well as perform any desired operation in case you request an undefined property.

Is it possible to capture property access in JavaScript?

I want to be able to provide a JavaScript function that will be called whenever any property of a specified object is being queried or updated. Is that possible, if so, how?
To give a simple example, if I have obj = { a:3 }, I want to have some function called whenever any code queries obj.a, and be able to return whatever I want instead of its current value, e.g. 4 instead of 3.
It's easy, you can use Object.prototype.defineProperty. more on it here.
To answer your question:
var obj = {};
Object.defineProperty(obj, "a", {
get: function() {console.log("I've been accessed"); return 5;//or whatever value}
});
console.log(obj.a)
Working fiddle
Update
The above can be shorthanded.
Object.prototype.addMonitoredGetter = function(property, value, callback) {
Object.defineProperty(this, property, {
writable: false,
get: function() {callback(); return this[property]
};
};
And the callback here could be the monitoring function. Of course, needs default params and checks, but it should do the trick.
There's a watch method available for Firefox...
o.watch("p", function(...)
http://jsfiddle.net/NTc52/

Trouble referencing variable in Collections.where method within render function

I have run into some trouble with a piece of backbone code. The code below relates to a render function. I can retrieve all the models. My trouble arises when I try to use the "Collections.where" method at line marked number #1. As you can see, I have passed an object literal into the render function but for some reason I am unable to reference it within the customers.where method on line #1. When I give this method a literal number like 45 it works. Is there some way around this so I can pass the variable reference in?
Thanks alot
render: function(options) {
var that = this;
if (options.id) {
var customers = new Customers();
customers.fetch({
success: function (customers) {
/* #1 --> */ var musketeers = customers.where({musketeerId: options.id});
console.log(musketeers.length) //doesn't work as options.id is failing on last line
var template = _.template($('#customer-list-template').html(), {
customers: customers.models
});
that.$el.html(template);
console.log(customers.models);
}
});
} else {
var template = _.template($('#customer-list-template').html(), {});
that.$el.html(template);
}
}
Although it isn't explicitly documented, Collection#where uses strict equality (===) when searching. From the fine source code:
where: function(attrs, first) {
if (_.isEmpty(attrs)) return first ? void 0 : [];
return this[first ? 'find' : 'filter'](function(model) {
for (var key in attrs) {
if (attrs[key] !== model.get(key)) return false;
}
return true;
});
},
note the attrs[key] !== model.get(key) inside the callback function, that won't consider 10 (a probable id value) and '10' (a probable search value extracted from an <input>) to be a match. That means that:
customers.where({musketeerId: 10});
might find something whereas:
customers.where({musketeerId: '10'});
won't.
You can get around this sort of thing with parseInt:
// Way off where you extract values from the `<input>`...
options.id = parseInt($input.val(), 10);

Is it a good practice to store jquery plugin configuration in data?

I want to create jQuery plugin with config (for example plugin myplugin).
Than call $(elem).myplugin(config); After that I want to call methods from this plugin like $(elem).myplugin().method() with already stored config.
My offer is something like that:
(function($) {
$.fn.myplugin = function(options) {
var $this = $(this);
var getOptions = function() {
return $this.data('myplugin');
};
var initOptions = function(opt) {
$this.data('myplugin', opt);
};
var setOption = function(key, value) {
$this.data('myplugin')[key] = value;
}
var updateBorderWidth = function() {
$this.css('border-width',
getOptions().borderWidth * getOptions().coeficient);
};
var init = function(opt) {
initOptions(opt);
updateBorderWidth();
}
function changeBorder(width) {
setOption('borderWidth', width)
updateBorderWidth();
}
if(options) {
init(options);
}
return {
changeBorder : changeBorder
};
}
})(jQuery);
And usage:
$(function() {
var item1 = $('#test1').myplugin({ coeficient: 1, borderWidth: 1 });
var item1 = $('#test2').myplugin({ coeficient: 2, borderWidth: 1 });
$('#btn').click(updateBorder);
});
function updateBorder() {
$('#test1').myplugin().changeBorder($('#inpt').val());
$('#test2').myplugin().changeBorder($('#inpt').val());
}
Example: http://jsfiddle.net/inser/zQumX/4/
My question: is it a good practice to do that?
May be it's incorrect approach. Can you offer better solution?
Edit:
After searching for threads on jQuery plugin template I found these Boilerplate templates (updated) which are more versatile and extensive designs than what I've offered below. Ultimately what you choose all depends on what your needs are. The Boilerplate templates cover more use cases than my offering, but each has its own benefits and caveats depending on the requirements.
Typically jQuery plugins either return a jQuery object when a value is passed to them as in:
.wrap(html) // returns a jQuery object
or they return a value when no parameter is passed in
.width() // returns a value
.height() // also returns a value
To read your example calling convention:
$('#test1').myplugin().changeBorder($('#inpt').val());
it would appear, to any developer who uses jQuery, as though two separate plugins are being utilized in tandem, first .myplugin() which one would assume will return a jQuery object with some default DOM maniplulation performed on #test1, then followed by .changeBorder($('#inpt').val()) which may also return a jQuery object but in the case of your example the whole line is not assigned to a variable so any return value is not used - again it looks like a DOM manipulation. But your design does not follow the standard calling convention that I've described, so there may be some confusion to anyone looking at your code as to what it actually does if they are not familiar with your plugin.
I have, in the past, considered a similar problem and use case to the one you are describing and I like the idea of having a convenient convention for calling separate functions associated with a plugin. The choice is totally up to you - it is your plugin and you will need to decide based on who will be using it, but the way that I have settled on is to simply pass the name of the function and it's parameters either as a separate .myplugin(name, parameters) or in an object as .myplugin(object).
I typically do it like so:
(function($) {
$.fn.myplugin = function(fn, o) { // both fn and o are [optional]
return this.each(function(){ // each() allows you to keep internal data separate for each DOM object that's being manipulated in case the jQuery object (from the original selector that generated this jQuery) is being referenced for later use
var $this = $(this); // in case $this is referenced in the short cuts
// short cut methods
if(fn==="method1") {
if ($this.data("method1")) // if not initialized method invocation fails
$this.data("method1")() // the () invokes the method passing user options
} else if(fn==="method2") {
if ($this.data("method2"))
$this.data("method2")()
} else if(fn==="method3") {
if ($this.data("method3"))
$this.data("method3")(o) // passing the user options to the method
} else if(fn==="destroy") {
if ($this.data("destroy"))
$this.data("destroy")()
}
// continue with initial configuration
var _data1,
_data2,
_default = { // contains all default parameters for any functions that may be called
param1: "value #1",
param2: "value #2",
},
_options = {
param1: (o===undefined) ? _default.param1 : (o.param1===undefined) ? _default.param1 : o.param1,
param2: (o===undefined) ? _default.param2 : (o.param2===undefined) ? _default.param2 : o.param2,
}
method1 = function(){
// do something that requires no parameters
return;
},
method2 = function(){
// do some other thing that requires no parameters
return;
},
method3 = function(){
// does something with param1
// _options can be reset from the user options parameter - (o) - from within any of these methods as is done above
return;
},
initialize = function(){
// may or may not use data1, data2, param1 and param2
$this
.data("method1", method1)
.data("method2", method2)
.data("method3", method3)
.data("destroy", destroy);
},
destroy = function(){
// be sure to unbind any events that were bound in initialize(), then:
$this
.removeData("method1", method1)
.removeData("method2", method2)
.removeData("method3", method3)
.removeData("destroy", destroy);
}
initialize();
}) // end of each()
} // end of function
})(jQuery);
And the usage:
var $test = $('#test').myplugin(false, {param1: 'first value', param2: 'second value'}); // initializes the object
$test.myplugin('method3', {param1: 'some new value', param2: 'second new value'}); // change some values (method invocation with params)
or you could just say:
$('#test').myplugin(); // assume defaults and initialize the selector
Passing parameters to javascript via data attributes is a great pattern, as it effectively decouples the Javascript code and the server-side code. It also does not have a negative effect on the testability of the Javascript code, which is a side-effect of a lot of other approaches to the problem.
I'd go as far as to say it is the best way for server-side code to communicate with client-side code in a web application.

javascript: dynamic call of nested function

in an existing implementation (can't change the structure much), i'm trying to call a function which is nested inside another function:
function outer(innerFunction, obj) {
//TODO: call innerFunction here, passing obj as first parameter
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
jsfiddle is here: http://jsfiddle.net/tbyyw/
i've alreay thought about using eval(), but i don't know how to pass an object - and they say 'eval is evil' ;)
another solution i've come up with is checking the innerFunction string, but this means i have to know which inner functions exist (besides, adding new functions would mean having to write extra checks then):
if(innerFunction == 'inner1') inner1(obj);
so is there another way without changing the overall implementation?
Without changing the overall structure eval appears to be the only option:
function outer(funcName, obj) {
var func = eval(funcName);
func(obj);
function inner1(obj) {
alert(obj.key);
}
}
There's nothing particularly "evil" about eval as long as you have full control over the code, but if you want, you can insert an additional security check:
if (funcName.match(/\W/))
throw "invalid function name!";
var func = eval(funcName);
This will raise an exception if someone tries to pass anything else than a simple identifier, i.e. a function name.
Is this what you wanted?
function outer(innerFunction, obj) {
var fn = {
inner1: function (obj) {
alert(obj.key);
}
};
fn[innerFunction](obj);
}
outer('inner1', {key:'value'});
http://jsfiddle.net/tbyyw/1/
A simple switch statement would be least intrusive. Or is the function name completely dynamic?
function outer(innerFunction, obj) {
switch (innerFunction) {
case "inner1": inner1(obj); break;
}
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
​

Categories