Using variable names where single quotes are expected - javascript

This is the Google RankTracker found here
<script>
if (document.referrer.match(/google\.com/gi) && document.referrer.match(/cd/gi)) {
var myString = document.referrer;
var r = myString.match(/cd=(.*?)&/);
var rank = parseInt(r[1]);
var kw = myString.match(/q=(.*?)&/);
if (kw[1].length > 0) {
var keyWord = decodeURI(kw[1]);
} else {
keyWord = "(not provided)";
}
var p = document.location.pathname;
ga('send', 'event', 'RankTracker', keyWord, p, rank, {'nonInteraction': 1});
dataLayer.push({'eventCategory':'RankTracker','eventAction':keyWord,'eventLabel':p,'eventValue':rank 'event':'RankTracker'});
}
</script>
I'm trying to get this working with Google Tag Manager, (the dataLayer.push({... section at the bottom), but I'm not sure the variables are working (although they work with the Universal Analytics ga('send'...) portion
Should calling the variables as I have done work in this case?
My main concern is the lack of single quotes around the values
BTW, if anyone is wondering I have set up macros in GTM for eventCategory, etc., and my rule for firing is that event is equal to RankTracker

Should calling the variables as I have done work in this case?
My main concern is the lack of single quotes around the values
Assuming you mean the keyword, p, and rank values used on the right-hand side of the : in a property initializer, those are used correctly and do not need quotes.
Here's a simpler example:
var foo = "testing";
var obj = {prop: foo};
console.log(obj.prop); // "testing"

I don't know much about Google RankTracker, but I do know you need a comma between those these two key/value pairs.
'eventValue':rank 'event':'RankTracker'
should be
'eventValue':rank, 'event':'RankTracker'
Maybe that's what's causing unexpected results.

Related

Assign HTML elements ID to document.queryselector shorthand variables in a loop

I am new to Javascript development.
I am trying to assign HTML elements IDs stored in an array to shorthands to be used in my function later.
So that instead of writing :
let addprop = document.querySelector(`#addprop`);
let readprop = document.querySelector(`#readprop`);
let editprop = document.querySelector(`#editprop`);
let footer = document.querySelector(`#footer`);
let association = document.querySelector(`#association`);
I can attribute elements ids that i store in an array like this :
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"] ;
arrayElements.forEach(el => { return(new Function (`${el} = document.querySelector("#${el}");`)()); });
Now, this bit of code works but from what I read here :
Execute JavaScript code stored as a string
This is probably not a good way to do it and also declares global variables.
One problem I encountered is that if I try to directly execute the assignment like this :
el = document.querySelector(`#${el}`);
Then the el value takes the value of the named access ID element (https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object) and breaks the code.
So I resorted to generate a string first then execute it.
I could simply assign each shorthand manually but I spent way too much time trying to make this work and am now left curious as to what would be a good solution or approach for this.
And would the scope limitations for loops simply forbid me to do this without using global variables ?
edit : switched the working code in one line
Possible answer :
1 - does it matter to declare global variables like that ? As these variables already exist globally because of browsers named access for elements IDs.
2 - By kiranvj's answer, a solution can be to store in an object structured as keys being the shortcuts and the full strings being the values, and calling the shortcuts with the object[key] method ; or using destructuring to assign the values to variable directly with :
const {addprop, readprop, editprop, idfooter, assocpatients} = elements;
I feel like I am missing something on this last one but it also seems to work.
In the end I will stick with my first code as condensing the function in one line seems to negate the risks of cross site scripting (?), and global values for the variables assigned though this method anyway already exist because of named access.
You can create a dictionary with all the elements with ID and then destroy it into your variables, ignoring the unused ones.
function getAllElementsWithId() {
let elements = {}
for (let el of document.querySelectorAll('[id]')) {
if (!(el.id in elements)) {
elements[el.id] = el
}
}
return elements
}
let { addprop, readprop, editprop, footer, association } = getAllElementsWithId()
This uses document.querySelectorAll (link to MDN) to get all elements with an ID. Notice that for big pages this could be a performance issue.
Also, what you would usually do is to add them into a container, in this case it seems like a dictionary.
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"]
let elementsId = Object.fromEntries(arrayElements.map(id => [id, document.getElementById(id)]))
This uses Object.fromEntries (link to MDN) to generate the dictionary. Also I'm using document.getElementById (link to MDN) instead of document.querySelector so you don't need to add the hashtag before the id.
If you are concerned about global scope, you can try something like below. Use forEach instead of map . map also work but since you are not handling the return of map, forEach would be a better choice.
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"];
let elements = {};
arrayElements.forEach(el => elements[el] = document.querySelector(`#${el}`));
// access variables like elements.ID-NAME
console.log(elements);
<div id="addprop"></div>
<div id="readprop"></div>
Object destructing can be used if you know the object key name.
example : let {addprop} = element;
Another thing which you might be interested is Automatic global variables
This means a new variable (scoped to window) with the name of element id is created for all the elements in page. See the html5 spec. I would not recommend using it though.
So you don't have to call like document.querySelector('addprop')
addprop variable will have the DOM object.
See this example
// these works due to automatic global varaibles binding
alert(addprop);
console.log(addprop);
<div id="addprop">Some contents</div>

window["object.something"] not working for objects javascript

Hi I just can't figure this one out.
I need to use the window["evaluate string into js object"] because I am converting a web Application into a ChromeOS Chrome app and they do not let you use eval() to do their content security policy.
My problem is that for basic varibles it is fine, example:
var a = "foo";
var b = window["a"];
This will put "foo" into b no problem. But as soon as I have an object (both global or local) it doesn't work, so if 'a' was an object the code would like something like this:
a.test = "foo";
var b = window["a.test"];
That will not work.
Is there a reason for this? I can't seem to find much info on window[] in general so wondering if anyway has any insight or at least can point me in the right direction to look.
Thanks
window[] doesn't work on namespaced functions, so if you try to evaluate window['a.test'] it would fail. A proper alternative is to use window['a']['test']. In case you're indefinite of number namespaced objects you're going to use, you can create a simple function that would split the string from . and create a window object for each part. Example :
var str = 'namespace.service.function';
var parts = str.split(".");
for (var i = 0, len = parts.length, obj = window; i < len; ++i) {
obj = obj[parts[i]];
}
console.log(obj);

Having trouble referring to object within array

I am trying to write an html page for class that uses a drop down menu to allow users to pull up a list of relevant information. Unfortunately I am having trouble figuring out how to make the script call on the information in the array. The jsfiddle has the full html section, any help would be GREATLY appreciated.
Please bear in mind that I am not very good with terminology, so be as specific as possible. Especially regarding jQuery, our teacher didn't go over it much so it's a freaking mystery to me.
Also, I do plan on adding more information to the objects in the array, but until I get it working, I don't want to waste the time on something I might need to restructure.
http://jsfiddle.net/GamerGorman20/nw8Ln6ha/11/
var favWebComics = [
Goblins = {1: "www.goblinscomic.org"},
GirlGenious = {1: "www.girlgeniousonline.com"},
GrrlPower = {1: "www.grrlpowercomic.com"}
];
var myFunction = function() {
var x = document.getElementById("mySelect").value;
document.getElementById("demo").innerHTML = "You selected: " + x;
document.getElementById("web").innerHTML = favWebComics.x;
};
Again, the JSFiddle link has the full html, there are some unused items currently, but I do plan on adding more of them soon.
My next plan is to incorporate images into the objects, so a picture loads for each selection option. How would I manage that?
[ ] is used for arrays, which are indexed with numbers. If you want named properties, you should use an object, which uses { } for its literals:
var favWebComics = {
Goblins: "www.goblinscomic.org",
GirlGenious: "www.girlgeniousonline.com",
GrrlPower: "www.grrlpowercomic.com"
};
= is for assigning to variables, not specifying property names in an object.
Then you need to understand the difference between . and [] notation for accessing objects. .x means to look for a property literally named x, [x] means to use the value of x as the property name. See Dynamically access object property using variable.
So it should be:
document.getElementById("web").innerHTML = favWebComics[x];
your array is not structured correctly and an object would be better suited:
var favWebComics = {
Goblins : "www.goblinscomic.org",
GirlGenious : "www.girlgeniousonline.com",
GrrlPower : "www.grrlpowercomic.com"
};
then you should be able to access the properties as you intend
favWebComics.Goblins
favWebComics.GirlGenious
favWebComics.GrrlPower
Technically you were treating the array like a dictionary. if you're going to do that but still wanna add more information later you'll need to use brackets {} on the code.
var favWebComics = {
Goblins: ["www.goblinscomic.org"],
GirlGenious: ["www.girlgeniousonline.com"],
GrrlPower: ["www.grrlpowercomic.com"]
};
Also for javascript, as long as your searching key value stores, use braces [] for the call. Here's the working code below.
document.getElementById("web").innerHTML = favWebComics[x];
I have your solution, that displays:
the selected choice
the url
the images
Please check the fiddle.
http://jsfiddle.net/nw8Ln6ha/13/
Your object would be:
var favWebComics = {
Goblins : {url:"www.goblinscomic.org", img:"img1"},
GirlGenious : {url:"www.girlgeniousonline.com", img:"img2"},
GrrlPower : {url:"www.grrlpowercomic.com", img:"img3"}
};
Your display code:
document.getElementById("demo").innerHTML = "You selected: "+x+" "+ eval("favWebComics[\""+x+"\"].url")+" "+ eval("favWebComics[\""+x+"\"].img");

Need to get an array of the names of all applicationScope variables

In an application I am working on I need to get a list of the names of all applicationScope variable then I need to cycle through them and filter out the ones starting with a know string say $xyx. I thought that the applicationScope.keySet().
I'm using this code for starter:
var col = applicationScope.keySet();
var itr:java.util.Iterator = col.iterator();
if (itr.hasNext()){
var str:String = itr.next();
dBar.info(str,"Value = ");
}
if I put the variable col in a viewScope it shows a list of all the keys. but when I run the script the values displayed in the dBar info are not the keys but some other information that I'm not sure where it comes from.
I should just be able to iterat through the list of keys, am I missing something?
This code is in the before page loads event
After some poking around and experimenting I got this to work:
var col = applicationScope.keySet();
var itr:java.util.Iterator = col.iterator();
while (itr.hasNext()){
var str:Map.Entry = itr.next();
if (str.substring(0,9) == "$wfsLock_"){
//do stuff
}
}
so I'm now a happy camper.
Although your code works in SSJS, it is not correct (and that's why I don't like SSJS...).
The applicationScope is an implementation of the java.util.Map interface and the keySet() method returns a Set containing the keys in that Map. Every entry is (probably) a String (other data types like integers are actually also valid). The line
var str:Map.Entry = itr.next();
doesn't cast it to a Map.Entry: it doesn't really do anything: str remains a string.
The Map interface also has an entrySet() method that returns the entries (Map.Entry). You can use that to retrieve the key as well as the value:
var it = applicationScope.entrySet().iterator();
while (it.hasNext()) {
var entry = it.next();
print( entry.getKey() + " = " + entry.getValue() );
}
(in this code the print() line will use the toString() method of the key as well as the value to send information to the console)
I see from your code that you've installed my XPages Debug Toolbar. You can also use that to quickly check what's in the scopes and what the actual datatype is.

Pass in vars to an eval workaround to process a code string from a json object after YUI compression

I need to pass a jQuery object in to a workaround for an eval. The issue is that i need access to a jQuery object that is out side the eval area but i can't see to pass it in. here is what i have.
var jObj = $(selector);
var myCode = "var jObj="+jObj+"; var i="+i+"; "+shape.mouseover.onEnd.replace("\u0027","'");
var myFucn = new Function(myCode);
myFucn();
the oject I'm getting the string out of is
shape.mouseover.onEnd.replace("\u0027","'");
is working and what I'm passing in that string is
open_info(jObj,i)
Which is what i have to fire. The deal is that the code is run thru YUI compressor so the jObj var becomes something else so i need to pass that in. Right now i get an error where it thinks it should have and ending ] which is not right. I is working it seems, just not the jObj var.
EDIT
there are many way to get where i need to be that are close but not quite like
How to pass parameters in eval in an object form?
shape.mouseover.onEnd = "open_info(jObj,i)";
/*
* this is coming in and must be as it is, don't say it's wrong please
* it's not able to be done anyother way!
*/
//lets process the string and pull in the vars
/* BEOFRE YUI COMPRESSOR CHANGES THINGS and works!!!
var jObj = $(selector);
var i = 1;
var myCode = shape.style.events.mouseover.onEnd.replace("\u0027","'");
var myFucn = new Function(myCode);
myFucn();
*/
// AFTER note it can be random as i change code so it fails cause
// var jObj is now var r and var i is now var e
var r = $(selector);
var e = 1;
var p= shape.style.events.mouseover.onEnd.replace("\u0027","'");
var f= new Function(p);
f();
Now it works before the compression.. After is not due to the change. Hope tha tclears it up some
I might be going down the wrong tracks and be confused here..
But isnt this what your trying to do?
Send myFucn the correct object and what ever i is
myFucn($(selector),10);
function myFucn(jObj,i)
{
shape.mouseover.onEnd.replace("\u0027","'");
}
I still don't understand why this question got 2 down votes, but well it's solved and works great. The trick is to do the same manipulation of the dom state. It's really simple once it is placed out.
//so this is what the object is parsed out to from the json string
//since you can't just pass a function stright that way any how
shape.mouseover.onEnd = "open_info(jObj,i)";
//this is what will take that string and process it
//note jObj is what is in the orgain code but it changes to
// var r or something else that is shorter after going thru YUI compressor
// Which is why we can't just use open_info(jObj,i) and it work..
// ie: it's not an issue with scoope but an issues with var names being shortened
(function(){
//this is the trick on passing them so YUI doesn't get them
//use a string and YUI skips it so we directly create the
//needed oject in the window namespace
window['jObj']=jObj; window['i']=i;
var p= shape.mouseover.onEnd;
var f= new Function(p);
f();
})();
That is it.. I put it in a click or hover event so it's kin to an onClick.
/* EXMAPLE OUTPUT AFTER YUI COMPRESSION
//Note after the YUI compressor get ahold of that
//processing code above it'll look like
*/
function(){window.jObj=n,window.i=t;var u=i.mouseover.onEnd,r=new Function(u);r()}();
So the way that works is, I needed to fix the issue of the var jObj being renamed. So I simply made a sting for the name and let the compressed the var name fill the name of the object I need for the processed code string. Don’t know why I didn’t see it before and I would have saved my rep value :-\ .. oh well. May be a way to shorten this but I'm leaving it for now.
Edit
I recant the edit it was working. :) Very well.. Left wondering what any other ways there would be to make it do the same thing.

Categories

Resources