Want to stop a function when a button is clicked in jQuery - javascript

I have written some code for my Shopify store with jQuery. The work is that when a customer will come to my shop he will see a product added to the cart already.
The code works perfectly but the problem is when he clicks the remove button to remove that product the product is not being removed. It's actually removing but it's added again to the cart.
Is there any solution for this? I have an idea that if someone clicks the remove button then the function will not run again. Please tell me what the code should be?
Shopify = Shopify || {};
Shopify.cart = {{ cart | json }};
if (Shopify.cart !=='undefined' && Shopify.cart.items.length === 0) {
jQuery.post('/cart/add.js', {
quantity: 1,
id: 36507787624610,
}).always(function(data){
window.location.reload();
})
}

I don't know what theme you are using but this what you can do with your theme. I used debut theme.
Add following data attribute in your remove button html
item-id="{{ item.id }}"
After adding the above line, in debut theme it will look like this.
<a href="/cart/change?line={{ forloop.index }}&quantity=0" item-id="{{ item.id }}" class="text-link text-link--accent" aria-label="{{ 'cart.label.remove' | t: product: item.title }}" data-cart-remove>{{ 'cart.general.remove' | t }}</a>
Add the JS code in your theme.jS file. (Change the Variant ID according to your product)
//Adding product in cart
$.getJSON('/cart.js',function( data ) {
$( data.items ).each(function( index, item ) {
//Replace the ID with your variantID
if(item.id == 30329455837287) {
localStorage.setItem("item_removed", "1");
}
});
});
$('a.text-link.text-link--accent').click(function(){
var variant_id = $(this).attr('item-id');
console.log(variant_id);
if(variant_id == 30329455837287){
localStorage.setItem("item_removed", "1");
}
});
setTimeout(function(){
if( localStorage.getItem("item_removed") == "0" || localStorage.getItem("item_removed") == null ) {
$.post('/cart/add.js', {
quantity: 1,
//Replace the ID with your variantID
id: 30329455837287
});
}
}, 500);
});

Related

How to remove the selected data from saved data when we click on button in a selected one

