GoJS: use more than one parameter in a conversion function - javascript

I need to use two properties of a node in GoJS to perform a particular operation. Here is my current code:
$(go.Picture,
{
//some properties
},
new go.Binding("source", "item_status", getIcon)),
//....
function getIcon(item_status) {
//do something
}
Is it possible to modify the above code so that getIcon() function gets a second parameter called item_id? E.g can i do something like this:
new go.Binding("source", "item_status","item_id", getIcon)),
....
function getIcon(item_status, item_id) {}
Thanks

Answering my own question again...
to get all data for a particular node, you can pass "" instead of "item_status" to the Binding function.
go.Binding("source", "", getIcon)),
...
getIcon(node){
var x = node.item_status;
var y = node.key;
}

Related

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

Javascript Function Calls: Regular call vs Call vs Bind Call

My question is simple:
I'm passing a function to some other function to be call later (sample callback function), the question is when, why and what is the best practice to do it.
Sample:
I have the xxx() function, and I have to pass it, as I show you below in the window.onload event.
What is the best practice and why? There is any performance aspect or why should I choose to use call or bind to call this function
function xxx(text)
{
var div = document.createElement("div");
div.innerHTML = text + " - this: " + this.toString();
document.body.appendChild(div)
}
function callFunction(func)
{
func("callFunction");
}
function callUsingCall(func)
{
func.call(this, ["callUsingCall"]);
}
function callUsingBind(func)
{
func.call(this, ["callUsingCall"]);
}
window.onload = function(){
callFunction(xxx);
callUsingCall(xxx);
callUsingBind(xxx.bind(document));
}
Thank you,
Sebastian P.
I don't think there's any "best" practise.
You use call if the function you're calling cares what this is.
You use bind if you want to ensure that the function can only be called with the specified value of this.
[There's some overhead to both, i.e. at least one depth of function calls / scope]
Otherwise you just call the function.
Simples :)
The this object is the context of the function. It's like you make a machine that something for you, and the this object would be the place that the machine works in, like your house. You can move it as you like.
We have 4 ways setting this objects.
Calling the function that is not a method:
fn(someArguments)
This way the this object is set to null or probably the window object.
Calling the function as a method:
someObject.fn(someArguments)
In this case the this object will point to someObject and it's mutable.
Calling with call or apply methods of the function.
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])
In this case the this object will point to someObject here. You are forcing it to have another context, when calling it.
Binding a the function
var fn2 = fn.bind(anotherObject, someArguments)
This will create another function that is binded to that this object we gave it(anotherObject). No matter how you call it, the this object is going to be the same.
Use Cases
Now you can do some tricky stuff knowing this. The reason that why we have it here(I think it came first from C++) is that methods of an object need to access to their parent. The this object provides the access.
var coolObject = {
points : ['People are amazing'],
addPoint : function (p) { this.points.push(p) }
}
So if you do the following it won't work:
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');
The error will be thrown because the this object is not our coolObject anymore and doesn't have the points property. So at times like this, you can something like this:
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');
This is pointless, but the function will work, even the this object is not what its supposed to be.
var anotherCoolObject = {
points : ['Im a thief!'],
addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');
Still the function will work if you call it like that, since the this object will point to anotherCoolObject which has the points property.
The most popular use case I've seen is slicing the arguments object:
function returnHalf() {
return [].slice.call(arguments, 0, arguments.length / 2);
}
returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']
So you see, arguments object is not an instanceof array. If we do arguments.slice(...) then you're gonna be killed by the compiler. But here we use the array's method on arguments object, since it's array like.
Sometimes you don't want your function context to be changed or you wanna add your own arguments, you use bind.
For example when you add a listener for an event with jquery, when jquery calls your function, the this object will be the element. But sometimes you wanna do tricky stuff and change it:
var myElement = {
init : function () {
$(this.element).click(this.listener.bind(this));
},
view : "<li>${Name}</li>",
name : 'ed',
element : $('#myelement'),
listener : function () {
this.element.append($.tmpl( this.view, this ));
}
}
myElement.init();
So here, you bind it to the myElement, so you can have access to the object properties to render the view. Another examples would be the following:
for (var i = 0; i < 10; i++) {
setTimeout(function () {console.log(i)}, 10)
}
// All of them will be 10.
for (var i = 0; i < 10; i++) {
setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}
If you have put an asynchronous function call in a loop, by the time the callback is called, the loop is finished, and the counter have reached the end, you can use bind to cleanly bind the current counter to your callback.
Another good use case of it, that I use a lot is when passing my functions with arguments to async module, without creating closures.
async.parallel({
writeFile : function (cb) {
fs.writeFile('lolz.txt', someData, cb);
},
writeFile2 : function (cb) {
fs.writeFile('lolz2.txt', someData, cb);
}
}, function (err){
console.log('finished')
});
async.parallel({
writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){
console.log('finished')
});
These two implementations are identical.
Performance
Just check these out:
http://jsperf.com/bind-vs-call2
http://jsperf.com/js-bind-vs-closure/2
http://jsperf.com/call-vs-closure-to-pass-scope/10
bind has a big performance overhead comparing to other types of calling, but make sure you don't sacrifice performance with maintainability with pre-mature optimizations.
Also you can have a look at this article.

Function in a variable, passing a parameter

I can't seem to get back on track with this one. I simply put a function in a variable and want to call it later, providing it with a parameter:
var logic = function(itemId) {
console.log(itemId);
};
jQuery("#flipright").click(function() { logic.apply(1); } );
This prints "undefinded".
What am I missing?
Simply call logic(1).
If you want to pass a context, you can use call or apply :
logic.apply(context, [1]);
// or
logic.call(context, 1);
You should use apply or call if you want to pass a context to another function - meaning that the this keyword in the called function will refer to whatever context you are passing to it.
Here's a scenario :
var logic = function(itemId) {
console.log(this,itemId);
};
jQuery("#flipright").click(function() {
// output to console the current jquery object and "1"
logic.call(this,1);
});
Make it:
jQuery("#flipright").click(function() { logic(1); } );
ref for apply: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

Javascript: How change function call params on the fly?

I'm receiving some 'body' content from a jquery's json call, where I can get the unique javascript element returned by doing:
script_element = $(data.body)[1]
This equals to:
<script type=​"text/​javascript">​
updater('foo', 'bar', {}, '0', constant='');
</script>​
So, typeof script_element returns "object"
And, if I run script_element.innerText, I can get:
updater('foo', 'bar', {}, '0', constant='');
After receiving this script, what I'm doing right now is just run an eval on it, but searching around I couldn't get a way to run eval changing function call params.
What I'm trying to do is change the third param of the call, in this case the {}, that can change depending on the return of the json call, so I can't just search for {}.
I could also do script_element.text.split(',')[2] for example, and change this text on the fly, but I was thinking there should be a better way to do this.
I don't know if javascript can recognize and treat a "future method call", but still think there should be a better way.
Any idea?
What you could do is shadowing the function so as to be able to alter the third argument. You ought to define that shadowing function before fetching the JSON.
var originalUpdater = updater; // keep old function to call
// overwrite (shadowing)
updater = function(a, b, c, d, e) {
// change c appropriately here
originalUpdater(a, b, c, d, e);
}
Then you can still just eval it (which is not very safe, but that's not your point if I'm not mistaking), and it will call the shadow function.
A more generic shadowing method would be along the lines of:
var originalUpdater = updater; // keep old function to call
// overwrite (shadowing)
updater = function() {
// change arguments[2] appropriately here
originalUpdater.apply(this, arguments);
}
Fiddle: http://jsfiddle.net/n7dLX/
Change the server. Rather than returning
<script type=​"text/​javascript">​
updater('foo', 'bar', {}, '0', constant='');
</script>​
Return
{
"method": "updater",
"params": [
"foo", "bar", {}, "0", ''
]
}
Assuming that you cannot change what is being sent over from the server, you can simply run through the innerText with a regular expression and pass update the HTML before you insert it.
var replacer = /\w+\(([^()]+)\)/gi;
script_element.innerText.replace(replacer, function(matched_text, func_params){
var orig_func_params = func_params;
// Make changes to func_params here.
return matched_text.replace(orig_func_params, func_params);
});
This can be functionized by doing the following:
var replacer = /\w+\(([^()]+)\)/gi;
function replace_arg(script_element, arg_index, replacement_value) {
script_element.innerHTML = script_element.innerHTML.replace(replacer,
function(matched_text, func_params){
var orig_func_params = func_params;
func_params = func_params.split(",");
if (arg_index >= func_params.length) {
throw new RangeError(arg_index + " is out of range. Total args in function:" + func_params.length);
}
func_params[arg_index] = JSON.stringify(replacement_value);
return matched_text.replace(orig_func_params, func_params.join(","));
});
return script_element;
}
This can be called in this way:
script_element = replace_arg(script_element, 3, {"new":"arg"});
I don't understand what you are doing, but in general if you don't want to rely on the order of parameters make the function take one parameter that is an object whose properties are the parameters:
function add(params) {
var a = params.hasOwnProperty("paramA") ? params.paramA : 0;
var b = params.hasOwnProperty("paramB") ? params.paramB : 0;
return a + b;
}
add({paramA: 1, paramB: 2});
In this case you should use hasOwnProperty to check if the function was passed the parameter you are looking for before trying to access it.

How can I call javascript function using a foreach on a JSON object?

My problem is pretty easy to understand. I have a JSON object (see code) and I will automatically call all functions of this object in the order that those appears. .
var installer = {
a : function() {
...
}
b : function() {
...
}
};
for(var func in installer) {
fn.call(document);
};
Have you any idea why the previous code doesn't work ? I'm sorry, I'm a beginner in javascript.
Thanks in advance !
Regards.
You don't have a variable called fn, and you are also missing commas at the end of your function definitions.
Additionally, your functions will not be called in order because JavaScript orders your object properties arbitrarily. You may want to consider using an array or, as I have done below, specify an array that determines the order.
var installer = {
a : function() {
...
},
b : function() {
...
},
};
var order = [ "a", "b" ];
for(var i = 0; i < order.length; i++) {
installer[order[i]].call(document);
}
You declare var func as the variable to loop through the members of installer, yet you use fn.call(...). Where did fn come from?
Should you be able to do: installer[func].call(document) instead of fn.call(document).
Also your functions declared in the installer object don't take any arguments, yet you're passing document as an argument.
[updated code to add missing .call to installer[func](document)]

Categories

Resources