Adding multiple items to cart at same time delay

Hello, I coded a website that allows you to pick from a list of products a quantity for each item then add them all at once
to your cart, it does work kind of…

For example, it works like a Grocery list in that you pick the quantity of each item you want. like below;

Oranges x 5
Apples x 3
Carrots x 6
Lettuce x 2
Popcorn x 1

However when you hit Buy Now sometimes you get

Oranges x 5
Carrots x 6
Popcorn x 1

And you are missing the Lettuce and Apples you selected.

If you refresh then try again you might get all the items you chose then next time only two of what you selected.

It makes me feel like I need to delay the addtocart function as it does not have enough time to add all the products but not sure how.

I am sure there is a more efficient way to code this but I got it to work besides it being random which products actually add.

A few notes.

  • The log does say all the products are added.

  • I do have onchange events for each qty selector.

  • The product ID is correct for each item.

  • The more different items I add the worst it is If I just chose two items like Carrots and Apples it will work every time.


import { cart } from 'wix-stores';

$w.onReady(function () {
$w("#bruno").onChange(CartButtonEnableDisable);
$w("#drooling").onChange(CartButtonEnableDisable);
$w("#conniption").onChange(CartButtonEnableDisable);
$w("#cookiedoh").onChange(CartButtonEnableDisable);
$w("#dirtyoh").onChange(CartButtonEnableDisable);
$w("#doublefudge").onChange(CartButtonEnableDisable);
$w("#chocojunkie").onChange(CartButtonEnableDisable);
$w("#elegangsta").onChange(CartButtonEnableDisable);
$w("#freeloader").onChange(CartButtonEnableDisable);
$w("#testy").onChange(CartButtonEnableDisable);
$w("#cappuccino").onChange(CartButtonEnableDisable);
$w("#golddigger").onChange(CartButtonEnableDisable);
$w("#nicebuns").onChange(CartButtonEnableDisable);
$w("#karen").onChange(CartButtonEnableDisable);
$w("#fritz").onChange(CartButtonEnableDisable);
$w("#ohfudger").onChange(CartButtonEnableDisable);
$w("#minty").onChange(CartButtonEnableDisable);
$w("#dolce").onChange(CartButtonEnableDisable);
$w("#dang").onChange(CartButtonEnableDisable);
$w("#kiddo").onChange(CartButtonEnableDisable);

});

function CartButtonEnableDisable() {

    let donut1=Number($w("#bruno").value);
    let donut2=Number($w("#drooling").value);
    let donut3=Number($w("#conniption").value);
    let donut4=Number($w("#cookiedoh").value);
    let donut5=Number($w("#dirtyoh").value);
    let donut6=Number($w("#doublefudge").value);
    let donut7=Number($w("#chocojunkie").value);
    let donut8=Number($w("#elegangsta").value);
    let donut9=Number($w("#freeloader").value);
    let donut10=Number($w("#testy").value);
    let donut11=Number($w("#cappuccino").value);
    let donut12=Number($w("#golddigger").value);
    let donut13=Number($w("#nicebuns").value);
    let donut14=Number($w("#karen").value);
    let donut15=Number($w("#fritz").value);
    let donut16=Number($w("#ohfudger").value);
    let donut17=Number($w("#minty").value);
    let donut18=Number($w("#dolce").value);
    let donut19=Number($w("#dang").value);
    let donut20=Number($w("#kiddo").value);

    let totalDonuts = (donut1 + donut2 + donut3 + donut4 + donut5 + donut6 + donut7 + donut8 + donut9 + donut10 + donut11 + donut12 + donut13 + donut14 + donut15 + donut16 + donut17 + donut18 + donut19 + donut20)
  
  if((totalDonuts >= 6)){
    $w('#buyNow').enable();
  } else $w('#buyNow').disable();

  console.log(totalDonuts)

}

