I have a click function on a button that adds an item to my cart using the Minicart.js library from minicartjs.com. When the button is clicked items are being added to the cart however, the cart is not popping up as expected. I've tested this on up to date versions of Chrome and IE (ie 11).
Some things I've noticed:
In the debugger if I execute the show cart function
paypal.minicart.view.show() the cart displays fine. Even with the
items I've added.
When my add button is clicked "class" is appended to the body with no
actual class assigned:
When the cart is showing a class "minicart-showing" is appended to
the body.
The following script is at the end of a MVC partial View:
<script src="~/Scripts/minicart.js"></script>
<script>
$(".showcart").click(function () {
var data = $(this).attr("data-id");
paypal.minicart.cart.add(JSON.parse(data));
// $("#body").toggleClass("minicart-showing"); <---doesn't work
// paypal.minicart.view.show() <---- doesn't work
});
paypal.minicart.render();
</script>
After further reviewing the minicartjs examples in the author's repository. I found that using e.stopPropagation() within the click function resolves the issue.
$(".showcart").click(function (e) { // <--- added the e function
var data = $(this).attr("data-id");
e.stopPropagation(); // <--- And this line.
paypal.minicart.cart.add(JSON.parse(data));
});
Code Example From Author's GitHub Repo
Related
I am using Shopify "Streamline Theme" with quick product view and I recently added infinite scroll to products on each collection using Ajaxinate.js.
When I open a collection page it loads with some products which is supposed to do, The products already there work fine with quick view and quick add to cart and also.
The Infinite scroll works fine and it loads new product fine but the problem is raised when the new products loaded through AJAX call doesn't have work with the quick view function.
I have tried to create a callback function to activate the quick view with no success, using the theme initialisation code with no success.
function callBack(){
theme.init();
theme.initQuickShop();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "scroll",
loadingText: 'Loading...',
callback: callBack
});
});
Edit -------
My problem, is that when the page is loaded only the initial loaded products quickview elements are loaded in the DOM. When the scroll more button is clicked, the newly loaded products are loaded without their respective quickview elements. Hence why the quickview does't work for them. The theme.js file comes with this initialisation code:
theme.reinitProductGridItem = function($scope) {
if (AOS) {
AOS.refreshHard();
}
if (theme.settings.currenciesEnabled) {
theme.currencySwitcher.ajaxrefresh();
}
// Reload quick shop buttons
theme.initQuickShop(true);
// Refresh reviews app
if (window.SPR) {
SPR.initDomEls();SPR.loadBadges();
}
// Re-register product templates in quick view modals.
// Will not double-register.
sections.register('product-template', theme.Product, $scope);
// Re-hook up collapsible box triggers
theme.collapsibles.init();
};
I have tried to integrate this into a callback but no success, the quickview modal doesn't seem to load for the newly loaded products:
function callBack(){
ReloadSmartWishlist();
var $container = $('#CollectionSection');
theme.reinitProductGridItem($container);
// I have tried the following init qith no success:
// theme.init();
// theme.initQuickShop(true);
// theme.initQuickShop();
// sections.register('product-template', theme.Product, $container);
// AOS.refreshHard();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "click",
loadingText: 'Loading...',
offset: 0,
callback: callBack
});
});
I am missing something but what? :/
Note for other things like loading products images with the callback and the wishlist app, it works as intended...
When you load elements via AJAX and if the events are not attached to a parent element that is not removed from the DOM, those elements will not have an attached event to them.
The term used here is event delegation.
Here is an example of non-delegated event:
document.querySelectorAll('a').addEventListener('click', function(){
// Do something
})
Since you are attaching the event to the existing "a" elements if you add new 'a' via AJAX those elements will not have the event since Javascript already attached all the events and it will not reattach them if you don't specifically recall them again.
Here is an example of a delegated event:
document.querySelector('body').addEventListener('click', function(target){
let target = event.target;
if (target.tagName === 'A'){
// Do something here
}
})
Where we attach the event to the body tag ( where it's a better idea to attach it to a closer none-modified parent element of the ajax items ) and once we click we check if our target tag is an "a" and do something then.
So long story short, you will need to delegate the quick cart link so that it works after you load the items via AJAX.
Drip is correct you need to delegate your event, but for people like me it's hard to completely understand how to do that.
I'm not sure how your quickview is structured, but if you open it with a .click function and can use jquery use the [.on() function][1].
For example: I use a quickview that opens on a button click. My button is attached to my product-grid-item.liquid with this bit of code:
<div class="quick-view-button">
<a class="quick-view" data-handle="{{ product.handle }}" href="javascript:void(0);">Quick View</a>
</div>
My quickview function originally looked like this:
function quickView() {
$(".quick-view").click(function () {
//all of the quickview code
What happens is exactly like you described. The event listeners only loaded on the first product load but nothing after an AJAX load.
Using jquery's .on() binds the event listener to the element meaning when it's loaded in later it'll still have the event. Here's an example of what my code looks like after using .on()
function quickView() {
$('body').on('click','.quick-view',function(){
I really hope this helps you or someone else with this problem.
[1]: http://api.jquery.com/on/
Is there a way in prestashop to show a confirmation message before an item is removed from the cart in prestashop 1.7? I'd just like to be pointed to the file that contains this method so that I may be able to add a confirm dialog, since right now a user can just delete without confirmin
Yes, you can show confirm dialog before deleting item from cart. By default core.js and theme.js file handles all events and update cart accordingly on updateCart event. (Refer more on events here)
To overcome default behaviour adding js prior to theme.js will help us to prevent default click event. Follow below mentioned step by step guide to load you own js and add confirmation dialog on item delete.
1) Register your js in theme.yml (More details here) by adding below code under assets
themes/{your_theme}/config/theme.yml
assets:
js:
cart:
- id: cart-extra-lib
path: assets/js/cart-lib.js
priority: 30
2) Create file cart-lib.js under themes/{your_theme}/assets/js and add below code into it.
themes/{your_theme}/assets/js/cart-lib.js
function refreshDataLinkAction() {
$('[data-link-action="delete-from-cart"]').each(function(){
$(this).attr('data-link-action', 'confirm-remove-item');
});
}
$(document).on('click', '[data-link-action="confirm-remove-item"]', function(e) {
e.preventDefault();
if (confirm('Are you sure you want to remove product from cart?')) {
$(this).attr('data-link-action', 'delete-from-cart');
$(this).trigger('click');
}
return false;
});
$(document).ready(function () {
refreshDataLinkAction();
prestashop.on('updatedCart', function (event) {
refreshDataLinkAction();
});
});
3) Now, to load your js file you need to delete file config/themes/{your_theme}/shop1.json (Reference)
4) Add products to cart and check cart; delete items you will see confirmation message. Attaching image for reference.
I am using some simple jquery to show view cart button if something has been added to the cart.
if ( $('.cartSummaryItem').text() != 'Shopping cart is empty.' ) {
$('.account').fadeIn(1000)
};
If the cart is empty it show this the text "Shopping cart is empty.", if something is added .account will fadeIn. The problem is I need to refresh the page for this to work, is there a way to do this without refreshing the page with ajax or similar?
Thanks
Nik
If the change event doesn't work. Another method is using an Interval.
<script type='text/javascript'>
$(document).ready(function()
{
setInterval(function () {
if ( $('.cartSummaryItem').text() != 'Shopping cart is empty.' ) {
$('.account').fadeIn(1000)
};
}, 10000);
});
</script>
Ofcourse, the interval should be changed to your desired amount. I would only use this if the change doesn't work.. The change event is prefered.
Well, I guess you have two choices
Call the javascript code after the user has changed the contents of the cart
Poll the server for cart changes
If you can, you should probably go for the first choice. Are you in control of the code that changes the contents of the cart?
I have an image that is in my apex application with the id tag of submit_button. I want to display an alert when the user tries to click this image but for some reason nothing is happening. In my header on the page I have this code
<script type="text/javascript">
$(document).ready(function() {
$('#submit_button').click(function) {
alert('hi');
}
});
</script>
Any ideas?
I don't know why that doesn't work (it doesn't work for me either, I just tried), but it is very simple to do via a dynamic action with the following properties:
Event = click
Selection Type = DOM Object
DOM Object = submit_button
"True" Action = Execute Javascript Code
Fire on page load = (unchecked)
Code = alert('hi');
I am developing a website that parses rss feeds and displays them based on category. You can view it here: http://vitaminjdesign.com/adrian
I am using tabs to display each category. The tabs use ajax to display a new set of feeds when they are clicked.
I am also using two other scripts- One called equalheights, which re-sizes all of the heights to that of the tallest item. And the other script I am using is called smart columns, which basically resize your columns so it always fills the screen.
The first problem I am having is when you click a new tab (to display feeds within that category). When a new tab is clicked, the console shows a jQuery error:
$(".block").equalHeights is not a function
[Break On This Error] $(".block").equalHeights();
The main problem is that each feed box fills up the entire screen's width (after you click on a tab), even if there are multiple feed boxes in that category.
MY GUESS - although all of the feeds (across all tabs) are loaded on pageload, when a new tab is selected, both jQuery scripts need to be run again. any ideas on how I can make this work properly?
One thing to note - I used the ajaxSuccess method for making equalHeights work on the first page...but it wont work after a tab is clicked.
My jQuery code for the tabs are below:
$(".tab_content").hide(); //Hide all content
$("ul.tabs li:first").addClass("active").show(); //Activate first tab
$(".tab_content:first").show(); //Show first tab content
$("#cities li:nth-child(1)").addClass('zebra');
$("#column li ul li:nth-child(6)").addClass('zebra1');
//On Click Event
$("ul.tabs li").click(function() {
$("ul.tabs li").removeClass("active"); //Remove any "active" class
$(this).addClass("active"); //Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
var activeTab = $(this).find("a").attr("href"); //Find the href attribute value to identify the active tab + content
$(activeTab).fadeIn(); //Fade in the active ID content
$(".block").equalHeights();
return false;
});
Thanks to Macy (see answer below), I have brought my jQuery script to the following: (still does not work)
$(document).ajaxSuccess(function(){
var script = document.createElement('script');
script.src = 'js/equalHeight.js';
document.body.appendChild(script);
equalHeight($(".block"));
I found some small problems in your code. I am not sure that my suggestions will solve all the problems, but I decide to describe my first results here.
1) You should remove comma before the '}'. Currently the call look like $("#column").sortable({/**/,});
2) The function equalHeight is not jQuery plugin. It is the reason why the call $(".block").equalHeights(); inside your 'click' event handler follows to the error "$(".block").equalHeights is not a function" which you described. You should change the place of the code to equalHeight($(".block")); like you use it on other places.
3) The script http://vitaminjdesign.com/adrian/js/equalHeight.js defines the function equalHeight only and not start any actions. Once be loaded it stay on the page. So you should not load it at the end of every ajax request. So I suggest to reduce the script
$(document).ajaxSuccess(function(){
var script = document.createElement('script');
script.src = 'http://vitaminjdesign.com/adrian/js/equalHeight.js';
document.body.appendChild(script);
equalHeight($(".block"));
$("a[href^='http:']:not([href*='" + window.location.host + "'])").each(function() {
$(this).attr("target", "_blank");
});
});
to
$(document).ajaxSuccess(function(){
equalHeight($(".block"));
$("a[href^='http:']:not([href*='" + window.location.host + "'])").each(function() {
$(this).attr("target", "_blank");
});
});
4) I suggest to change the code of http://vitaminjdesign.com/adrian/js/equalHeight.js from
function equalHeight(group) {
tallest = 0;
group.each(function() {
thisHeight = $(this).height();
if(thisHeight > tallest) {
tallest = thisHeight;
}
});
group.height(tallest);
}
to
function equalHeight(group) {
var tallest = 0;
group.each(function() {
var thisHeight = $(this).height();
if(thisHeight > tallest) {
tallest = thisHeight;
}
});
group.height(tallest);
}
to eliminate the usage of global variables tallest and thisHeight. I recommend you to use JSLint to verify all your JavaScript codes. I find it very helpful.
5) I recommend you to use any XHTML validator to find some small but sometime very important errors in the markup. Try this for example to see some errors. The more you follow the XHTML standards the more is the probability to have the same results of the page in different web browsers. By the way, you can dramatically reduce the number of the errors in your current code if the scripts included in the page will be in the following form
<script type="text/javascript">
//<![CDATA[
/* here is the JavaScript code */
//]]>
</script>
I didn't analysed the full code but I hope that my suggestions will solve at least some of problems which you described in your question.
Essentially, when you add a new element to the document, the equalheights script has not attached its behavior to that new element. So, the "quick fix", is probably to re-embed the equalheights script after an ajax request has completed so that it re-attaches itself to all elements on the page, including the elements you just added.
Before this line: $(".block").equalHeights(); , add a line of script which re-embeds/re-runs your equalheights script.
$.getScript('<the location of your equalHeightsScript>');
$.getScript('<the location of your smartColumnsScript>');
$(".block").equalHeights();
or
var script = document.createElement('script');
script.src = '<the location of your script>';
document.body.appendChild(script);
A better solution would be to upgrade the plugin so it takes advantage of live. However, I'm not up to that at the moment :)
Some Error Here
$("ul.tabs li").click(function() {
$("ul.tabs li").removeClass("active"); //Remove any "active" class
$(this).addClass("active"); //Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
.
.
.
});
Should be re-written like this
$("ul.tabs li").click(function() {
$(this).addClass("active").Siblings("li").removeClass("active");; //Remove any "active" class Add "active" class to selected tab
$(".tab_content").hide(); //Hide all tab content
.
.
.
});
I don't think you need to run the scripts again after the ajax, or at least that's not the "main" problem.
You seem to have some problems in the script smartColumn.js
Right now it seems to only operate on the ul with the id "column" ('#column'), and it is working on the one UL#column you do have, but of course your HTML has many other "columns" all of which have the class "column" ('.column') that you want it to work on as well.
Just to get the beginning of what you are trying to do, change all the selectors in smartColumn.js that say 'ul#column' to say 'ul.column' instead, and then alter the HTML so that the first "column" has a class="column" rather than an id="column".
That should solve the 100% wide columns at least.
That should solve your "Main" Problem. But there are other problems.