In my application I have saved the data when we click on it(we can add the multiple data by entering some data and save the multiple data by clicking the save button).
.component.html
<ng-container *ngFor="let categoryDetail of selectedCategoryDetails">
<div class="__header">
<div>
<b>{{ categoryDetail.category }}</b>
</div>
</div>
<div
class="clinical-note__category__details"
*ngIf="categoryDetail.showDetails">
<ul>
<li class="habit-list"
*ngFor="let habits of categoryDetail.habitDetails" >
<div class="target-details">
<b>{{ clinicalNoteLabels.target }}: </b
><span class="habit-list__value">{{ habits.target }}</span>
</div>
</li>
</ul>
<div class="habit-footer">
<span class="m-l-10"
[popoverOnHover]="false"
type="button"
[popover]="customHabitPopovers"><i class="fa fa-trash-o" ></i> Delete</span>
</div>
<div class="clinical-note__popoverdelete">
<popover-content #customHabitPopovers [closeOnClickOutside]="true">
<h5>Do you want to delete this habit?</h5>
<button
class="btn-primary clinical-note__save" (click)="deletedata(habits);customHabitPopovers.hide()">yes </button>
</popover-content></div>
</div>
</ng-container>
In the above code when we click on delete button it will show some popup having buttons yes(implemented in above code) and now so my requirement is when we clcik on yes button in from the popover it has to delete the particular one.
.component.ts
public saveHealthyHabits() {
let isCategoryExist = false;
let categoryDetails = {
category: this.clinicalNoteForm.controls.category.value,
habitDetails: this.healthyHabits.value,
showDetails: true,
};
if (this.customHabitList.length) {
categoryDetails.habitDetails = categoryDetails.habitDetails.concat(
this.customHabitList
);
this.customHabitList = [];
}
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category === categoryDetails.category) {
isCategoryExist = true;
selectedCategory.habitDetails = selectedCategory.habitDetails.concat(
categoryDetails.habitDetails
);
}
});
}
if (!this.selectedCategoryDetails || !isCategoryExist) {
this.selectedCategoryDetails.push(categoryDetails);
}
this.clinicalNoteForm.patchValue({
category: null,
});
this.healthyHabits.clear();
public deletedata(habits){
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category ==categoryDetails.category) {
isCategoryExist = true;
this.selectedCategoryDetails.splice(habits, 1);
}
});
}
}
The above code I have written is for saving the data(we can enter multiple data and save multiple )
Like the above I have to delete the particular one when we click on yes button from the popover.
Can anyone help me on the same
If you're iterating in your html like:
<... *ngFor="let categoryDetails of selectedCategoryDetails" ...>
and your button with deletedata() is in the scope of ngFor, you can:
Change your iteration to include index of an item and trackBy function for updating the array in view:
<... *ngFor="let categoryDetails of selectedCategoryDetails; let i = index; trackBy: trackByFn" ...>
On the button click pass the index to deletedata() method like:
deletedata(index)
Create your deletedata method like:
deletedata(index:number){
this.selectedCategoryDetails.splice(index, 1);
// other code here, like calling api
// to update the selectedCategoryDetails source
// etc.
}
Create trackByFn method like:
trackByFn(index,item){
return index;
}
EDIT: Without index
If you want to iterate over selectedCategoryDetails in the ts file, without using ngFor with index in your html, you can have your deletedata like this:
deletedata(categoryDetails:any){
for (let i = this.selectedCategoryDetails.length - 1; i >= 0; i--) {
if (this.selectedCategoryDetails[i] === categoryDetails.category) {
this.selectedCategoryDetails.splice(i, 1);
}
}
}
It will iterate over selectedCategoryDetails backwards and remove the categoryDetails if it finds it in the array of objects.
Now, you only need to pass the categoryDetails to deletedata in your html:
(click)="deletedata(categoryDetails);customHabitPopovers.hide()"

Computed, print items on change without duplicate

I'm trying to show items in a table every time the list of item changes. I've got a function and a computed but I'm not quiet sure if I'm doing it right.
Function(){
Every time a new value comes in: changeList.push(item);
}
Then I have this computed
Computed:
changedData: function(){
return this.changeList;
}
HTML
<tr v-for="change in changedData">
<td>change.value</td>
<tr>
It does print out every item in the list when it is changed, but the thing is I don't want it to print out the items that already printed out, only new items.
EDIT: Found the problem (push function)
for(index in question.Answers){
if(question.Answers[index].Selected === "selected" &&
question.Answers[index].Value === savedQuestion.Value){
this.myList.push({newValue: question.Answers[index].Value, oldValue:
savedQuestion.Value});
}
}
This will add all the questions with their value regardless if the list already contains the same question with the exact same values.
So to achieve this you can check in the array if the object with same values is present or not.If not than only push the values.
Below is the updated code.
const search = (newVal,oldVal) => array.find(element => (element.newValue === newVal && element.oldValue === oldVal));
for(index in question.Answers){
if(!search(question.Answers[index].Value,savedQuestion.Value))
if(question.Answers[index].Selected === "selected" &&
question.Answers[index].Value === savedQuestion.Value){
this.myList.push({newValue: question.Answers[index].Value, oldValue:
savedQuestion.Value});
}
}
In your code computed is actually not needed.Here is the basic example of adding dynamic values into the list at runtime.
https://codepen.io/anon/pen/LqKjMM?editors=1111
Template code =>
<script src="//vuejs.org/js/vue.js"></script>
<h1>Example of managing a Vue.js list</h1>
<div id="products">
<vue-products></vue-products>
</div>
<script type="text/template" id='vue-products-template'>
<div>
<form v-on:submit.prevent="addProduct">
<input type="text" v-model="productName">
<input type="submit" value="Add"></input>
</form>
<ul>
<li v-for="name in productNames">{{name}}</li>
</ul>
</div>
</script>
Script code =>
Vue.component('vue-products', {
template: '#vue-products-template',
data: function() {
return {
productName: "",
productNames: ['booze', 'tums', 'peas', 'short wave radio'],
}
},
methods: {
addProduct: function() {
this.productNames.push(this.productName)
this.productName = ""
}
}
})
$(function() {
new Vue({el: '#products', data: {}})
});

