I'm trying to push some numbers to an array, and then I want to assign the array to a hidden input to posted with a form.
On each click I am pushing a value to the array, but the array seems to be reinitialized on each click, so it stores the last pushed value only.
The full scenario:
open a popup modal contains a form (form loaded by ajax).
select a category, then the category items will be loaded by ajax too. (the shared code below is in this page).
click an item to get the full item details by ajax and load them in a div, and push the item ID to the array.
the array that stored the chosen items IDs will be assigned to a hidden input element.
So if the user choose another category, the items page will be reloaded, and this is the reason why the array is reinitialized each time.
$(document).ready(function(){
var added_items = [];
$('.items-list .one-item').click(function(e){
e.preventDefault();
if(added_items.indexOf($(this).attr('href')) < 0){
ajaxLoad('<?=Yii::$app->urlManager->createUrl('bookings/item'); ?>', $('.added-items'), {item:$(this).attr('href')}, true);
added_items.push($(this).attr('href'));
$('#added-items-list').val(JSON.stringify(added_items));
}
else{
alert("item already exist");
}
});
});
So how I can save the items IDs and post them with the form.
Three possible reasons
1.) form reloads page
2). if(added_items.indexOf($(this).attr("href")) < 0) returns false
3). Single .one-item element having $(this).attr("href"), see 2)
Utiltizing localStorage ; note, untested
$(document).ready(function() {
var added_items = localStorage.getItem("items") || [] ;
$('.items-list .one-item').click(function(e) {
e.preventDefault();
if (typeof added_items === "string") {
added_items = JSON.parse(added_items);
}
if (added_items.indexOf($(this).attr('href')) < 0) {
added_items.push($(this).attr('href'));
localStorage.setItem("items", JSON.stringify(added_items));
// note, not certain if page reloads here ?
// should $('#added-items-list').val(localStorage.getItem("items"));
// be called before `ajaxLoad` ?
ajaxLoad('<?=Yii::$app->urlManager->createUrl('
bookings / item '); ?>', $('.added-items'), {
item: $(this).attr('href')
}, true);
$('#added-items-list').val(localStorage.getItem("items"));
} else {
alert("item already exist");
}
});
});
Your code:
$(document).ready(function(){
var added_items = [];
...
}
seems located inside ajax loaded content so this code run every ajax call.
Your should move at least var added_items = []; outside of ajax reloaded content.
what I did (tested and worked successfully):
the form page :
$(document).ready(function(){
localStorage.clear();
...
$('form').on('submit', function(){
$('#added-items-list').val(JSON.stringify(localStorage["added_items"]));
});
});
the items page:
$(document).ready(function(){
var added_items = [];
if(localStorage.getItem("added_items")===null){
localStorage["added_items"] = JSON.stringify(added_items);
}
else {
// Parse the serialized data back into an array of objects
added_items = JSON.parse(localStorage.getItem('added_items'));
}
$('.items-list .one-item').click(function(e){
e.preventDefault();
if(added_items.indexOf($(this).attr('href')) < 0){
added_items.push($(this).attr('href'));
localStorage.setItem('added_items', JSON.stringify(added_items));
}
else{
alert("item already exist");
}
});
Related
I created form where are filled data storaged to localstorage and I want to delete them if form is submitted. But it is not working inside this function.
If I use it outside of this function, it is working well.
What can be problem?
// Send formData to upload.php
form.on('submit', function() {
event.preventDefault();
if (checkFieldsIfNotEmpty() == true) {
var formDataFields = form.serializeArray(), // Get all data from form except of photos
count = Object.keys(data).length; // count fields of object
// Fill formData object by data from form
$.each(formDataFields, function(index, value) {
if (value.name === 'category' || value.name === 'subcategory' || value.name.indexOf('filter') >= 0) {
// do nothing
} else {
formData.append(value.name, value.value); // add name and value to POST data
}
});
// foreach - fill formData with category, subcategory and filters names/values from form
$('.add-item__input-select').each(function(index, value) {
formData.append($(this).attr('name'), $(this).attr('id'));
});
// foreach - fill formData with photos from form
$.each(data, function(index, value) {
formData.append('files[]', value);
});
uploadData(formData); // send data via ajax to upload.php
// Clear loaclstorage
window.localStorage.clear();
}
});
If I click on submit the it redirects me from form page to item page. and if I go back I can see data from localstorage again on fomr page. I added code which have some connection with localstorage. Maybe there is some problem. On form page is nothing important
/* SAVE FORM DATA TO LOCAL STORAGE - presistent - saved until submit is not clicked */
// The unload event is sent to the window element when the user navigates away from the page for ex. page refresh
$(window).on('unload', function() {
// Save values of form fields to local storage
$(':file, :checkbox, select, textarea, input').each(function() {
// Due to JS added input instead of select, need to get value from input + add to storage just checked items
if ( !$(this).hasClass('add-item__select') && !$(this).is(':checkbox') ) {
// Save value of field to local storage
localStorage.setItem($(this).attr('name'), $(this).val());
} else if ( $(this).is(':checked') ) {
// Save just name of checkbox which is checked
localStorage.setItem($(this).attr('name'), $(this).val());
}
})
});
// Get values form local storage if page is refreshed
$(window).on('load', function() {
// Save values of form fields to local storage
$(':file, :checkbox, select, textarea, input').each(function() {
// Set values for input elements
if ( !$(this).hasClass('add-item__select') && ( !$(this).is(':checkbox' ) && !$(this).is(':file') ) ) {
// Get value of field
fieldValue = localStorage.getItem($(this).attr('name'));
// Show value of field if fieldValue is not empty
if (fieldValue.length !== 0) {
// Fill value of element by value from from localstorage - all filled fileds must have class counted to be not conted again
$(this).val(fieldValue).addClass('black-text counted');
// Add label, bcz it is checked just on focusout event
$('<label class="add-item__form-label-JS">' + $(this).attr('placeholder') + '</label>').insertBefore($(this));
$('.add-item__form-label-JS').css({color: '#888'});
}
// Done action just for checkbox
} else if ( $(this).is(':checkbox') ) {
// Get value of field
fieldValue = localStorage.getItem($(this).attr('name'));
// All filled fileds must have class counted to be not conted again
// If chekcbox name is same as saved in local storage then set as checked
if ( fieldValue === $(this).val() ) {
$(this).prop('checked', true);
$(this).parent().parent().addClass('counted');
}
// Remove checkbox value in localstorage each time - bcz of change checked checkboxes
localStorage.removeItem(fieldValue);
}
})
});
You are saving when unloading the page.
To solve:
let submitting = false;
$(window).on('unload', function() {
if (!submitting) {
// Save values of form fields to local storage
form.on("submit", function(e) {
uploadData(formData); // send data via ajax to upload.php
// in PRINCIPLE you should move the clear AND setting submitting to the success of the ajax
// Clear localstorage
window.localStorage.clear();
submitting = true;
BUT
WHY are you redirecting in uploadData? WHY not just SUBMIT the form to the server and redirect in the response from the server using a header directive???
Background info: I'm using WooCommerce and Gravity Forms, and trying to make it so the Add to Cart button is inactive according to two conditions - either there are no attendees registered, or the date hasn't been selected from the product variation dropdown. The user should only be able to move forward if both sections are completed.
The Gravity Forms component of this has a popup module to sign up those attendees, but the summary is displayed outside the module and on the main product page. The class .gpnf-no-entries lives on the "outside" of the Gravity Forms module, since it's always visible on the page. .gpnf-nested-entries and .gpnf-row-actions are also outside the module, but rely on information from within the module. .tingle-btn is a class used on multiple buttons inside the module - to add an attendee, cancel editing, or delete that attendee (unsure if I need a loop on here - alerts were working without one, and it seems like there's something else causing issues regardless).
Issues: It was working at one point, but only after the second click (anywhere on the page). There's also a second issue - on this form, if you've added an attendee but not added the product to the cart, the page retains any info you've put in. So what happens is, if you refresh the page and have old attendee info already there, the Add to Cart never gets clickable after selecting a date, even though both areas are filled out.
Screenshots:
I'm still somewhat of a beginner here so it's quite possibly something silly.
<script>
var modalButtons = document.querySelectorAll('.tingle-btn');
var noEntries = document.querySelector('.gform_body .gpnf-no-entries');
var entryField = document.querySelectorAll(".gpnf-nested-entries .entry-field[style='display: block;']");
var nestedEntriesDelete = document.querySelector('.gpnf-row-actions .delete');
var addToCart = document.querySelector('.single_add_to_cart_button');
var wcVariation = document.querySelector('.woocommerce-variation-add-to-cart');
var selectCheck = document.querySelector('#select-date-option');
//When date selection dropdown is changed, check value and check for "no entries" message
document.addEventListener('change', function (event) {
if (!event.target.matches('selectCheck')) {
if ((noEntries.style.display !== 'none') || (selectCheck.value === '')) {
addToCart.classList.add('disabled');
wcVariation.classList.remove('woocommerce-variation-add-to-cart-enabled');
wcVariation.classList.add('woocommerce-variation-add-to-cart-disabled');
}
else {
addToCart.classList.remove('disabled');
wcVariation.classList.add('woocommerce-variation-add-to-cart-enabled');
wcVariation.classList.remove('woocommerce-variation-add-to-cart-disabled');
}
}
}, false);
// When attendee is deleted, check to see if there are any entry fields left
document.addEventListener('click', function (event) {
if (!event.target.matches('nestedEntriesDelete')) {
if (entryField.length <= 3) {
addToCart.classList.add('disabled');
wcVariation.classList.remove('woocommerce-variation-add-to-cart-enabled');
wcVariation.classList.add('woocommerce-variation-add-to-cart-disabled');
}
}
}, false);
// Check for "no entries" and no date selection value when buttons to add or remove attendees are clicked
document.addEventListener('click', function (event) {
if (!event.target.matches('modalButtons')) {
if ((noEntries.style.display !== 'none') || (selectCheck.value === '')) {
addToCart.classList.add('disabled');
wcVariation.classList.remove('woocommerce-variation-add-to-cart-enabled');
wcVariation.classList.add('woocommerce-variation-add-to-cart-disabled');
}
else {
addToCart.classList.remove('disabled');
wcVariation.classList.add('woocommerce-variation-add-to-cart-enabled');
wcVariation.classList.remove('woocommerce-variation-add-to-cart-disabled');
}
}
}, false);
</script>
I ended up doing this a much simpler way by adding classes:
<script>
var noEntries = document.querySelector('.gform_body .gpnf-no-entries');
var entriesContainer = document.querySelector('.gpnf-nested-entries-container');
var addToCart = document.querySelector('.single_add_to_cart_button');
//When page is fully loaded, check for cached entries
window.addEventListener('load', function () {
//if there are entries, show the add to cart button
if (noEntries.style.display === 'none'){
entriesContainer.classList.add('has-entries');
addToCart.classList.add('do-add');
addToCart.classList.remove('dont-add');
}
//if there are no entries, disable the add to cart button
else if (noEntries.style.display === ''){
entriesContainer.classList.remove('has-entries');
addToCart.classList.add('dont-add');
addToCart.classList.remove('do-add');
}
//if the form isn't present, don't do any of this
else if (noEntries = 'null'){
//do nothing
}
});
//When the container with the form and the entries is clicked, check for entries
document.addEventListener('click', function (event) {
if (!event.target.matches('#gform_wrapper_41')) {
setInterval(function() {
//if an entry is added, show the add to cart button
if (noEntries.style.display === 'none'){
entriesContainer.classList.add('has-entries');
addToCart.classList.add('do-add');
addToCart.classList.remove('dont-add');
}
//if all entries are removed, disable the add to cart button
else if (noEntries.style.display === ''){
entriesContainer.classList.remove('has-entries');
addToCart.classList.add('dont-add');
addToCart.classList.remove('do-add');
}
},2000);
}
}, false);
</script>
I could use a point in the right direction. I have a product that I am showing on a cart page for charity donations. If someone adds the donation to their cart I have been able to remove the donation option since it is now already in the cart. This is done because when a donation button is clicked the page is refreshed and the donation added to the cart. The problem I am having is when someone removes the donation from the cart the page does not refresh and therefor the option to donate does not show up until I manually refresh the page. I would post some code but I dont have any because I am not sure how I go about the page looking at the cart basically in a loop to keep checking if that item in the cart or not.
This is the code I use to check and see if the donation is in the cart.
$(document).ready(function() {
var found = false;
$('.bd a').each(function(index, ele){
if($(ele).html().indexOf('Charity Bucks') > -1){
found = true;
}
})
if(found){
$('#divID').css('display','none');
}
});
from this stack
this is event listener for changes at element with class .bd
$("body").on('DOMSubtreeModified', ".bd", function() {
// code here
});
try add this code :
$("body").on('DOMSubtreeModified', ".bd", function() {
$('.bd a').each(function(index, ele){
if($(ele).html().indexOf('Charity Bucks') > -1){
$('#divID').css('display','none');//or inline-block; or block; as your default css for this element
}else{
$('#divID').css('display','inline');
}
})
});
I ended up using a callback to solve my problem
<script>
$(document).ready(function() {
var found = false;
$('.bd a').each(function(index, ele){
if($(ele).html().indexOf('Charity Bucks') > -1){
found = true;
var parent = $(ele).parent().parent();
var sibs = $(parent).siblings('.group4');
$(sibs).find('a').each(function(index2, ele2){
console.log(ele2);
if($(ele2).html().indexOf('remove') > -1){
console.log('found it');
$(ele2).on('click', function(){
$('#divID').show();
});
}
});
}
})
if(found){
$('#divID').hide();
}
});
</script>
The issue is due to a missing else statement. In your logic you only modify the #divID element if you find the charity entry, but not if you no-longer find the charity entry and have already hidden the element.
Additionally I would recomend showing/hiding the element via a css class rather than directly though css properties.
$(document).ready(function() {
$('#remove-donation-button').click(removeDonation());
var found = false;
$('.bd a').each(function(index, ele){
if($(ele).html().indexOf('Charity Bucks') > -1){
found = true;
}
})
if(found){
$('#divID').addClass("hide-charity");
}
});
function removeDonation(){
$('.hide-charity').removeClass('hide-charity');
/** Actually remove */
}
I am currently working on a project that utilizes an input to create a list of items. I have the addition of programs working, however the deletion of an item is where I am having problems.
The items are added to an array via .push() and the method of deletion is via the .splice() method. The function correctly splices the correct array element but ends up doing a second pass and deleting the elements before it. How do I stop the splice from happening more than once?
$(skill_add_button).click(function(e){ //on add input button click
var skill_input=document.getElementById("skill_input").value;
document.getElementById("skill_input").value = "";
e.preventDefault();
if(s < 12){ //max input box allowed
if (skill_input==""){
skillset = skill_arr.join('');
alert(skillset);
} else {
s++; //text box increment
$(skill_wrap).append('<div class="skill_tag" id="skill_tag'+s+'">'+skill_input+'</div>'); //add input box
skill_arr.push(skill_input+'|s|');
alert(skill_arr);
$('.skill_tag').hover(function(){
$(this).css("background-color", "#C14330");
$(this).css("cursor", "pointer");
}, function(){
$(this).css("background-color", "#04CA29");
});
$('.skill_tag').click(function() {
var skill_id = $(this).attr('id');
var index = skill_id.split('skill_tag').pop();
skill_arr.splice(index,1);
$('#'+skill_id).remove();
alert(skill_arr);
s--;
});
}
}
if(s > 11) {
$(skill_add_button).remove();
}
});
If I try to put my .skill_tag click function outside of my skill_add_function, it does not work at all.
Each time you click on $(skill_add_button) you create a new div.skill_tag but and you add .click event on ALL .skill_tag elements of the page.
Save your generated div into a var and use this var to add click event.
var myDiv = '<div class="skill_tag" id="skill_tag'+s+'">'+skill_input+'</div>';
$(skill_wrap).append(myDiv); //add input box
[...]
myDiv.hover(function(){
[...]
myDiv.click(function(){
$('body').on('click','.skill_tag',function(){
//TODO::add code here
})
Here's my jsfiddle: http://jsfiddle.net/LUsMb/2779/
What I'm attempting to do is make a checkbox-selectable select2 that shows how many items you have selected, instead of showing the item list. Everything works except for de-selecting an item. I think this is because I call evt.preventDefault in the select2-selecting event. Here is my code for that particular event:
.on('select2-selecting', function(evt) {
var newValue = evt.object.value;
var found = false;
var me = this;
var $me = $(me);
var arr = $me.select2('data');
arr.forEach(function(e) {
if(found) return;
if(newValue === e.value) {
found = true;
var index = arr.indexOf(e);
if(index === -1) console.error(e,"NOT FOUND IN ARRAY. ABORT ABORT ABORT.");
arr.splice(index, 1);
$me.select2('data',arr);
changeText(me);
evt.preventDefault();
}
});
I do evt.preventDefault() because I want to remove the item from the select2 data list instead of adding it again (because I don't want to have it work the traditional way). Unfortunately, when I go to de-select an item it does all of the updating correctly, except for in select2 - the display list is not updated properly. I could always close and re-open the list, but I strongly prefer not to do that.
Has anyone done this successfully before? Or maybe would know where to go from here?