I have a product page on Shopify with an Add to Cart button.
On click, the product gets added to cart and page redirects to another upsell product.
After they add upsell product to cart, it goes to checkout page BUT it's only displaying the upsell product and not the first product user wanted to buy. What's wrong with the code below?
How do I make both products appear in checkout?
<script>
function redirectToUpsellPageHandler(wrapper) {
var upsellPageUrl = '/clientproducts/cryogenic-storage';
var addToCartButton = wrapper.querySelector('.sqs-add-to-cart-button');
var productVariants = wrapper.querySelector('.product-variants');
if (addToCartButton) {
addToCartButton.addEventListener('click', onClick);
}
function isVariantInStock() {
return productVariants.getAttribute('data-variant-in-stock');
}
function onClick() {
if (productVariants && isVariantInStock() || !productVariants) {
setTimeout(function() {
document.location.href = upsellPageUrl;
}, 1000);
}
}
}
function redirectToUpsellPage() {
// Product Page
var productPage = document.querySelector('.collection-type-products.view-item');
if (productPage) {
redirectToUpsellPageHandler(productPage);
}
// Product Blocks
var productBlocks = [].slice.call(document.querySelectorAll('.sqs-block-product'));
productBlocks.forEach(redirectToUpsellPageHandler);
}
document.addEventListener('DOMContentLoaded', redirectToUpsellPage);
window.addEventListener('mercury:load', redirectToUpsellPage);
</script>
Add some console.logs and make sure you're getting into your onClick function. If you're not there may be some type of issue with using a function named onClick since that is a reserved function in jQuery or JS.
Related
Im trying to do quiz with HTML and Javascript where users are allowed 2 attempts at the quiz.
When users finish and submit the quiz answer, a result.html will pop up with score and attempt. After the first attempt, the user can use a button to redo the quiz and the button will disappear after the second attempt. But I cant get it to redirect back to the quiz after showing the result the first time.
Quiz.js
function showInfo() {
if(sessionStorage.attempt == undefined){
var attempt = 1;
document.getElementById("attempt").textContent = attempt;
getInfo();
sessionStorage.attempt = attempt + 1;
}
else {
document.getElementById("attempt").textContent = sessionStorage.attempt;
getInfo();
document.getElementById("btn-try").style = "DISPLAY:none";
}
}
I tried to limit the attempt in this function then called it in the init() function however, the result.html just refresh and the attempt goes up to 2.
function tryAgain() {
window.location= "quiz.html";
}
function init() {
if (document.getElementById("quizform") != null)
{
var regForm = document.getElementById("quizform");
regForm.onsubmit = validate;
} else {
showInfo();
document.getElementById("btn-try").onclick = tryAgain;
}
}
I am working on a simple script that loops through all elements on a page and shares them in vanilla JavaScript. Here is what I have so far
var buttons = document.getElementsByClassName('share-gray-large');
for(var i=0; i<buttons.length; i++){
buttons[i].click();
document.getElementsByClassName('internal-share__link')[0].click();
}
The share-gray-large button is the class of the "share" buttons. Once the first share button is clicked, a modal appears that asks the user where they want to share the items to. I need to click the first item in the modal with class name internal-share__link. The problem that I am running up against is the fact that the last line of my code results in the following error
Uncaught TypeError: Cannot read property 'click' of undefined
which makes sense, as the modal hasn't appeared yet at the time of the second click() function being called. I need to wait for the element to appear, then click it, then wait until the modal disappears to share the next item. I've looked into async/await functions, setTimeout(), and the solutions from similar StackOverflow questions. I adapted this secondary solution
var waitForEl = function(className, callback) {
if (document.getElementsByClassName(className).length) {
callback();
} else {
setTimeout(function() {
waitForEl(className, callback);
}, 100);
}
};
var buttons = document.getElementsByClassName('share-gray-large');
for(var i=0; i< buttons.length; i++){
waitForEl('share-gray-large', function() {
document.getElementsByClassName('share-gray-large')[i].click();
});
waitForEl('internal-share__link', function() {
document.getElementsByClassName('internal-share__link')[0].click();
});
}
which kind of works, but I believe that it actually ends up sharing the last item multiple times instead of sharing all of them in order. I ran into this issue of needing to wait for a button to appear as well with a different project, so any help would be greatly appreciated!
TL;DR I'm working on projects with the following sequence of steps. Using a page with 3 items that need to be shared:
Click "share" on first button
Wait for confirmation button to appear in a modal
Click confirm
Wait for modal to disappear
Click "share" on second button
Repeat steps 2-4
Click "share" on third button
Repeat steps 2-4
How do you do this in VanillaJS?
This will click from the last to first share button, email share exluded and make sure the browser is allowed to click/open multiple popup.
function waitForElement(selector) {
var element = document.querySelectorAll(selector);
if (element.length) {
if (shareLinkCount == 999) { // set to real number of elements
shareLinkCount = element.length;
}
shareLinkCount--;
var shareElement = element[shareLinkCount];
if(shareElement.textContent != "Email") // Do not click email share
element[shareLinkCount].click();
if (shareLinkCount) { // not 0
setTimeout(clickShareButton, 500);
}
else{
alert('Click Finished');
document.body.click();
}
} else {
setTimeout(waitForElement, 500, selector);
}
}
function clickShareButton() {
var button = document.querySelector('.share-gray-large');
button.click();
waitForElement('internal-share__link');
}
var shareLinkCount = 999; // dummy number
clickShareButton();
This is the answer that worked for me. Credit goes to #uingtea for most of the solution. Since I did not post the link to the website, I was able to test it and modify their solution to suit my needs.
function waitForElement(selector) {
var element = document.querySelector(selector);
if (element) {
shareLinkCount--;
element.click();
if (shareLinkCount) { // not 0
setTimeout(clickShareButton, 500);
}
else{
element.click();
alert('Click Finished');
}
} else {
setTimeout(waitForElement, 500, selector);
}
}
function clickShareButton() {
document.querySelectorAll('.share-gray-large')[shareLinkCount].click();
waitForElement('.internal-share__link');
}
var shareLinkCount = document.querySelectorAll('.share-gray-large').length - 1;
clickShareButton();
I'm making a javascript game and once the user finished the game, the user will enter their initials and hit submit. Once they hit submit, it'll redirect them to a new page (end.html). I'm not sure if I've set up my click event incorrectly or I'm using the wrong location.href. But, when I hit the submit button, it brings the user back to the start screen(index.html), instead of the end (highscore) page.
The script tag is located on the bottom of the HTML pages, tags are correctly named. I tried the DOMContentLoaded function and that didn't seem to work. If I need to provide more of my code, please let me know.
here's the js snippet
submitScore.addEventListener("click", function () {
var initials = document.getElementById("initials").value;
// calling highscore page function
endPage(initials, time);
});
function endPage(inits, scores) {
var userData = {
inits: inits,
scores: scores
};
highscores.push(userData);
localStorage.setItem("userData", JSON.stringify(highscores));
location.href = "end.html"
}
I personally have never used location.assign - have you tried location.replace()?
submitScore.addEventListener("click", function () {
var initials = document.getElementById("initials").value;
// calling highscore page function
endPage(initials, time);
});
function endPage(inits, scores) {
var userData = {
inits: inits,
scores: scores
};
highscores.push(userData);
localStorage.setItem("userData", JSON.stringify(highscores));
location.replace(`${location.origin}/end.html`);
// get base url and append 'end.html'
}
EDIT [for others confused]: Actual bug was that the button was being submitted - bravo epascarello for this code:
submitScore.addEventListener("click", function (evt) {
evt.preventDefault(); // prevent default behaviour of event
I'm still trying to master jQuery, AJAX, and JSON.
On my application, I have the following dropdown select menu:
<select id="serviceload" name="serviceload"></select>
I auto populate the OPTIONS with another function which I don't think is necessary to display here. Just know that the above SELECT has 1 or more OPTION values.
This is followed by the content section:
<div class="row" id="completeProfile">
// series of DIVS and TABLES
</div>
Initially, the content section is hidden, so the user will only see the dropdown menu:
$('#completeProfile').hide();
And now, the jQuery: this next piece of code is what I use when the user chooses a selection from the dropdown menu. Every time they pick a new selection, queries rerun, and new content is displayed to the screen, unless they select a blank OPTION.
$('#serviceload').change(function () {
var page = $('#serviceload').val();
if (page == "") {
$('#completeProfile').hide();
} else {
$.post('api/profileSearch.php', {
page: page
}, function (data) {
var obj = JSON.parse(data);
$('#portBody').empty();
var htmlToInsert = obj.map(function (item) {
return '<tr><td>' + item.PORT + '</td><td>' + item.NAME + '</tr>';
});
$('#portBody').html(htmlToInsert);
});
// I do several more $.post to return data into specific tables
// Take note of this next $.post
$.post('api/vesselSearch.php', {
page: page
}, function (data) {
var obj = JSON.parse(data);
$('#vesselinfo').empty();
var htmlToInsert = obj.map(function (item) {
return '<tr><td>Edit</td><td>' + item.VESSEL_NAME + '</td></tr>';
});
});
// after all the queries are ran, and the data is returned, now we show the content
$('#completeProfile').show();
}
});
In the vesselInfo portion above, there is section that prints a hyperlink with which you can click, and it opens a modal window. This is for editing purpose. This functions properly.
Here is where the issue lies.
Back in the content section, there is another hyperlink that opens a modal window to add a new vessel.
<h3>Vessels</h3> / Add New
This opens an Add New Vessel modal. In that modal there is a FORM with a button that reads like this:
<button type="button" id="addVesselSubmit">Add</button>
When this button is clicked, it sends the values entered by the user to a PHP script which updates a table.
$('#addVesselSubmit').click(function () {
var addservice = $('#addservice').val();
var addvessel = $('#addvessel').val();
$.post('api/addInfo.php', {
addservice: addservice,
addvessel: addvessel
}, function (data) {
// here is where my problem lies
if (data == 0) {
alert("Vessel was not saved");
} else {
alert("Vessel was saved");
// At this point, I need to rerun the main function above so that it shows the vessel that was added immediately to the content section without a page refresh
}
});
});
So in the code directly above, if the new record was successfully saved to the table, the whole content section should rerun without a page refresh, with the new record automatically showing in the vesselInfo section.
I think the code that is used to display the content needs to be turned into a main function that can be called when the addVesselSubmit is successful, but I am not sure how to proceed with that.
To reiterate my question: I need to be able to save a new record, and print the new record to the page without a page refresh.
$.post('api/addInfo.php', {
addservice: addservice,
addvessel: addvessel
}, function (data) {
// here is where my problem lies
if (data == 0) {
alert("Vessel was not saved");
} else {
alert("Vessel was saved");
// At this point, I need to rerun the main function above so that it shows the vessel that was added immediately to the content section without a page refresh
//Trigger a change on element
$('#serviceload').trigger('change');
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
}
});
$(document).ready(function() {
var session = {};
// Getting PHP session variables into javascript object in order to restric actions for certain users.
$.getJSON('session.php',function(data){
session = data;
console.log(session.role); // currently showing 2.
});
// Display datagrid on page
getRecords();
// If not admin, disable certain actions
if(session.role != 1){ // means it is 2
$("#deletecustomer").attr('class','btn btn-danger disabled');
}
});
Hi,
i m trying to disable the delete record button based on the user role. But i dont know why it is not updating the class of my button even though the console is showing role = 2.
Thanks
Since AJAX is asynchronous, please play with it in the callback:
$(document).ready(function() {
var session = {};
// Getting PHP session variables into javascript object in order to restric actions for certain users.
$.getJSON('session.php',function(data){
session = data;
console.log(session.role); // currently showing 2.
// Display datagrid on page
getRecords();
// If not admin, disable certain actions
if(session.role != 1){ // means it is 2
$("#deletecustomer").attr('class','btn btn-danger disabled');
}
});
});
EDIT: Without possibility to put thisinside the same parts of code, you can do:
var session = {};
var getSessionData = function(callback) {
$.getJSON('session.php',function(data){
session = data;
console.log(session.role); // currently showing 2.
// Display datagrid on page
callback.call();
});
}
var updateButton = function() {
getRecords();
// If not admin, disable certain actions
if(session.role != 1){ // means it is 2
$("#deletecustomer").attr('class','btn btn-danger disabled');
}
}
getSessionData(updateButton);