javascript to filter unwanted data

I am new to angular js. I have a link http://www.bursamalaysia.com/searchbox_data.json that I want to get a list of name and id.
I able to get the list from a link in json but I need to filter unwanted items in the list. If the id is more than 4 digits, then remove full_name,name, short_name and id. example: if id:123456 , it need to be filter out, together with name,short name.
app.js
abc: {
name: "Momo",
value: "kls",
long: "KLSE",
searchRef: KLSE_SEARCH_REF,
searchRefURL: "http://www.bursamalaysia.com/searchbox_data.json",
},
details.js
$ionicLoading.show();
if ($scope.currentMarket == "abc"){
$webServicesFactory.getNotParsed($marketProvider[$scope.currentMarket].searchRefURL).then(function success(response){
response = JSON.parse(response);
for (var i = 0; i < response[0].length; i++){
$scope.searchRef.push({
name: response[0][i].name || response[0][i].full_name,
symbol: response[0][i].short_name,
code: response[0][i].id,
market: $marketProvider[$scope.currentMarket].long
});
}
console.info($scope.searchRef);
$ionicLoading.hide();
});
}
html
<div class="list">
<div class="item" ng-repeat="item in searchItems" ng-click="openDetail(item)">
<p>{{item.symbol}} - {{item.name}}</p>
<p>{{currentMarket | uppercase}}</p>
</div>
</div>
You could go with Array.prototype.filter and Array.prototype.map, which is quite elegant.
$ionicLoading.show();
if($scope.currentMarket == "abc") {
$webServicesFactory.getNotParsed($marketProvider[$scope.currentMarket].searchRefURL).then(
function success(response) {
$scope.searchRef = JSON.parse(response)[0].filter(function(itm) {
// whatever you want to filter should pass this condition
return itm.id.toString().length <= 3;
}).map(function(itm) {
// for each item, transform to this
return {
name: itm.name || itm.full_name,
symbol: itm.short_name,
code: itm.id,
market: $marketProvider[$scope.currentMarket].long
};
});
$ionicLoading.hide();
}
);
}
Make sure to handle any errors and to make your code defensive.
if you need filter more than 4 digit id values , then you can restrict with simple condition if(response[0][i].id <= 999)
example below:
for(var i=0; i<response[0].length; i+=1){
if(response[0][i].id.toString().length <= 3 ) {
$scope.searchRef.push(
{
name: response[0][i].name || response[0][i].full_name,
symbol: response[0][i].short_name,
code: response[0][i].id,
market: $marketProvider[$scope.currentMarket].long
}
);
}
}

element in my $scope variable won't get display

