How to get updated URL parameters after a jQuery change event - javascript

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.

Related

Populate select drop-down based on choice of another select form field

Here is my fiddle : DEMO
Under the "Rules" Tab, on click of "+" a group of form-fields are cloned i.e, Join operator, Attributes, Operator & Threshold.
The attribute drop down is populated using a json (called expressionDetails) created using the relationship between contracts and thresholds variables.
Based on the choice of attributes, the thresholds field will be populated.
I could achieve this for the non-cloned Attribute and Threshold. However, due to class/ id duplication I am not able to pick up the cloned attribute's value as all the clones attributes hold the same class and their values are getting concatenated (in var z1).
//Appending option to "cloned" thresold field based on choice of attribute
$('.attributeExpr').on('change', function(e) {
$('.thresholdExpr').empty();
var z1 = $(".attributeExpr option:selected").text();
console.log(z1);
var a1 = expressionDetails[z1];
console.log(a1);
for (var i1 = 0; i1 < a1.length; i1++) {
var b1 = a1[i1].name;
// alert(b1);
var opt1 = $("<option>").text(b1);
// console.log(opt1);
$('.thresholdExpr').append(opt1);
}
});
Is there a different approach for this? Also, it should work for every cloned group thereafter as I will be using all of these values to create the "Expression" field.
Any help would be much appreciated. Thank you.
Replace the line 3 in above code with this. it will only return selected value.
var z1 = $("option:selected",$(this)).text();
Have you tried something like:
var z1 = $(this).find('option:selected').text();
Instead
var z1 = $(".attributeExpr option:selected").text();
Try this, I have tested it in your fiddle DEMO and it is working.
$('.attributeExpr').on('change', function(e) {
var index = $(this).index('.attributeExpr');
$('.thresholdExpr:eq( '+index+' )').empty();
var z1 = $(this).find("option:selected").text();
console.log(z1);
var a1 = expressionDetails[z1];
console.log(a1);
for (var i1 = 0; i1 < a1.length; i1++) {
var b1 = a1[i1].name;
// alert(b1);
var opt1 = $("<option>").text(b1);
// console.log(opt1);
$('.thresholdExpr:eq( '+index+' )').append(opt1);
}
});
I have added index so it can target the current element.
First thing you should do to make it work properly specially such complex implementation is to make the expressionsBuilder formgroup option fields to be dynamic, means it is being populated by JavaScript and not hard-coded in your HTML.
Then, you will assign the change event listener for each individual fields you created, this way you can control every form-group's behavior.
example click here
by populating it programatically you have total control of the fields behavior. You can then get each and every value of fields by iterating expressions variable like this:
for (var i = 0; i < expressions.length; i++)
{
var id = expressions[i];
var theAttribute = $("#" + id).find("[name='attribute']").val();
var theOperator = $("#" + id).find("[name='operator']").val();
var theThreshold = $("#" + id).find("[name='threshold']").val();
}
Hope that helps
===
ALSO heads up, it appears you are creating such complex application. I am suggesting you should make use for JavaScript frameworks to ease up maintainability of your code. This approach will become very hard to maintain in the long run

Dynamically Change HTML Content Using a URL Variable [duplicate]

This question already has answers here:
How can I get query string values in JavaScript?
(73 answers)
Closed 7 years ago.
I have been struggling with dynamically changing HTML content using URL variables. Let me give you an example and than provide you my code thus far.
Ex. I have a landing page with content to be changed. I would like to have a variable in my URL www.domain.com/header=new-content
I would like to be able to rewrite the HTML to show the new header using Javascript or Jquery. Here is what I have thus far. Seems like I am missing the trigger or if/else statement.
Thank you so much!
<script>
var element = document.getElementById("header");
element.innerHTML = "New Content";
</script>
First of all, when you're dealing with URL parameters, you should place a ? before you start defining parameters. This will result in the browser retrieving the page www.foo.bar/ instead of www.foo.bar/header=new-content. Once you add the question mark, you can retrieve URL parameters using the following snippet. I retrieved this from this question.
function getUrlParameter(sParam)
{
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++)
{
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == sParam)
{
return sParameterName[1];
}
}
}
In your specific case, your final code, after defining the above function, might look something like this:
<script>
var header = getUrlParameter('header');
document.getElementById('header').innerHTML = header;
</script>
This will retrieve the URL parameter header and change the value of the element with ID header to the value contained in the URL. For the URL www.foo.bar/?header=new-content, the element's value would be changed to new-content. If you want to have spaces in the variable, you can remove the URL-encoded characters (ex. %20 for space) by changing the first line in the above snippet to this:
var header = decodeURIComponent(getUrlParameter('header'));
Last minute addition: I just noticed that another answer with more-or-less the same code snippet came in while I was writing this. Whoops. :)
You could read the url and extract the desired paramenter with a function such as:
function fGetUrlParameter(sParam) {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == sParam) {
return sParameterName[1];
}
}
};
So if you are accessing a url such as:
http://www.domain.com/?header=new-content
You could store the parameter in a variable
var stringHeader = fGetUrlParameter("header")
and modify your element html
var element = document.getElementById("header");
element.innerHTML = stringHeader;
I'm not sure I understood your question.
Assuming that you want to pass a parameter using the URL the correct way to rewrite your url would be
www.domain.com?header=new-content
That would make your variable named header equal the value of new-content.
The way to extract your data would be:
<script>
var element = document.getElementById("header");
//use your variable
</script>

Sorting elements in array

I have an array containing a list of images that I have stored online:
var imgs = ["img1","img2","img3"...];
They are displayed as such:
var child, i;
for (i = 0; i < imgs.length; i++) {
child.style.backgroundImage = 'url(https://mywebsite/images/' + imgs[i] + '.jpg)';
$('body').append(child);
}
However, I'm looking to try to display the images based on their attribute, that can change depending on a user action.
This attribute will look like this:
child.setAttribute("class", 0);
Say for example, the user decides to click on an image, then the attribute of the image he clicked on will increment. So the class will no longer be '0' but '1'. And because of so, the image will be placed before the others in the array.
Assuming 'img2' was clicked, then the array would look like:
imgs = ["img2","img1","img3"...];
I feel like the method I'm going by is inefficient and I have considered using objects or even 2d arrays, but I'm not sure where to start and lack experience. However, if this isn't "such a bad way" to get started, then I'd appreciate if someone showed me how I could move the elements in the array.
Thanks in advance.
You can try this:
$('body').find("img").on("click", function()
{
$(this).data("count", (Number($(this).data("count")) + 1));
reOrderImages();
});
function reOrderImages()
{
var imgs = $('body').find("img");
for (var i = 0; i < imgs.length; i++)
{
var img1 = $(imgs[i]);
var img2 = (imgs.length > (i + 1) ? $(imgs[(i + 1)]) : false);
if (img2 && Number(img1.data("count")) < Number(img2.data("count")))
{
img1.before(img2);
}
}
};
Fiddle. Here I'm using data attributes instead of the class attribute, which isn't designed for your case. It just swaps the elements with before() method.
You can use array.sort with a compare function. getClass method here is some method which returns current class attribute of an image by it's url
imgs.sort(function(img1, img2){
var class1 = getClass(img1);
var class2 = getClass(img2);
return class1 - class2;
})
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

textContent Vs. innerText Cross Browser solution

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.

Pass URL parameter to href using JavaScript

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')

Categories