Launching Script based on Eval Figure - javascript

$(".app-launch").on("click", function () {
var appId = this.id;
// Check if Function is running.
if (typeof eval('$' + appId).start == 'undefined') {
eval('$' + appId).start();
}
}
The eval just causes it to come back and say $XXXXXX is not defined and kills the java-script execution. Is there anyway to prevent it from killing the execution and continuing? This function is either launching the application or loading the javascript first and then launching the application, so this check is there to determine if the javascript has already been loaded.

Try this
eval('$("' + appId + '"')

First, stop using eval. If you want dynamically namable variables, use an object.
Then you can just test the type of the object before you try to access its start property.
var objects = {};
var appId = "thing";
objects[appId] = { start: foo; }
if (
typeof objects[appId] !== 'undefined' &&
typeof objects[appId].start === 'function'
) {
objects[appId]();
}

If you are trying to retrieve a global variable, just use the associative array syntax window['$'+appId]
Also, the reason your code is breaking is because you are checking if the start method is defined, whereas it is $XXXXXX that does not exist. Check if $XXXXXX exists before referencing the method. Also, you are calling the method if it is not defined, which makes no sense.
Also eval.
Here is a jsfiddle that shows what is wrong. Here is a fixed version.

Related

Can't access the window level variable even though it exists. returns undefined when accessed

I am trying to access the window level variable in my script in the window.onLoad(), but it always returns undefined. But when I console log it or try to just type in the window in the debug console, it clearly shows me the variable exists on window object and has a value. I am unclear why this is happening and is there a way to access it? Please correct me if I am doing something wrong and point me in the right direction. Any help is greatly appreciated.
Update: The window._vp variable is declared in the script of some live website and I am trying to access that particular variable using my chrome extension.
My script:
window.onload = _ => {
console.log("window._vp is:", window._vp);
}
Website script:
var _vp = {};
_vp['IsDashAvailable'] = false;
//...
You can see the behavior in the following screenshot of the dev tool console:
Thank you.
I believe this is an issue with your extensions isolated context, as detailed in another SO post about Context isolation who also faced an identical issue.
You should try the following Method quoted from the other answer:
Method 2b: Using a function
For a big chunk of code, quoting the string is not feasible. Instead of using an array, a function can be used, and stringified:
var actualCode = '(' + function() {
// All code is executed in a local scope.
// For example, the following does NOT overwrite the global `alert` method
var alert = null;
// To overwrite a global variable, prefix `window`:
window.alert = null;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
This method works, because the + operator on strings and a function converts all objects to a string. If you intend on using the code more than once, it's wise to create a function to avoid code repetition. An implementation might look like:
function injectScript(func) {
var actualCode = '(' + func + ')();'
...
}
injectScript(function() {
alert("Injected script");
});
Note: Since the function is serialized, the original scope, and all bound properties are lost!
var scriptToInject = function() {
console.log(typeof scriptToInject);
};
injectScript(scriptToInject);
// Console output: "undefined"

KendoUI data- attribute event handlers and 'this' scope

It seems that kendo's unobtrusive-javascript style event calls break this in my method context.
Say I have an object Foo, instantiated as bar = new Foo()
function Foo(){};
Foo.prototype.name = "Herring";
Foo.prototype.doSomething = function(e) {
alert(this.name);
};
bar = new Foo();
And attach the event using data-click for example
<a data-role="button" data-click="bar.doSomething">Click Me</a>
Object context to bar is replaced (not sure why, since we have the convenient element container.) and so this.name is undefined.
I've tried the old var self = this; in the object constructor, but it's not working, does anyone know what the best way to solve this is?
Update : Hacky Workaround
Since I really don't want to lose the benefits of wrapping up my modules as classes, I've created event call functions wrappers, which then call the methods on the appropriate object.
For example, connect the markup to a wrapper-function.
<a data-role="button" data-click="doSomething">Click Me</a>
and the wrapper function just calls the object.method.
function doSomething(e){ bar.doSomething(e) };  
Now, this achieves the intended result, but it's quite horrible, each and every event called from markup must have a proxy function like the one above. So just imagine a scenario where you have 300 events... and you'll instantly see why this is horrible.
If there's no other solution, and I dearly hope there is. I'll post this workaround as an answer, but as far as I'm concerned, it's far from desirable.
Footnote
I'll be completely honest this seems like major architectural flaw in Kendo, since this method of calling events from markup is "the kendo way." Obviously it can't be patched out, because there's probably a fair bit of code already dealing with this as a reference to the html element.
Being able to override it, or being able to route these event calls through a generic handler which can pass the call on, essentially a generic proxy function, are possible ways this could be dealt with. It could also be a simple configurable value on the kendo. object.
Theoretical Solution
I'll post follow-up if this works, in theory it's possible to throw events at a generic proxy, and have it call the properly scoped function.
Say we use the event attribute to call the proxy and then create a separate attribute to convey the object/method call. For example.
<a data-role="button" data-click="prox" data-prox="o.eventHandler">Click Me</a>
The proxy function would pull prox from the attribute dataset:
method - using eval
Not because I'm evil, but needs must.
// sitting in global namespace
function prox(e){
var p = e.sender.element.data['prox'];
// make sure our delegate is a function.
if("function" == eval("typeof "+p)) {
eval(p + "(e)");
}
}
Obviously I'd like a better way to do this but, at least it's DRY.
(I'll cook a non-eval method in a moment...)
Begone Eval...
let's use the window context to locate the object / method.
function prox(e) {
var p = e.sender.element.data['prox'];
if(p.indexOf(".") == -1){
// global function : where *this* is window.
// check you've got the function if not ditch it.
if("function" == typeof window[p]) window[p](e);
} else {
// object/method (one level deep only.)
var s = p.split(".");
var o = s[0], m = s[1];
// check the object/method is a function before executing it.
if("function" == typeof window[o][p]) window[o][p](e);
}
}
Of course for global (window) scoped functions, this as the element is probably more useful, but in that case, you have a choice, I'd leave out the
version in use.
// dynamic proxy for retaining object context on methods called by
// data- attributes in Kendo.
//
// e.g.
//
// data-click="o.method"
//
// Would lose context with `o` - context would be set in the same
// way as JQuery handlers, which is an inconvenience.
//
// Alternatively we use the prox method
//
// data-click="prox"
//
// We'd then set `data-prox` on the same element, to the
// object.method pair.
//
// data-prox="o.method"
//
// This is read by prox, transformed into a method call, type
// checked and executed if it's a valid method.
//
// A `data-prox` value in any form other than `object.method` will
// be ignored, for example, `object.child.method` will fail. If
// you're doing that sort of thing, feel free to hack it.
//
// There's a backup eval() to locate the object if window doesn't
// own it. It should be possible to remove it under most
// circumstances, it's here for compatability with
// JSFiddle. (JSBin works without it.)
function prox(e) {
var p = this.element.data().prox;
if(p.indexOf(".") > -1){
var s = p.split("."); if(s.length > 2) return;
var o = s[0], m = s[1];
if("object" == typeof window[o]) {
o = window[o];
}
if("function" == typeof o[m]) o[m](e);
// comment this out in production:
l( "prox called " + s[0] + "::" + s[1] );
}
}
function l(s) { console.log(s); }
Caveats
If you have multiple handlers on the same element, prox() is unsuitable, for example, if you have data-init, data-show, etc. prox cannot differentiate, and will fail.
I'll probably update this, especially if this becomes a prevalent use-case for me.
I temporarily tried a third method, with a non-generic technique, which works like this.
Pseudo code:
MyObject {
method : function(e) {
if (this instanceof MyObject) {
// Do something with this
} else {
myInstance.method(e); // otherwise re-call the method to set this properly.
}
}
}
myInstance = new MyObject();
Not as flexible as the prox method, but suitable for my use case, and at least doesn't require a separate function proxy away from the method we want to use. We could make this more terse by doing the type check & re-call up front.
e.g.
MyObject = {
method : function(e) {
if (! this instanceof MyObject) myInstance.method(e); // re-call
// Method body...
}
}
myInstance = new MyObject();
It also meant I didn't need custom data- attributes in my markup.
Note: this method is problematic for objects which will have multiple instances, however, the objects I was applying to were single instances.
If you have handlers which need to be instance specific (which is the main reason I raised this question) the prox method is a much better fit than this, which is just a neater way of doing one-per-event proxy functions.
You may use jQuery Proxy (http://api.jquery.com/jQuery.proxy/).
function Foo(){};
Foo.prototype.name = "Herring";
Foo.prototype.doSomething = function(e) {
alert(this.name);
};
bar = new Foo();
$("btn").click($.proxy(bar.doSomething), bar);
or for inside using
$("btn").click($.proxy(this.doSomething), this);
I developed a proxy method using the JS Proxy Polyfill that simplify calling custom logic via parameters in a custon html data-* attribute.
Include https://raw.githubusercontent.com/GoogleChrome/proxy-polyfill/master/proxy.js
function makeGridTemplateEventProxy(o) {
return new Proxy(o, {
get(target, eventName) {
return function (options) {
return templateEventProxy(options, eventName);
}
}
});
}
templateEventProxy: function (options, attribute) {
if (!options.sender.element.attr('data-proxy-' + attribute)) {
throw new Error('Cannot find attribute data-proxy-' + attribute + ' on ' + options.sender.name + ' widget');
}
var proxyParams = JSON.parse(options.sender.element.attr('data-proxy-' + attribute));
method = $("#" + proxyParams.id).data(proxyParams.widget).element.data(proxyParams.method);
if (method && typeof method == 'function') {
return $.proxy(method, this)(options);
}
return null;
}
var eventproxy = makeGridTemplateEventProxy({});
for example for upload component
<input type=file ...
data-success="eventproxy.customsuccesshandler"
data-proxy-customsuccesshandler='{widget:"kendoGrid",method:"<myJqueryDataDefinedMethod>",id:"<gridId>"}'
....
/>
substitute myJqueryDataDefinedMethod and gridId with your parameters
as you see you can define in data-success an eventproxy with dynamic name
data-success="eventproxy.CUSTOMKEY"
and after define a custom attribute
data-proxy-CUSTOMKEY
data-proxy-CUSTOMKEY contains parameters ( JSON encoded ) you can use to implement a custom logic,
I suggested custom logic which can retrieve JS method stored on kendo widget grid via $.data
$("#" + proxyParams.id).data(proxyParams.widget).element.data(proxyParams.method)
You can bind method to grid for example with this
$('#my-grid-id').data("kendoGrid").element.data('methodName',function(e){
// my implementation
});

how to check efficiently if variable has declared

I have many js methods that uses global variables like:
function DoSomething() {
var val=$('#'+clientId).val();
.
.
.
}
DoSomething uses clientId variable. The problem is that clientId is not always declared and therefore I get an exception of undeclared variable.
I have many places like this and add if (typeof clientId == "undefined") check everywhere is a lot of work and code duplication (duplication of the check). Is there I can workaround it? for example use a method that returns null if the variable is not declared? (In such way I can control on the return value in case of an undefined for example)
It seems to me that your code is just busted if you have code paths that attempt to use a global variable before it is defined. Either you need to give it a default value, you need to reorder the loading or execution of your code or you need to prevent code from running when your environment hasn't been initialized.
It is possible to initialize a variable if and only if it hasn't already been defined like this:
var clientId = clientId || "foo";
You could put this at the top of any module that uses it. This would initialize it with whatever value you want if and only if it wasn't already initialized.
You could also build yourself an accessor function that you would use instead of directly accessing the variable like this:
// put this somewhere early in the JS loading process
function getClientId() {
if (typeof window.clientId !== "undefined") {
return(window.clientId);
} else {
return("foo"); // whatever default value you want to return here
}
}
// use it like this:
function DoSomething() {
var val=$('#'+getClientId()).val();
.
.
.
}
Or, you can make a global function that will test it:
function isClientId() {
return(typeof window.clientId !== "undefined");
}
// use it like this:
function DoSomething() {
if (isClientId()) {
var val=$('#'+clientId).val();
.
.
.
}
}
Just an idea: all variables are properties of a namespace, up to the global namespace (in a browser, that's window). A property that's not assigned evaluates to undefined. So if you want to know if a variable is assigned, you can use if (property in namespace). If it concerns a global variable in a browser: if (clientId in window). Now you can make a function out of that:
function exists(label, namespace){
namespace = namespace || window;
return namespace[label] || false;
}
// possible usage
function DoSomething() {
var val=$('#'+( exists('clientId')||0) ).val();
// ...
}
Global variables are evil and are to be avoided if at all possible.
In the example you give, it would be much better to declare client ID as a parameter, like so:
function DoSomething(clientId) {
var val=$('#' + clientId).val();
.
.
.
}
This way, you are not affected by issues with global variables and there are no side effects (value changes caused by other methods) to worry about.
Good luck!
try :
var isExists =clientId || false;
but be careful
if ClientId==0 it will show you false.
I use:
if (typeof (foo) != 'undefined')
alert ('foo is defined');
If the variable itself is declared (as opposed to just having an undefined value), then you can simply use ( clientId || 'default value' ). This requires that you have var clientId; or something similar in the global scope (which is bad practice, BTW).
If you do not have a guarantee that clientId has been declared somewhere, then using the above construct will still throw an undefined variable error. In that case, you can use this: ( typeof clientId == 'undefined' ? 'default value' : clientId ).
While i like the answers, I go the simple way... Just declare var clientId; on top of your script. If you don't pass it any values then :
var clientId;
if(!clientId){
//will reach here cause declared but with no value
}
but
var clientId;
clientId = 132;
if(!clientId){
}else{
//will reach here cause it has a value
}
so
function DoSomething() {
if(clientId){
Would work

scope and eval explanation

I have an Ajax call where I get back some JavaScript as a String. In the onSuccess Method I want to eval this code. In the JavaScript code there are Function-declarations. All these function should be accessible after the eval.
I made up a small-as-possible example. (The things are going on in the onFailure method in the example, because in JFiddle I can't make a successfull Ajax Call).
You can find the Example here: http://jsfiddle.net/ubXAV/6/
The example you see is working in all browsers (Unfortunately, this will not work in JSFiddle in IE). I marked some lines refering to questions below. Here's the code again:
function evalScript(script)
{
that.eval(script); //1.
}
var that = this;
// AJAX-Call - GadgetActionServlet
new Ajax.Request("THISWILLFAIL.com", {
method: 'post',
onSuccess: function(ajaxResponse) {
alert("success");
},
onFailure: function(){
var script = "{function sayHello(){alert('Hello');}}";
//that.eval(script); //not working in IE 2.
evalScript(script); //working in all browsers
}
});
I read a lot in the internet about scopes and contexts in java but i just can't explain the behaviour here:
Why do I need to call eval on "that" ? According to many sources on the internet the context of a globally defined function is the most global context. (Here it should be window). And the code evaluated through eval should be executed in the context which is calling the eval function.
Assuming, that there is a new global context for the Ajax call (is it?) why can i access the evalScript function but not evaluate the script here directly.
The overall question i have is: Which particular rules apply to the usage of eval? Where are my functions attached to regarding the context? And: does an prototype Ajax call like in the example has its own global object?
First off: If you can avoid using eval, avoid using eval. Does your code have to come back from a POST? Because if you're willing to use GET instead, you can just append a script element to the page:
var script = document.createElement('script');
script.src = "http://example.com" +
"?" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param1value") +
"&" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param2value");
var parent = document.body
|| document.documentElement
|| document.getElementsByTagName('head')[0];
parent.appendChild(script);
Done.
Or if it has to be POST, does it really have to be actual script code? Couldn't it be data that's interpreted by code already on the page? JSON is a useful data format if you can go that way.
But if it has to be POST, and what you get back has to be actual script code as opposed to data, then we'll have to do something like eval. :-)
eval itself is very, very special. It works within the scope in which it's used, even though it looks a bit like a function and that's not how functions work. So actually evaluating script code in global scope is hard unless the eval call is actually at global scope (not within any function call), and of course you can't do that here — you have to trigger this from your ajax callback, and so by definition this happens within a function. (Edit: I just thought of a way to actually use eval at global scope, from within a function. See the update at the end of the answer. But it's evil and horrible and wrong.)
The reason you may have seen advice saying to use window.eval is that a lot of modern browsers offer window.eval (as opposed to eval) which evaluates the given code in global scope. But it's not available on all browsers, and certainly not older ones.
There are workarounds, though. The IE family provides execScript which is very similar to the window.eval offered by other browsers, and in the worst case you can fall back on using a script element. Here's a global eval function that works in nearly everything:
window.evalInGlobalScope = (function() {
var fname, scr;
// Get a unique function name
do {
fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
}
while (typeof window[fname] !== 'undefined');
// Create test script
scr = "function " + fname + "() { }";
// Return the first function that works:
return test(evalInGlobalScope_execScript) ||
test(evalInGlobalScope_windowEval) ||
test(evalInGlobalScope_theHardWay) ||
evalInGlobalScope_fail;
function test(f) {
try {
f(scr);
if (typeof window[fname] === 'function') {
return f;
}
}
catch (e) {
return false;
}
finally {
try { delete window[fname]; } catch (e) { window[fname] = undefined; }
}
}
function evalInGlobalScope_execScript(str) {
window.execScript(str);
}
function evalInGlobalScope_windowEval(str) {
window.eval(str);
}
function evalInGlobalScope_theHardWay(str) {
var parent, script, d = document;
parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
if (parent) {
script = d.createElement('script');
script.appendChild(d.createTextNode(str));
parent.appendChild(script);
}
}
function evalInGlobalScope_fail() {
throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
}
})();
..and here's a live example of using it.
Note that all of the code figuring out what to use only runs once; the function that got chosen is assigned to the evalInGlobalScope property on window.
Also note that I haven't given it any return value. That's because the "hard way" version basically can't return any return value, so it's safest if none of them does. Mind you, I'm not sure what browsers still require "the hard way" — nearly everything has execScript and/or window.eval now.
Update: I said above that you couldn't use eval at global scope from within a function. And technically that's true, but I thought of a way to do an end-run around it. It's evil and horrible and wrong, but it does work: Use setTimeout instead, and give it a timeout of 0:
setTimeout("your code here", 0);
When you give setTimeout a string, it performs an eval on it — after the timeout, at global scope.
Again, it's evil and horrible and wrong, and it has the added disadvantage that it's asynchronous (whereas with our evalInGlobalScope function, the eval happens synchronously), but it does...sort of...work. (Live copy) I do not recommend it.

Test for undefined function in Javascript

So Safari keeps yelling at me for one specific error.
I'm trying to use Google Maps API and call map.getCenter();. However sometimes, this happens before the map has been fully loaded.
So instead in my function I test for an undefined call like this:
if (map.getCenter() != undefined)
But that still errors out because I guess it doesn't even like making the call just to test the if the result is undefined or not?
Can I get some help here?
Thanks!
I actually prefer something along these lines.
if(typeof myfunc == 'function') {
myfunc();
}
Just because something isn't undefined doesn't make it a function.
if (typeof map !== 'undefined' && map.getCenter) {
// code for both map and map.getCenter exists
} else {
// if they dont exist
}
This is the right way to check for existence of a function.. Calling the function to test its existence will result in an error.
UPDATE: Snippet updated.
if (typeof map.getCenter !== 'undefined')
Won't throw an error.
So, better yet, if (typeof map.getCenter === 'function') map.getCenter();
Technically you should be testing if map is undefined, not map.getCenter(). You can't call a function on an undefined reference.
However, Google's own tutorial suggests that you invoke your JavaScript that accesses the API in a body.onload handler, so that you do not attempt to reference anything until all of the remote .js files are loaded - are you doing this? This would solve the problem permanently, rather than failing cleanly when your JavaScript executes prior to loading the API.
I have been in the habit recently of using the typeof operator to test for things and types. It returns the type as a string which I think avoids some response type confusion.
if( typeof map.getCenter != 'undefined') ...
I'm not sure if it's more correct, but I find good results with this process.
You should be testing whether map is undefined. In your current check your are still trying to execute the function call.
Assuming that map.getCenter() is always a function, it's sufficient to just use this check:
if (map.getCenter) {
var x = map.getCenter();
}
The worked solution for me is try and catch,
const stopPropagation = (e) => {
try {
e.stopPropagation();
} catch (err) {
console.log("error with stopPropagation: " + err.error);
}
}
const triggerClick = (e) => {
stopPropagation(e);
};

Categories

Resources