I just deployed a website to test in "production" but when i try to go to the website some of my computer won't see one the results of my ng-repeat and some will see. If I go to the website when there's nothing displayed I look at the source code and I see the ng-repeat with each object of my array, but no html output on the screen. Here some of my code when I load my controller:
/**
* Function that send a request to get a list of posts.
* #return {Function} A promise.
*/
function retrievePosts() {
var defered = $q.defer();
// If the user is logged in we do a search by country, otherwise we get all the posts.
if($rootScope.user !== null && $rootScope.user !== undefined) {
PostService.searchPost({ countries: [$rootScope.user.country] }, function(err, posts) {
if(err) {
defered.reject(err);
}
else if(posts && posts.length > 0) {
defered.resolve(posts);
}
// If the previous condition is not true, we try to get all the posts, since the search by country didn't work.
else {
PostService.getAllPosts(function(err, posts2) {
if(err) {
defered.reject(err);
} else {
defered.resolve(posts2);
}
});
}
});
} else {
PostService.getAllPosts(function(err, posts) {
if(err) {
defered.reject(err);
}
else {
defered.resolve(posts);
}
});
}
return defered.promise;
}
This function is used to get an array of JSON posts object. Then I do a q.all like this:
$q.all([retrieveManufacturer(), retrieveCategories(), retrievePosts(), getTotalPosts(), retrieveGalleryPosts()]).then(function(results) {
$scope.manufacturers = results[0];
$scope.categories = results[1];
// Here we must cache the result and slice it, so that angular doesn't render
// a tone of post but 10 at a time.
postCache = results[2];
$scope.numberOfPostsToShow = 10;
$scope.posts = postCache.slice(0, $scope.numberOfPostsToShow);
// Some code to display the proper amount of post for each category.
var i = -1;
var max = results[3].length;
var groupedPostsCount = { };
var group;
while(++i < max) {
group = results[3][i];
// "_id" contains the name of the category.
groupedPostsCount[group._id] = group.count;
}
if(Object.keys(groupedPostsCount).length > 0){
$scope.categoriesPostCount = groupedPostsCount;
}
$scope.galleryPosts = results[4];
// Prepare the $scope.galleryPosts to be bound with posts.
buildGallery($scope.galleryPosts);
}, function(err) {
console.log(err);
});
Every task in $q.all gets executed and they all get resolved. I see them in my HTML like the categories, manufacturers, etc... Results[2] which are the array of posts are not null they really do have 500 posts in them. I try to call $scope.$apply() after buildGallery() method call, but nothing work. If I print {{ posts }} anywhere in my html i see the array of posts. But when they are in that ng-repeat:
<div class="ad-container" ng-repeat="post in posts" ng-click="viewPostDetails(post)">
<div class="ad-picture">
<table class="wrapper">
<tr>
<td><img ng-src="img/175/{{ post.mainImageName || post.imgUrls[0] }}" alt="No image provided"/></td>
</tr>
</table>
</div>
<div class="ad-info">
<span class="ad-info-title">{{ post.title }}</span>
<span class="ad-info-price">{{ post.country == 'Canada' ? (post.price | currency : "CA$") : (post.price | currency : "US$") }}</span>
<br />
<span>{{ post.country }}, {{ post.province }}, {{ post.createdAt | date }}</span>
<p>{{ post.description }}</p>
</div>
</div>
Of course this code is inside a div that has a controller bound to it.Like I said, it's really weird. On my development computer everything works perfectly, but some of the computers of my friend did work and others didn't. Here's the link to the website www.firearmsbin.com maybe the problem will occur on your computer. I tried on firefox, firefox for dev, edge, chrome and IE11.
Thanks.
I found out that it was adblock who was not displaying my div which as the class "ad-container". So every class in css that contains "ad" word get block.

How do I correctly load a specific jQuery script

