Wishlist Coding Issues with parameters

I keep getting these messages on my wishlist page for my website:
Wix code SDK Warning: The src parameter of “productImage” that is passed to the src method cannot be set to null or undefined.
Wix code SDK Warning: The text parameter of “name” that is passed to the text method cannot be set to null or undefined.
Wix code SDK Warning: The text parameter of “price” that is passed to the text method cannot be set to null or undefined.

I’ve been using the codes in the tutorials to help me as well as the example site but I can’t for the life of me figure out what to do. I’ve been researching and working on this code for OVER A WEEK and nothing has helped. I’ve underlined it for recognition purposes for anyone who can help but it’s obviously not underlined on my site.

This is the section of code that I’m having issues with:
// Set up the wishlist repeater items when the repeater’s data is loaded.
function myItemReady($w, wishlistItem){
// Get the wishlist product.
let product = wishlistItem.product;
// Set the repeater’s elements using the item data.
$w(‘#productImage’).src = product.mainMedia;
$w(‘#name’).text = product.name;
$w(‘#price’).text = product.formattedPrice;
// Set the action that occurs when the product image is clicked.
$w(‘#productImage’).onClick(() => {
// Navigate to the wishlist item’s product page.
wixLocation.to(product.productPageUrl);
});
// Set the action that occurs when the remove item image is clicked to the removeItem() function.
$w(‘#removeItem’).onClick(removeItem(wishlistItem._id));
}

Does anyone have ANY clue on what I need to fix?

Have you tried using the Connect to Data feature on the repeater Gallery instead of using code to see if that changes the behavior? I have a Pro Gallery that I have connected to the dataset as a category page and lists a bunch of locations that I have stored in a collection. https://www.fishonbassanglers.com/Tournaments/Locations

The Connect to Data on it is configured as shown below

The wishlist data is supposed to be what the customer adds to the wishlist from the product pages. Its member manipulated so its different than you adding a gallery that you change the images for and that everyone can see. A wishlist can only be seen by the member who has created that list.

Besides that, yes, I have tried doing that but it defeats the purpose of the wishlist and doesn’t function like a wishlist should.

Gotcha. Have you doublechecked that the field keys are not all lowercase (ie mainmedia instead of mainMedia)? The case of the field names can be different from the field keys

@poolshark314 Yup. I’ve even tried changing it just to check. I’m not kidding when I said I’ve tried pretty much everything and have been working on this dang code for at least 3 hours every day for the past week.

This is what I keep getting:


and this is the full code for that section:


So the repeater is working, just not the image, product name, and price.

@aejul95 I don’t have the Wix Store app so i’m not sure but can you look at wishlists in Preview mode? If you can, you can try to use console.log() to see what is being returned from product. For example:

console.log(product.name)

placed within your myItemReady function should return the name of the product in the debug console window. If it doesn’t or returns ‘undefined’, the product is not being read from the collection properly. If you did:

console.log(product)

it should return an array that has the mainMedia, name, formattedPrice, etc. If that command shows empty, then I don’t think the issue is within your myItemReady function and may be back in the loadWishlist function.

Sorry in advance if you have already tried this, but I found it helps to work backwards through the output to see where the hangup is

@poolshark314 I don’t quite understand. I’m new to coding. Could you show me where exactly I’d have to put the console.log(product.name)?
I also feel like my problem is more related to the 2 lines above where the error codes are coming from but I don’t understand how what to change in order to make it work.

@aejul95 It can go anywhere after your declaration of product, so it can go right underneath the “let product =…” line on its own line. I have a feeling that product will be undefined or empty, which would likely mean the issue isn’t in the myItemReady function, but before it and the wishlistItem isn’t getting passed to it properly. Console.log just writes to the debug screen, so when you are in preview mode, just expand the panel that shows up at the bottom (the same place where the code panel is normally. If you see nothing or undefined then your product is empty

Hi Ashley:

poolshark314 is on the right track. What ever you have calling your myItemReady() function is likely to be passing a null argument or the wrong argument.

Lets examine this in a mini tutorial using your code:

function myItemReady($w, wishlistItem){
    // Get the wishlist product.
    let product = wishlistItem.product;
    // Set the repeater's elements using the item data.     
    $w('#productImage').src = product.mainMedia;
    $w('#name').text = product.name;
    $w('#price').text = product.formattedPrice;

The Warning you are getting:
Wix code SDK Warning: The src parameter of “productImage” that is passed to the src method cannot be set to null or undefined.
Is essentially saying:

“Hey you cannot set $w(‘#productImage’).src to a non-existent value”
OK let’s reverse through the code.

The assignment that is a problem is this one:

$w('#productImage').src = product.mainMedia

This means that the value of product.mainMedia doesn’t exist (is null or undefined). Why would this be the case?

Well either:

  • the value of product is null or undefined
    OR

  • product exists BUT it doesn’t have a property called mainMedia.

QUICK Tutorial:
Many times when we use data collections we have all of the data for an item in what is called an object. This is a container that carries multiple values we need each of which is attached to a name that we call a key. These “key:value” pairs are convenient ways to access the value.

In our example we need to assume that product is an object which is carrying some of these “key:value” pairs and that you think one of them is called mainMedia. So if I were to examine a valid product instance I would see something like this:

let product = {
    "mainMedia": "an Image URL",
    "name": "the product name",
    "formattedPrice": "theFormatted price"
    ... // other records if any
};

If product doesn’t contain a “key:value” pair like “mainMedia”: “an Image URL” then product.mainMedia gives us a null value. null tells us that javascript was sent on a wild goose chase and found nothing!

OK So now we have to look at product to see if it could be the problem. This is the code that gives us our product value:

let product = wishlistItem.product;

Oh guess what another object assignment.

We are not getting an error with this assignment why is that? Well it is perfectly legal to give a new variable (created using let or var) a null value. So this means that:

  • wishlistItem could be null
    OR

  • there is no “key:value” pair contained in wishlistItem

By the way - this is the sort of stuff developers love to do :wink:
We now have a mystery that we need to solve. Some where in your code a bad value is being set and we need to figure out where that bad value is coming from to fix the problem. As poolshark314 points out it is highly likely that the problem has nothing to do with your myItemReady() function but the code that calls it :-).
The way we figure that out is by using some console.log() calls. These print the values of the variables at key points in our code to tell us what the values of the dat are as we head towards the problem area. With this data we can (hopefully) get rid of the bad (buggy) code.

So key points to look at values are - always - when a function is called (to see if we got the value we were expecting. So since we are expecting an object we need to use a JSON call to see the contents reliably. The call you need looks like this:

function myItemReady($w, wishlistItem){
    // Check our argument - stringify makes sure the object can be
    // Printed. We also check for a null value and say that is what we found
    console.log((wishlistItem ? JSON.stringify(wishlistItem): "wishlist is NULL!"));
    // Get the wishlist product.
    let product = wishlistItem.product;

The other thing we need to check (if wishlistItem is valid) is what product contains. You should see product in the console.log() output above. This is simply double checking things:

// Get the wishlist product.
let product = wishlistItem.product;
console.log((product ? JSON.stringify(product): "product is NULL!"));

Now you have this you might be able to figure the rest out. If not we will need to see ALL of your code and have more context for the page.
Also if you post the URL for your page we can given even more help :wink:

Steve

Okay. I’m trying to follow along the best I can but you’re teaching coding to someone with a biology degree. Haha!
This is what I put in:


And this is what I got:


Did I do it wrong? If not, what does this mean and what do I do from here?

There’s still a ton of changes to be made, but this is the website so far: https://aejul95.wixsite.com/lavecksgarden

@aejul95 That looks correct, and that output looks like the wishlistItem is getting passed correctly into the myItemReady function. That is the ID of the wishlistitem in your collection. To view the corresponding record, if you went into the collection that item is stored in, and then clicked Visible Fields at the top and check the box for ID, you should find that ID listed there and the corresponding properties. I would say also check the name, mainMedia, and formattedPrice fields for that item to make sure they are not empty.

Can you try the same thing with console.log() for product.mainMedia, product.name, and product.formattedPrice?

@poolshark314 Okay.
I’ve done this:


And got :


And I did this:


And got:


What now?

@aejul95 Ahhh now if you look at the output from the console.log() and look for the product key value pair you will see this:

product: "a814dc83-e30a-ca9d-8895-80c4d651b11d"

Now as I mentioned in my mini tutorial product needs to be an object. An object contains key value pairs. If product was an object with a value for the property mainMedia then we would see something like this:

product : { mainMedia: "<a string containing a link to an image>"}

So what product actually contains is a unique identifier. OK so I have looked at the wishList example tutorial which you no doubt copied:

What it does is remember information in a wishList data collection by recording the unique id from the product record.

async function addToWishlist() {
  let wishListItem = {
    product: product._id,  <<<<< adds a product id not the item
    userId: user.id
  };
  let result = await wixData.insert("Wishlist", wishListItem);
}

So you need to use the product._id that is in the product field to get the item from the product data collection.

So this is what you need to do:

function myItemReady($w, wishlistItem){
    // Get the wishlist product.
    let product = wishlistItem.product;
    
    // Get the product information from the product database
    wixData.get("Stores/Products", product)
    .then((productRecord) => {
        // Set the repeater's elements using the item data.   
        $w('#productImage').src = productRecord.mainMedia;
        $w('#name').text = productRecord.name;
        $w('#price').text = productRecord.formattedPrice;
    });
}

This should do what you want :slight_smile:

Steve

Oh my Jesus. I feel like I’m so close to getting it right…
This is what I did:


And got:

  1. I hate those darn parsing errors and don’t 100% know how to deal with them
  2. The information shows up in my repeater but its not showing the exact data that it’s supposed to - the actual image of the product that I have saved to my wishlist, it’s name, and price.

Delete line 72. The red dot is flagging an error in your code. It is telling you that you have terminated the function already (on line 72) if you remove the } (this ends the function definition). It should do what you want. The function ends on line 79 (where the red dot error is being flagged). You will know if you have deleted the right line because the red dot will go away!

OH MY GOD!!! Thank you so much! You have no idea how much I appreciate your help.

Excellent! Can I ask you add a Top Comment to the post to let others know it has been answered? Good luck with the rest of your site.

I have a problem. So, everything is pretty much working the way that its supposed to but it doesn’t add a product to the wishlist every time I favorite it, only sometimes. If I try to delete an item from the wishlist, sometimes it deletes multiple items at the same time. Could you take a look at it and see if it does it for you?
There is a tiny hidden pepper at the bottom right hand corner of the footer that accesses the product page:


And the wishlist button is hidden. Just click inside the circle to access the wishlist.

https://aejul95.wixsite.com/lavecksgarden/account/wishlist

https://aejul95.wixsite.com/lavecksgarden/shop

@Steve Cropper, i wish there were more members like you, while i am not dealing with an issue like this, i absolutely love the fact you took the time to help and teach people how they can find answers themselves.

@aejul95 Hi Ashley
I ran a couple of checks and the functionality seems to work fine. Having looked at your code (which looks pretty good) I think you might want to think about a couple of things:

  1. What happens if there is an error when accessing the database?
  2. Only change visual cues to users when a database transaction has completed.

To address these issues you may want to change you code and stop using the await form of accessing the data collection using wix-data and make use of the Promises functionality.

The await will block and wait for the promise to complete but won’t catch any errors that might occur. To catch errors you need to add a catch block.

If you use the Promise .then() function after the wix-data request completes and THEN change the wishlish icons you will know that the data has been saved into the data collection.

So what would this look like in code?

//-------------Wishlist Functionality-------------//

// Add the current product to the current user's wishlist and update the page accordingly.
//**Steve: remove async from function declaration
function addToWishlist() {
 // Create the wishlist item relating the current product to the current user.
 let wishListItem = {
        product: product._id, 
        userId: user.id
    };

//**Steve: Call insert before changing wishlist icons 
 // Insert the item created above into the "products-wishlist" collection.
 wixData.insert("wishlist", wishListItem) // **Steve: remove await and semi-colon
.then((result) => {     // **Steve: add then block
    //**Steve: If we get here the insert was successful but use an if  statement to make sure
    if (result) {
         // Hide the "notInWishList" image with a fade effect.
        $w('#notInWishList').hide('fade', {duration: 100});
        // Show the "inWishList" image with a fade effect.
        $w('#inWishList').show('fade', {duration: 100});
   } else {
        console.log("SHOULD NEVER GET HERE: insert result is null!");
   }
})
// **Steve: add a catch block in case we have a wix-data error
.catch((error) => {
    // **Steve: Console log the error - this could also be used to show an error to the user
    console.log(error);
});
 
}

// Remove the current product to the current user's wishlist and update the page accordingly.
//**Steve: remove async from function declaration
function removeFromWishlist() {
    // Query the "products-wishlist" collection to find the wishlist item corresponding to the current product and current user.
   // **Steve: declare wishlistRecordCount for later use
   let wishlistRecordCount = 0;
   //**Steve: remove async from function declaration
   wixData.query("wishlist")
        .eq("product", product._id)
        .eq("userId", user.id)
        .find()
        // **Steve: Add then so we can make sure we have a success before continuing
        .then((wishListResult) => {
            // If a wishlist item was found: 
            // **Steve: We need to determine what an error is here
            // **Steve: for example should we only ever have one or zero records in the wishlist?
            // **Steve: the code below assumes we only expect zero or one and 
            // **Steve: uses console.log() to warn of this but removes the first record anyway
            // **Steve: We want to return a promise so we can add the remove promise and catch
            // **Steve: all errors in one place. We default to a dummy promise that always works
            let returnPromise = Promise.resolve(null); // **Steve: null means not object present
            wishlistRecordCount = wishListResult.length; // **Steve: remember the wishlist record count
            if (wishlistRecordCount > 0) {
                let recordToRemove = wishListResult.items[0];
                // **Steve: We need to execute the remove (not return a successful Promise)
                // **Steve: So override the returnPromise...
                returnPromise = wixData.remove("wishlist", recordToRemove._id) 
            }
            return returnPromise;
        })
        // **Steve: Because we returned a promise we can decide which Icons should display 
        .then((removedObject) => {
            // **Steve: If we get here we know that we have removed the last wishlist (hopefully only) 
            // **Steve: item from the data collection. If we found more than one then we need to 
            // **Steve: report that so we throw an exception which the catch will handle. 
            // **Steve: Otherwise we can display "notInWishlist

            if (wishlistRecordCount > 1) {
                    throw "WARNING: Wish list contained ["+wishlistRecordCount+"] duplicate product entries!! Only one{1} has been removed.";
            }
          
            // Show the "notInWishList" image with a fade effect.
            $w('#notInWishList').show('fade', {duration: 100});
            // Hide the "inWishList" image with a fade effect.
            $w('#inWishList').hide('fade', {duration: 100});
        })
        // **Steve: Catch errors!
        .catch((error) => {
            // **Steve: If we get here the remove failed for some reason or 
            // **Steve: we have more than one record so console.log() the problem and 
            // **Steve: display the inWishList icon
            console.log(error);
            // Show the "inWishList" image with a fade effect.
            $w('#inWishList').show('fade', {duration: 100});
            // Hide the "notInWishList" image with a fade effect.
            $w('#notInWishList').hide('fade', {duration: 100});
        });

 
}

Ashley - this may not solve the problem you are experiencing BUT it will help you find what might be causing them.

As a general suggestion to anyone reading this - it is always good to code defensively (i.e. don’t assume your code will always work, assume you might get an error and think about how you might handle it :-)).

Hope this helps you out
Cheers
Steve