I've got some JavaScript to retrieve a URL parameter, check if the parameter called "pc" was found and if it's value is "tmgppc5" or "tmgggr1", then append to all hrefs on the page.
var pc = getQueryVariable("pc"),
url = 'http://www.thisurl.com';
// Check if the parameter called "pc" was found and if it's value is "tmgppc5" or "tmgggr1"
if (pc && pc === "tmgppc5" || "tmgggr1") {
url += "pc=" + pc;
}
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
var elements = document.getElementsByTagName('href')[0];
elements.setAttribute('href',url);
I'm using getElementsByTagName to search for all hrefs, however I get the error: uncaught type error cannot read property 'setAttribute' of undefined
Using getElementsById on a single href works, using getElementsByClassName returns the same error. What's the cause of the error? Is there an alternative? Thanks.
You have 2 errors there, 1. you are searching for "href" instead of "a" and secondly
you can not setAttribute on node collection, try to loop trough them :
var elements = document.getElementsByTagName('a');
// You can also use document.querySelectorAll("a")
for (var i=0; i< elements.length; i++) {
elements[i].setAttribute('href',url);
}
The tag is a for example (a link ), if the links are anchors you could use
getElementsByTagName('a')
Related
In Shopify, i'm trying to get the ID of the selected variant in a script file. I was able to get the Variant ID by getting the URL parameter, but it is giving me the url parameter that was there prior to the on change event.
I tried doing an AJAX call, looped through the product variant IDs but no luck.
// Getting the URL Parameter for Variant ID
var getUrlParameter = function getUrlParameter(sParam) {
var sPageURL = window.location.search.substring(1),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
}
}
};
$('#option-color').change(function() {
var currentUrl = getUrlParameter('variant');
var variants = [];
var selected = $(this).val(),
mainImage = jQuery('.main-image img').attr('srcset'),
maxCount = 0;
$('.thumbnail').addClass('thumbnail--hidden');
$('.thumbnail--last').addClass('thumbnail--last');
arr = [];
var addImage = $.each(images, function(i, image) {
var alt = images[i].alt,
url = images[i].url;
if (( alt == selected || url == mainImage) && maxCount < 4) {
$($('.thumbnail img[alt="' + alt + '"]')[maxCount]).parents('.thumbnail').removeClass('thumbnail--hidden');
maxCount++
}
});
I basically want to be able to output the variant ID that it becomes after selecting on a new color.
When looking to get the variant ID of the currently selected variant, you should setup a listener on the actual element that changes the variant. All those active elements emit a type of "change" event you can listen to. When you get the change event, typically you get a variant to inspect, but if not, you can always query the element for its current value.
Looking in the URL is probably the least efficient and least trustworthy way to do this. Not all themes bother placing the current variant in the URL, and like you have pointed out, depending on when you choose to examine and parse that value, it might not represent what you want.
So the safest approach is examine the DOM and figure out the element the customer selected variants with, and dig through that to discover the "change" and subsequent value.
My specific situation is that I'm trying to remove/make inactive a link element from the DOM (I have no control over it being generated). The way that I plan to do this is through replacing the 'href' attribute with a nonsense value - the reason I've chosen to do it this way rather than simply using disable = true is so that the function can be reused on other occasions to change other attributes.
The problem I'm having is with .getAttribute where it returns the error "TypeError: elemArr.hasAttribute is not a function".
function removeLink(elem, att, value, replacement) {
var elemArr = document.getElementsByTagName(elem);
for (var i = 0; i < elemArr.length; i++) {
var workingAtt = elemArr.hasAttribute(att);
if (workingAtt.value === filePath) {
elemArr[i].setAttribute(att, replacement);
}
}
}
removeLink("link", "href", "filePath", "#");
Any help with why this error is getting thrown is greatly appreciated.
What's going on in there is that elemArr is an array, and arrays don't have a hasAttribute method. Rewrite your code as
function removeLink(elem, att, value, replacement) {
var elemArr = document.getElementsByTagName(elem);
for (var i = 0; i < elemArr.length; i++) {
//this line here wasn't referring to a specific node but the array
var workingAtt = elemArr[i].hasAttribute(att);
if (workingAtt && elemArr[i].getAttribute(att) === value) {
elemArr[i].setAttribute(att, replacement);
}
}
}
removeLink("link", "href", "filePath", "#");
And it will work.
A more succint approach would be something like this:
function removeLink(elem, att, value, replacement){
var selector = elem + '['+ att +'="'+ value +'"]';
[].forEach.call(document.querySelectorAll(selector), function(node){
node.setAttribute(att, replacement);
});
}
It does basically the same thing, but is quite a bit shorter and more explicit.
.hasAttribute() returns a boolean true or false. Therefore, workingAtt will either equal true or false. Boolean values are not HTMLElements, therefore they do not have value attributes. That's why there's an error.
It looks like you're trying to do something like select elements where there is a href attribute.
If so, you can just filter them:
var myElements = [];
[].filter.call(elemArr, function(el) {
if(el.hasAttribute(att)) {
myElements.push(el);
}
});
// then, do something with myElements
You have several errors in your code:
elemArr.hasAttribute instead of elemArr[i].hasAttribute.
var workingAtt = elemArr.hasAttribute(att); — here, workingAtt will be a boolean value, workingAtt.value is non-existent. You should use elemArr[i].getAttribute(att) and later use workingAtt, NOT workingAtt.value (it will be non-existent again!).
if (workingAtt.value === filePath) you're comparing to filePath while you should most definitely compare to value that you pass in the function.
I've been having a hard time with cross browser compatibility and scrapping the dom.
I've added data analytics tracking to ecommerce transactions in order to grab the product and transaction amount for each purchase.
Initially I was using document.querySelectorAll('#someId')[0].textContent to get the product name and that was working fine for every browser except internet explorer.
It took some time to figure out that it was the .textContent part that was causing ie problems.
Yesterday I changed .textContent to .innerText. From looking inside analytics it seems that the issue has been resolved for ie but now Firefox is failing.
I was hoping to find a solution without writing an if statement to check for the functionality of .textContent or .innerText.
Is there a cross browser solution .getTheText?
If not what would be the best way around this? Is there a simple solution? (I ask given my knowledge and experience with scripting, which is limited)
** added following comments **
If this is my code block:
// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');
for(var i = 0; i < brand.length; i++) {
//set granular vars
var prd = {};
//add to prd object
prd.brand = brand[i].innerText;
prd.name = name[i].innerText;
prd.price = price[i].innerText;
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;
//add to prods array
prods.push(prd);
}
Then if I understand the syntax from the comments and the question linked to in the comment, is this what I should do:
// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');
for(var i = 0; i < brand.length; i++) {
//set granular vars
var prd = {};
//add to prd object
prd.brand = brand[i].textContent || brand[i].innerText;
prd.name = name[i].textContent || name[i].innerText;
prd.price = price[i].textContent || price[i].innerText;
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;
//add to prods array
prods.push(prd);
}
So using or with a double bar || assigns the first non null value?
Re: your edit, not quite. The way to access methods or properties on an object (eg a DOM element) is to use dot notation if you have the name itself, or square brackets in case of variables/expressions (also works with strings, as in obj["propName"], which is equivalent to obj.propName). You can also just test the property against one element and use that from there on:
// build products object
var prods = [];
var brand = document.querySelectorAll('.txtStayRoomLocation');
var name = document.querySelectorAll('.txtStayRoomDescription');
var price = document.querySelectorAll('.txtStayRoomSplashPriceAmount');
for(var i = 0; i < brand.length; i++) {
//set granular vars
var prd = {};
//add to prd object
var txtProp = ("innerText" in brand[i]) ? "innerText" : "textContent"; //added string quotes as per comments
prd.brand = brand[i][txtProp];
prd.name = name[i][txtProp];
prd.price = price[i][txtProp];
prd.quantity = window.session_context_vars.BookingContext.Booking.ReservationLineItems[i].ReservationCharges.length/2;;
//add to prods array
prods.push(prd);
}
Regarding the line:
var txtProp = (innerText in brand[i]) ? innerText : textContent;
The in keyword checks an object to access the property (syntax: var property in object). As for the question notation (I made an error earlier, using ||, the correct thing to use was a :),
var myVar = (prop in object) ? object[prop] : false;
As an expression, it basically evaluates the stuff before the ?, and if it's true, returns the expression before the :, else the one after. So the above is the same as / a shorthand for:
if(prop in object){
var myVar = object[prop];
}
else{
var myVar = false;
}
Since you are checking between two properties only and wanting to assign one or the other, the shortest way would indeed be:
var txtProp = brand[i].innerText || brand[i].textContent;
It would basically test the first property, and if it were false or undefined, it would use the second one. The only reason I (pedantically) avoid using this is because the first test of a || b would fail even if a existed but just had a value of 0, or an empty string (""), or was set to null.
So I have html page called A.html it was called like this from B.html : A.html?varString="bla-bla-bla" Is it correct for sending args to JS? How to parse args from JS?
(not using any frameworks like Jquery, working in IE6, FireFox 3)
Here is a function to parse the query string. Pass it the parameter name and it returns the value.
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
if (pair[0] == variable)
{
return pair[1];
}
}
return -1; //not found
}
Use location.search:
alert(location.search); // will display everything from the ? onwards
You probably want to separate the different variables from the query string so that you can access them by name:
var request = {};
var pairs = location.search.substring(1).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
request[pair[0]] = pair[1];
}
Then you can access it like request['varString'] and that will give you "bla-bla-bla".
Mostly you'd like to handle the parameters passed to your page in the server side, but if you got your reasons why to do it client-side, here's a small script i found:
function gup( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
i didn't test it, but i'm pretty sure it'll to the job.
just use it like: gup('parameter') and it'll return the parameter value for you.
To parse the query string through JS, you can view use something like
function getQueryValue(param) {
var queryStringArray = querystring && querystring.substring(1).split("&");
for (var i=0, length = queryStringArray.length; i < length; i++) {
var token = queryStringArray[i],
firstPart = token && token.substring(0, token.indexOf("="));
if (firstPart === param ) {
return token.substring(token.indexOf("=") + 1, token.length);
}
}
}
E.g. Given a URL "http://domain.com.au?aaa=bbb , you can call this fn as getQeuryValue("aaa") and you'll get "bbb"
I uploaded this code on Gist (bit modified to be compliant with a module pattern).
Thanks to the new URLSearchParams interface, it becomes easier:
var url = new URL("https://example.org/?foo=bar&foo2=bar2");
var params = url.searchParams;
// Access to a variable
console.log(params.get("foo"));
// Loop over params
for (var key of params.keys()) {
console.log(params.get(key));
}
You should check Mozilla Developer Network for browser compatibility, since it's a new API.
Anyone know the quickest way to grab the value of a CGI variable in the current URL using Prototype? So if I get redirected to a page with the following URL:
http://mysite.com/content?x=foobar
I am interested in retrieving the value of "x" (should be "foobar") in a function called on page load like this:
Event.observe(window, "load", my_fxn ());
Thanks
You may want to look at the parseQuery method. This should do all the splitting you'd expect on a standard querystring such as document.location.search
http://api.prototypejs.org/language/string.html#parsequery-instance_method
For example:
document.location.search.parseQuery()["x"];
Will be undefined if it's not present, and should be the value otherwise.
I couldn't find any shortcuts here, so in the end I just parsed the URL with js like so:
function my_fxn () {
var varsFromUrl = document.location.search;
// get rid of first char '?'
varsFromUrl = varsFromUrl.substring(1);
var pairsArray = varsFromUrl.split("&");
for (i = 0; i < pairsArray.length; i++) {
var pair = pairsArray[i].split("=");
if (pair[0] == "x")
alert(pair[1] + ' is what I want.');
}
}