export function buyNow_click(event) {
let brunoqty=Number($w("#bruno").value);
let droolingqty=Number($w("#drooling").value);
let conniptionqty=Number($w("#conniption").value);
let cookiedohqty=Number($w("#cookiedoh").value);
let dirtyohqty=Number($w("#dirtyoh").value);
let fudgeqty=Number($w("#doublefudge").value);
let chocojunkieqty=Number($w("#chocojunkie").value);
let elegangstaqty=Number($w("#elegangsta").value);
let freeloaderqty=Number($w("#freeloader").value);
let testyqty=Number($w("#testy").value);
let cappucinoqty=Number($w("#cappuccino").value);
let golddiggerqty=Number($w("#golddigger").value);
let nicebunsqty=Number($w("#nicebuns").value);
let karenqty=Number($w("#karen").value);
let fritzqty=Number($w("#fritz").value);
let fudgerqty=Number($w("#ohfudger").value);
let mintyqty=Number($w("#minty").value);
let dolceqty=Number($w("#dolce").value);
let dangqty=Number($w("#dang").value);
let kiddoqty=Number($w("#kiddo").value);

let bruno="4bc810fb-97e5-640a-a5b6-94126092ef96"
let drooling="554f5ca5-db54-c838-49ed-ffa168190e70"
let conniption="8601b979-85bd-0630-65af-64e908fee1f7"
let cookiedoh="4b383860-8b9a-4d39-1496-28d1e088728b"
let dirtyoh="e5e0b76a-175b-d903-b37d-8b7d5c68d2f1"
let fudge="1946d03d-9999-19e6-40d6-60d49d969a74"
let chocojunkie="b5bd3b2a-301b-13db-98a9-ca1360e7572a"
let elegangsta="0e21a287-c9b4-34d1-9625-3d1f04055131"
let freeloader="0551f7ca-f91d-cc8f-bd84-454b0669a7da"
let testy="4763505c-cd2e-8ddf-758e-560d00caf0e8"
let cappucino="6c869f62-b2b2-eb5c-316c-9b6e1de7bbfa"
let golddigger="b09b80db-ab5f-4017-5174-c14810e53fc5"
let nicebuns="d741a62b-5f83-23a3-5ecc-5243c93167cf"
let karen="19449e24-8945-a3c2-9a24-2a51c318a963"
let fritz="9fb7a881-d670-8cff-97cc-e1085a7fd3ed"
let fudger="ff63bb84-815f-5330-667f-9850948d6034"
let minty="9850e303-f282-ddfe-2d8f-4982d7c45fcf"
let dolce="5c528992-70da-0e1f-47f2-875a6634a510"
let dang="67dcdbc0-a8d2-adac-381d-13eead20822b"
let kiddo="56c0e5f6-77bc-7eee-3bcf-ea193a2c7318"

  $w("#shoppingCartIcon1").addToCart(bruno,brunoqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );
 $w("#shoppingCartIcon1").addToCart(drooling,droolingqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );
$w("#shoppingCartIcon1").addToCart(conniption,conniptionqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );
$w("#shoppingCartIcon1").addToCart(cookiedoh,cookiedohqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(dirtyoh,dirtyohqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(fudge,fudgeqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(chocojunkie,chocojunkieqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(elegangsta,elegangstaqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(freeloader,freeloaderqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(testy,testyqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(cappucino,cappucinoqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(golddigger,golddiggerqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(nicebuns,nicebunsqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(karen,karenqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(fritz,fritzqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(fudger,fudgerqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(minty,mintyqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(dolce,dolceqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(dang,dangqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

$w("#shoppingCartIcon1").addToCart(kiddo,kiddoqty)
    .then( () => {
      console.log("Product added");
    } )
    .catch( (error) => {
      console.log(error);
    } );

}

Any suggestions on how to either delay it so it has time to add all selections to cart or how to make this better would be greatly appreciated!

Thanks!

Hey there,

as per addToCart docs , this method is deprecated and should be replaced with wix-stores.cart.addProducts .

I have cleaned up your code a bit and replaced addToCart with addProducts . The main difference is that addProducts accepts multiple items in one go which should eliminate the issue of disappearing line items. A word of caution though - I haven’t tested this code and it might need further adjustments depending on your page contents & setup. I hope this helps!

import { cart } from ‘wix-stores’ ;

// This is a single place to manage all donut inputs on stage. In case a new donut needs to be added, just add it here and make sure that the relevant component ID matches the name property of the new item
const donuts = [
{ name: ‘bruno’ , id: ‘4bc810fb-97e5-640a-a5b6-94126092ef96’ },
{ name: ‘drooling’ , id: ‘554f5ca5-db54-c838-49ed-ffa168190e70’ },
{ name: ‘conniption’ , id: ‘8601b979-85bd-0630-65af-64e908fee1f7’ },
{ name: ‘cookiedoh’ , id: ‘4b383860-8b9a-4d39-1496-28d1e088728b’ },
{ name: ‘dirtyoh’ , id: ‘e5e0b76a-175b-d903-b37d-8b7d5c68d2f1’ },
{ name: ‘fudge’ , id: ‘1946d03d-9999-19e6-40d6-60d49d969a74’ },
{ name: ‘chocojunkie’ , id: ‘b5bd3b2a-301b-13db-98a9-ca1360e7572a’ },
{ name: ‘elegangsta’ , id: ‘0e21a287-c9b4-34d1-9625-3d1f04055131’ },
{ name: ‘freeloader’ , id: ‘0551f7ca-f91d-cc8f-bd84-454b0669a7da’ },
{ name: ‘testy’ , id: ‘4763505c-cd2e-8ddf-758e-560d00caf0e8’ },
{ name: ‘cappucino’ , id: ‘6c869f62-b2b2-eb5c-316c-9b6e1de7bbfa’ },
{ name: ‘golddigger’ , id: ‘b09b80db-ab5f-4017-5174-c14810e53fc5’ },
{ name: ‘nicebuns’ , id: ‘d741a62b-5f83-23a3-5ecc-5243c93167cf’ },
{ name: ‘karen’ , id: ‘19449e24-8945-a3c2-9a24-2a51c318a963’ },
{ name: ‘fritz’ , id: ‘9fb7a881-d670-8cff-97cc-e1085a7fd3ed’ },
{ name: ‘fudger’ , id: ‘ff63bb84-815f-5330-667f-9850948d6034’ },
{ name: ‘minty’ , id: ‘9850e303-f282-ddfe-2d8f-4982d7c45fcf’ },
{ name: ‘dolce’ , id: ‘5c528992-70da-0e1f-47f2-875a6634a510’ },
{ name: ‘dang’ , id: ‘67dcdbc0-a8d2-adac-381d-13eead20822b’ },
{ name: ‘kiddo’ , id: ‘56c0e5f6-77bc-7eee-3bcf-ea193a2c7318’ },
]

// extracts donut component value given donut name
function getDonutQty ( donut ) {
return Number ( $w ( ‘#’ + donut . name ). value )
}

$w . onReady ( function () {

// goes over all donuts and attaches onChange handler to each of them
donuts . forEach (({ name }) => {
$w ( ‘#’ + name ). onChange ( CartButtonEnableDisable )
})
})

function CartButtonEnableDisable () {

// converts donuts array to donut quantities array
const donutQuantities = donuts . map ( getDonutQty )

// sums each element in donutQuantities
const totalDonuts = donutQuantities . reduce (( sum , currentDonutAmount ) => {
return sum + currentDonutAmount
}, 0 )

if (( totalDonuts >= 6 )) {
$w ( ‘#buyNow’ ). enable ();
} else $w ( ‘#buyNow’ ). disable ();

}

export function buyNow_click ( event ) {

const donutIdsAndQuantities = donuts
// this is optional step that was not present in original code
// it filters out donuts with zero quantity
. filter ( donut => {
return getDonutQty ( donut ) > 0
})
// replace donuts’ { name, id } representation to { productId, quantity } which addProducts() expects
. map (({ name , id }) => {
return {
productId: id ,
quantity: Number ( $w ( ‘#’ + name ). value )
}
})

cart . addProducts ( donutIdsAndQuantities )
. then (( updatedCart ) => {
console . log ( ‘Products added’ , updatedCart );
})
. catch ( error => {
console . log ( error )
})
}

@egidijus-jucevicius Wow I cannot thank you enough for this. I really truly appreciate it. I will test the code and make any needed changes if any. I will report back once done for anyone who might need it in the future.

Thanks a million.

@egidijus-jucevicius So far so good except I am getting the following error.
Which is odd as the .onchange is definitely a function.


The error is on Line 36. Highlighted below.

  // goes over all donuts and attaches onChange handler to each of them
  donuts.forEach(({ name }) => {
    $w('#' + name).onChange(CartButtonEnableDisable)
  })
})

Thanks for this I think it will help a lot of people who want to add multiple products at once to a cart.

The error indicates that the element returned by $w(“#<some_donut_name>”) does not have the function onChange. This may be caused by a typo in my code.
You can identify the typo by changing the above snippet into

donuts.forEach(({ name }) => {
  const donutComponent = $w('#' + name)
  if (!donutComponent || !donutComponent.onChange) {
    console.log('There is a problem with', name)
  }
  donutComponent.onChange(CartButtonEnableDisable)
})

@egidijus-jucevicius Thanks again I can confirm it is now working great. The error was in the Const Donuts names like you suspected I had to make sure they matched the qty drop down names for each of course.

The only thing now is I get the following error.

TypeError: Cannot read properties of undefined (reading ‘id’)
I am assuming this is because it now filters out the 0 qty items as they would be undefined.

It adds them all to the cart but doesn’t display the mini cart like it use to which is odd. So it works still but yet gives me the error above.

Sorry to be annoying and I have to say your are extremely talented at this. :slight_smile:

@jordon can you share the exact error and the line it’s happening? The screenshot would allow me to identify it better.
As an alternative, you can remove the following lines, as they are optional:

. filter ( donut => {
return getDonutQty ( donut ) > 0
})

As for minicart display, I’m not familiar with the old API, but maybe it managed mini cart display out of the box. I suggest checking out docs for wix-stores.cart.showMiniCart() , maybe they will be of some help.

@egidijus-jucevicius There is no line associated in the console and it doesn’t seem to affect the code working in any way. The error also doesn’t show highlighted in red in the console, and does not show on the published site. Since it doesn’t effect the working of the site in any way so I will just ignore it for now.

I kept the .filter function in as I think that is a great added function.
I also added the code to show the mini cart and it works great. You are correct I think it was built into the old API.

This is now complete. I honestly cannot thank you enough.

Here is the final code below for anyone needing to add multiple items to the cart at once.

How this works is I created boxes with a picture of each product, the description and a quantity selector in each box. Then named the quantity drop down boxes accordingly to the name found in below const donuts = [

Next I went and got the product ID for each item and listed them next to their name accordingly.

I added an add to cart button and disabled it. It only becomes enabled when there are a total quantity of 6 all together.

Note: One function most people might not need is these products have a minimum so you must purchase a qty of 6 before the add to cart button works

This is found in the function CartButtonEnableDisable ( ) { function below and can be removed with a few minor changes. or by changing the if (( totalDonuts >= 6 )) { to a 0 instead of 6

Special thank you to @egidijus-jucevicius for all your help.


import { cart } from 'wix-stores';
import { formFactor } from 'wix-window';

// This is a single place to manage all donut inputs on stage. In case a new donut needs to be added, just add it here and make sure that the relevant component ID matches the name property of the new item
const donuts = [
  { name: 'bruno', id: '4bc810fb-97e5-640a-a5b6-94126092ef96' },
  { name: 'drooling', id: '554f5ca5-db54-c838-49ed-ffa168190e70' },
  { name: 'conniption', id: '8601b979-85bd-0630-65af-64e908fee1f7' },
  { name: 'cookiedoh', id: '4b383860-8b9a-4d39-1496-28d1e088728b' },
  { name: 'dirtyoh', id: 'e5e0b76a-175b-d903-b37d-8b7d5c68d2f1' },
  { name: 'doublefudge', id: '1946d03d-9999-19e6-40d6-60d49d969a74' },
  { name: 'chocojunkie', id: 'b5bd3b2a-301b-13db-98a9-ca1360e7572a' },
  { name: 'elegangsta', id: '0e21a287-c9b4-34d1-9625-3d1f04055131' },
  { name: 'freeloader', id: '0551f7ca-f91d-cc8f-bd84-454b0669a7da' },
  { name: 'testy', id: '4763505c-cd2e-8ddf-758e-560d00caf0e8' },
  { name: 'cappuccino', id: '6c869f62-b2b2-eb5c-316c-9b6e1de7bbfa' },
  { name: 'golddigger', id: 'b09b80db-ab5f-4017-5174-c14810e53fc5' },
  { name: 'nicebuns', id: 'd741a62b-5f83-23a3-5ecc-5243c93167cf' },
  { name: 'karen', id: '19449e24-8945-a3c2-9a24-2a51c318a963' },
  { name: 'fritz', id: '9fb7a881-d670-8cff-97cc-e1085a7fd3ed' },
  { name: 'ohfudger', id: 'ff63bb84-815f-5330-667f-9850948d6034' },
  { name: 'minty', id: '9850e303-f282-ddfe-2d8f-4982d7c45fcf' },
  { name: 'dolce', id: '5c528992-70da-0e1f-47f2-875a6634a510' },
  { name: 'dang', id: '67dcdbc0-a8d2-adac-381d-13eead20822b' },
  { name: 'kiddo', id: '56c0e5f6-77bc-7eee-3bcf-ea193a2c7318' },
]

// extracts donut component value given donut name
function getDonutQty(donut) {
  return Number($w('#' + donut.name).value)
}

$w.onReady(function () {

  // goes over all donuts and attaches onChange handler to each of them
donuts.forEach(({ name }) => {
  const donutComponent = $w('#' + name)
  if (!donutComponent || !donutComponent.onChange) {
    console.log('There is a problem with', name)
  }
  donutComponent.onChange(CartButtonEnableDisable)
})
})


function CartButtonEnableDisable() {

  // converts donuts array to donut quantities array
  const donutQuantities = donuts.map(getDonutQty)

  // sums each element in donutQuantities
  const totalDonuts = donutQuantities.reduce((sum, currentDonutAmount) => {
    return sum + currentDonutAmount
  }, 0)

  if ((totalDonuts >= 6)) {
    $w('#buyNow').enable();
  } else $w('#buyNow').disable();

}

export function buyNow_click(event) {

  const donutIdsAndQuantities = donuts
    // this is optional step that was not present in original code
    // it filters out donuts with zero quantity
.  filter(donut => {
      return getDonutQty(donut) > 0
    })
    // replace donuts' { name, id } representation to { productId, quantity } which addProducts() expects
    .map(({ name, id }) => {
      return { 
        productId: id,
        quantity: Number($w('#' + name).value)
      }
    })

  cart.addProducts(donutIdsAndQuantities)
    .then((updatedCart) => {
      if (formFactor !== "Mobile") {
      cart.showMiniCart();
      
      console.log('Products added', updatedCart);
    }
    })
    .catch(error => {
      console.log(error)
    })
}