I've been given a script by my e-commerce provider that will allow me to dynamically change the stock levels based on the product option selected by the user from a simple select element.
While the code seems strait forward, it will not run properly. As I am fairly new to jQuery, I'm assuming this is due to me not properly initializing the script within my html. The code itself is a default code that my e-commerce provider hands out, but does not support it in any way.
Here is the script
<script>
// <![CDATA[
var selectCallback = function(variant, selector) {
if (variant) {
if (variant.available) {
// Selected a valid variant that is available.
$('#add-to-cart').removeClass('disabled').removeAttr('disabled').val('Add to Cart').fadeTo(200,1);
} else {
// Variant is sold out.
$('#add-to-cart').val('Sold Out').addClass('disabled').attr('disabled', 'disabled').fadeTo(200,0.5);
}
// Whether the variant is in stock or not, we can update the price and compare at price.
if ( variant.compare_at_price > variant.price ) {
$('#product_price').html('<span class="product-price on-sale">'+ Shopify.formatMoney(variant.price, "") +'</span>'+' <s class="product-compare-price">'+Shopify.formatMoney(variant.compare_at_price, "")+ '</s>');
} else {
$('#product_price').html('<span class="product-price">'+ Shopify.formatMoney(variant.price, "") + '</span>' );
}
} else {
// variant doesn't exist.
$('#add-to-cart').val('Unavailable').addClass('disabled').attr('disabled', 'disabled').fadeTo(200,0.5);
}
}
// initialize multi selector for product
jQuery(function($) {
new Shopify.OptionSelectors("product-select", { product: , onVariantSelected: selectCallback });
});
// ]]>
</script>
Any ideas on why this might not be working? You can see this script live on my site:
http://www.yandasmusic.com/products/fender-american-standard-stratocaster?variant=1178632565
EDIT:
Upon further inspection, I have found a second piece of code that also calls up the product option selection box. I can tell that this code also serves the function of changing the currently shown product image based on the current option selected:
<script>
var selectCallback = function(variant, selector) {
if (variant && variant.available) {
jQuery('#add-to-cart').removeAttr('disabled').removeClass('disabled'); // remove unavailable class from add-to-cart button, and re-enable button
if(variant.price < variant.compare_at_price){
jQuery('#product_price .price').html('<span class="money">' + Shopify.formatMoney(variant.price, "{{ shop.money_format }}") + '</span><span class="money compare-at-price">' + Shopify.formatMoney(variant.compare_at_price, "{{ shop.money_format }}") + '</span>');
} else {
jQuery('#product_price .price').html('<span class="money">' + Shopify.formatMoney(variant.price, "{{ shop.money_format }}") + '</span>');
}
} else {
jQuery('#add-to-cart').addClass('disabled').attr('disabled', 'disabled'); // set add-to-cart button to unavailable class and disable button
var message = variant ? "Sold Out" : "Unavailable";
jQuery('#product_price .price').text(message);
}
// if (variant && variant.featured_image) {
// var originalImage = $(".zoomWrapper img");
// var newImage = variant.featured_image;
// var element = originalImage[0];
// Shopify.Image.switchImage(newImage, element, function (newImageSizedSrc, newImage, element) {
// $(element).parents('a').attr('href', newImageSizedSrc);
// $(element).attr('src', newImageSizedSrc);
// });
// };
if (variant && variant.featured_image) {
var originalImage = $("#elevatezoom_big");
var newImage = variant.featured_image;
var element = originalImage[0];
Shopify.Image.switchImage(newImage, element, function (newImageSizedSrc, newImage, element) {
$(element).attr('src', newImageSizedSrc);
$("#elevatezoom_gallery a").each(function(){
if ( $(this).attr('data-zoom-image') == newImageSizedSrc ) {
$(this).trigger('click')
};
});
});
};
};
jQuery(document).ready(function($){
new Shopify.OptionSelectors("product-select", { product: {{ product | json }}, onVariantSelected: selectCallback, enableHistoryState: true });
// Add label if only one product option and it isn't 'Title'.
{% if product.options.size == 1 and product.options.first != 'Title' %}
$('.selector-wrapper:eq(0)').prepend('<label>{{ product.options.first }}</label>');
{% endif %}
// Auto-select first available variant on page load.
{% assign found_one_in_stock = false %}
{% for variant in product.variants %}
{% if variant.available and found_one_in_stock == false %}
{% assign found_one_in_stock = true %}
{% for option in product.options %}
$('.single-option-selector:eq({{ forloop.index0 }})').val({{ variant.options[forloop.index0] | json }}).trigger('change');
{% endfor %}
{% endif %}
{% endfor %}
});
</script>
If I run both scripts, the page shows two select boxes for the product options. Is it possible to combine them?
You have a JavaScript error on your page because of this line of code:
new Shopify.OptionSelectors("product-select", { product: , onVariantSelected: selectCallback });
According to this reference document: https://docs.shopify.com/manual/configuration/store-customization/advanced-navigation/linked-product-options, that line of code should actually look like this:
new Shopify.OptionSelectors("product-select", { product: {{ product | json }}, onVariantSelected: selectCallback });

Categories