Rarible tutorial marketplace display error

I almost finished the complete rarible tutorial and i’m obviously really thankful for all the help!

Everything seems to work (minting, my items showing up etc) but the marketplace wont display anymore. It could be something stupid because I’m kind of a beginner. I got these errors back in my console:

main.js:296 Uncaught (in promise) TypeError: Cannot read property 'appendChild' of null
    at renderItem (main.js:296)
    at main.js:306

`localhost/:67 GET http://localhost:8000/.../ 404 (File not found)

I can provide any code if needed.

server url: https://xcfmpfwalrip.moralis.io:2053/server

Hope someone can help me out!

1 Like

Yes, please provide the code as well as check our most common issues at FAQ - Common Issues & How To Get Help

1 Like

I think these are all the relevant codes in main.js, index.html and cloud functions respectively :

renderItem = (item) => {
    const itemForSale = marketplaceItemTemplate.cloneNode(true); 
    if (item.sellerAvatar){
        itemForSale.getElementsByTagName("img")[0].src = item.sellerAvatar.url();
        itemForSale.getElementsByTagName("img")[0].alt = item.sellerUsername;
        itemForSale.getElementsByTagName("span")[0].innerText = item.sellerUsername;
    }
    itemForSale.getElementsByTagName("img")[1].src = item.image;
    itemForSale.getElementsByTagName("img")[1].alt = item.name;
    itemForSale.getElementsByTagName("h5")[0].innerText = item.name;
    itemForSale.getElementsByTagName("p")[0].innerText = item.description;

    itemForSale.getElementsByTagName("button")[0].innerText = `Te koop voor ${item.askingPrice}`;
    itemForSale.getElementsByTagName("button")[0].onclick = () => buyItem(item);
    itemForSale.id = `item-${item.uid}`;
    itemsForSale.appendChild(itemForSale);      
}

getAndRenderItemData = (item, renderFunction) => {
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data => {
        item.name = data.name;
        item.description = data.description;
        item.image = data.image;
        renderFunction(item);
    })
}
ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');
    const contract = new web3.eth.Contract(tokenContractAbi, tokenAddress);
    const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
    if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS);
        await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS, tokenId).send({from: userAddress});
}

const userItemTemplate = initTemplate("itemTemplate");
const marketplaceItemTemplate = initTemplate("marketplaceItemTemplate");
//items for sale

const itemsForSale = document.getElementById("ItemsForSale");


    <div class="col mb-4" id="marketplaceItemTemplate">
        <div class="card h-100 border-light bg-transparent text-light">
            <nav class="card-header navbar navbar-dark text-light p-1">
            <img src="" alt="">
            <span></span>
        </nav>

            <img src="..." class="card-img-top" alt="...">
            <div class="card-body c-flex align-items-end">
                <div class="w-100">
                 <h5 class="card-title"></h5>
              <p class="card-text"></p>
              <button class="btn btn-primary"></button>    
                </div>
            </div>
          </div>
    </div>


    <div class="col mb-4" id="itemTemplate">
      <div class="card h-100 border-light bg-transparent text-light">


          <img src="..." class="card-img-top" alt="...">
          <div class="card-body c-flex align-items-end">
              <div class="w-100">
               <h5 class="card-title"></h5>
            <p class="card-text"></p>

            <div class="input-group mb-3">
              <input type="number" min="1" step="1" class="form-control" placeholder="price">
              <div class="input-group-append">
              <button class="btn btn-outline-secondary" type="button">te koop zetten</button>
            </div>  
          </div>
              </div>
          </div>
        </div>
  </div>


Moralis.Cloud.define("getItems", async (request) => {

  const query = new Moralis.Query("ItemsForSale");
  query.notEqualTo("isSold", true);
  query.select("uid", "askingPrice", "tokenAddress", "tokenId", "token.token_uri", "token.symbol", "token.owner_of", "token.id", "user.avatar");
  
  const queryResults = await query.find({useMasterKey:true});
  const results = [];

  for (let i = 0; i < queryResults.length; ++i) {
    
    if (!queryResults[i].attributes.token || !queryResults[i].attributes.user) continue;
	
    results.push({
    	"uid": queryResults[i].attributes.uid,
      	"tokenId": queryResults[i].attributes.token_id,
 	    "tokenAddress": queryResults[i].attributes.tokenAddress,
       	"askingPrice": queryResults[i].attributes.askingPrice,
      
     	"symbol": queryResults[i].attributes.token.attributes.symbol,
    	"tokenUri": queryResults[i].attributes.token.attributes.token_uri,
      	"ownerOf": queryResults[i].attributes.token.attributes.owner_of,
      	"tokenObjectId": queryResults[i].attributes.token.id,
      
      	"sellerUsername": queryResults[i].attributes.user.attributes.username,
      	"sellerAvatar": queryResults[i].attributes.user.attributes.avatar,      
    });
  }
  return results;
});

Moralis.Cloud.define("getItem", async (request) => {

  const query = new Moralis.Query("ItemsForSale");
  query.EqualTo("uid", request.params.uid);
  query.select("uid", "askingPrice", "tokenAddress", "tokenId", "token.token_uri", "token.symbol", "token.owner_of","token.id", "user.avatar", "user.username");
  
  const queryResult = await query.first({useMasterKey:true});
  if (!queryResult) return;
	return {
    	"uid": queryResult.attributes.uid,
      	"tokenId": queryResult.attributes.token_id,
 	    "tokenAddress": queryResult.attributes.tokenAddress,
       	"askingPrice": queryResult.attributes.askingPrice,
      
     	"symbol": queryResult.attributes.token.attributes.symbol,
    	"tokenUri": queryResult.attributes.token.attributes.token_uri,
      	"ownerOf": queryResult.attributes.token.attributes.owner_of,
		"tokenObjectId": queryResult.attributes.token.id,
      
      	"sellerUsername": queryResult.attributes.user.attributes.username,
      	"sellerAvatar": queryResult.attributes.user.attributes.avatar,      
    };
});

My guess is that you have defined “ItemsforSale” with another casing than const itemsForSale = document.getElementById("ItemsForSale"); in your HTML (It is not shown in your posted code), and therefore the variable is undefined.

1 Like

This was the problem. Thank you a lot for helping me again. It all seems to work properly now so that means I finished your tutorial. Really grateful for al your effort

1 Like

Hi All,

I’m having a similar problem to the OP here, and I’m not sure where to begin in debugging or fixing.

I can mint and display user items just fine, but the for sale items don’t appear!

I’m getting a different error than the OP though:

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

Promise.then (async)

getAndRenderItemData @ main.js:278
(anonymous) @ main.js:199
loadUserItems @ main.js:196
async function (async)
loadUserItems @ main.js:195
initUser @ main.js:71
async function (async)
initUser @ main.js:66
init @ main.js:11
async function (async)
init @ main.js:8
(anonymous) @ main.js:355

Any help you guys could give would be very much appreciated! Thank you so much for all your hard work!

@tsmoreau,

Please provide us with your main.js file so that we can accurately pin point your issue.

Thanks. :slight_smile:

Of course! I’m not totally sure where I’m going wrong, but at least I can see my own items.

Truly odd part is that I’m getting different errors on Mac and PC when testing!

My main.js can be found below, thank you so much:

Moralis.initialize("scTtiXXPZvvBFkMjpzH4G2o2FgF9TAh2t5v6Puav");
Moralis.serverURL = 'https://cwpoaa9isobw.moralis.io:2053/server';
const TOKEN_CONTRACT_ADDRESS = "0x110eE108f45330E3Ae7e538614AA4eBD525E6A9D";
const MARKETPLACE_CONTRACT_ADDRESS = "0xC410AcefF25B05DEA7aDB65c7B92Bc272D9b87F3";

init = async () => {
    hideElement(userItemsSection);
    window.web3 = await Moralis.Web3.enable();
    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
    window.marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);
    initUser();
    loadItems();

    const soldItemsQuery = new Moralis.Query('SoldItems');
    const soldItemsSubscription = await soldItemsQuery.subscribe();
    soldItemsSubscription.on("create", onItemSold);

    const itemsAddedQuery = new Moralis.Query('ItemsForSale');
    const itemsAddedSubscription = await itemsAddedQuery.subscribe();
    itemsAddedSubscription.on("create", onItemAdded);
}

onItemSold = async (item) => {
    const listing = document.getElementById(`item-${item.attributes.uid}`);
    if (listing){
        listing.parentNode.removeChild(listing);
    }
    
    user = await Moralis.User.current();
    if (user){
        const params = {uid: `${item.attributes.uid}`};
        const soldItem = await Moralis.Cloud.run('getItem', params);
        if (soldItem){
            if (user.get('accounts').includes(item.attributes.buyer)){
                getAndRenderItemData(soldItem, renderUserItem);
            }

            const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
            if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
          
        }
   
    }
}

onItemAdded = async (item) => {
    const params = {uid: `${item.attributes.uid}`};
    const addedItem = await Moralis.Cloud.run('getItem', params);
    if (addedItem){
        user = await Moralis.User.current();
        if (user){
            if (user.get('accounts').includes(addedItem.ownerOf)){
                const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
                if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);

                getAndRenderItemData(addedItem, renderUserItem);
                return;
            }
        }
        getAndRenderItemData(addedItem, renderItem);
    }

}

initUser = async () => {
    if (await Moralis.User.current()){
        hideElement(userConnectButton);
        showElement(userProfileButton);
        showElement(openCreateItemButton);
        showElement(openUserItemsButton);
        loadUserItems();
    }else{
        showElement(userConnectButton);
        hideElement(userProfileButton);
        hideElement(openCreateItemButton);
        hideElement(openUserItemsButton);
    }
}

login = async () => {
    try {
        await Moralis.Web3.authenticate();
        initUser();
    } catch (error) {
        alert(error)
    }
}

logout = async () => {
    await Moralis.User.logOut();
    hideElement(userInfo);
    initUser();
}

openUserInfo = async () => {
    user = await Moralis.User.current();
    if (user){    
        const email = user.get('email');
        if(email){
            userEmailField.value = email;
        }else{
            userEmailField.value = "";
        }

        userUsernameField.value = user.get('username');

        const userAvatar = user.get('avatar');
        if(userAvatar){
            userAvatarImg.src = userAvatar.url();
            showElement(userAvatarImg);
        }else{
            hideElement(userAvatarImg);
        }

        $('#userInfo').modal('show');
    }else{
        login();
    }
}

saveUserInfo = async () => {
    user.set('email', userEmailField.value);
    user.set('username', userUsernameField.value);

    if (userAvatarFile.files.length > 0) {
        const avatar = new Moralis.File("avatar1.jpg", userAvatarFile.files[0]);
        user.set('avatar', avatar);
    }

    await user.save();
    alert("User info saved successfully!");
    openUserInfo();
}

createItem = async () => {

    if (createItemFile.files.length == 0){
        alert("Please select a file!");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please give the item a name!");
        return;
    }

    const nftFile = new Moralis.File("nftFile.jpg",createItemFile.files[0]);
    await nftFile.saveIPFS();

    const nftFilePath = nftFile.ipfs();

    const metadata = {
        name: createItemNameField.value,
        description: createItemDescriptionField.value,
        image: nftFilePath,
    };

    const nftFileMetadataFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
    await nftFileMetadataFile.saveIPFS();

    const nftFileMetadataFilePath = nftFileMetadataFile.ipfs();

    const nftId = await mintNft(nftFileMetadataFilePath);

    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');

    switch(createItemStatusField.value){
        case "0":
            return;
        case "1":
            await ensureMarketplaceIsApproved(nftId, TOKEN_CONTRACT_ADDRESS);
            await marketplaceContract.methods.addItemToMarket(nftId, TOKEN_CONTRACT_ADDRESS, createItemPriceField.value).send({from: userAddress });
            break;
        case "2":
            alert("Not yet supported!");
            return;
    }
}

mintNft = async (metadataUrl) => {
    const receipt = await tokenContract.methods.createItem(metadataUrl).send({from: ethereum.selectedAddress});
    console.log(receipt);
    return receipt.events.Transfer.returnValues.tokenId;
}

openUserItems = async () => {
    user = await Moralis.User.current();
    if (user){    
        $('#userItems').modal('show');
    }else{
        login();
    }
}

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    ownedItems.forEach(item => {
        const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
        if (userItemListing) return;
        getAndRenderItemData(item, renderUserItem);
    });
}

loadItems = async () => {
    const items = await Moralis.Cloud.run("getItems");
    user = await Moralis.User.current();
    items.forEach(item => {
        if (user){
            if (user.attributes.accounts.includes(item.ownerOf)){
                const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
                if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
                getAndRenderItemData(item, renderUserItem);
                return;
            }
        }
        getAndRenderItemData(item, renderItem);
    });
}


initTemplate = (id) => {
    const template = document.getElementById(id);
    template.id = "";
    template.parentNode.removeChild(template);
    return template;
}

renderUserItem = async (item) => {
    const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
    if (userItemListing) return;

    const userItem = userItemTemplate.cloneNode(true);
    userItem.getElementsByTagName("img")[0].src = item.image;
    userItem.getElementsByTagName("img")[0].alt = item.name;
    userItem.getElementsByTagName("h5")[0].innerText = item.name;
    userItem.getElementsByTagName("p")[0].innerText = item.description;

    userItem.getElementsByTagName("input")[0].value = item.askingPrice ?? 1;
    userItem.getElementsByTagName("input")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].onclick = async () => {
        user = await Moralis.User.current();
        if (!user){
            login();
            return;
        }
        await ensureMarketplaceIsApproved(item.tokenId, item.tokenAddress);
        await marketplaceContract.methods.addItemToMarket(item.tokenId, item.tokenAddress, userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') });
    };

    userItem.id = `user-item-${item.tokenObjectId}`
    userItems.appendChild(userItem);
}

renderItem = (item) => {
    const itemForSale = marketplaceItemTemplate.cloneNode(true);
    if (item.sellerAvatar){
        itemForSale.getElementsByTagName("img")[0].src = item.sellerAvatar.url();
        itemForSale.getElementsByTagName("img")[0].alt = item.sellerUsername;
     
    }

    itemForSale.getElementsByTagName("img")[1].src = item.image;
    itemForSale.getElementsByTagName("img")[1].alt = item.name;
    itemForSale.getElementsByTagName("h5")[0].innerText = item.name;
    itemForSale.getElementsByTagName("p")[0].innerText = item.description;

    itemForSale.getElementsByTagName("button")[0].innerText = `Buy for ${item.askingPrice}`;
    itemForSale.getElementsByTagName("button")[0].onclick = () => buyItem(item);
    itemForSale.id = `item-${item.uid}`;
    itemsForSale.appendChild(itemForSale);
}


getAndRenderItemData = (item, renderFunction) => {
    
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data => {
        item.name = data.name;
        item.description = data.description;
        item.image = data.image;
        renderFunction(item);
    })
}

ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');
    const contract = new web3.eth.Contract(tokenContractAbi, tokenAddress);
    const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
    if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS){
        await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS,tokenId).send({from: userAddress});
    }
}

buyItem = async (item) => {
    user = await Moralis.User.current();
    if (!user){
        login();
        return;
    } 
    await marketplaceContract.methods.buyItem(item.uid).send({from: user.get('ethAddress'), value: item.askingPrice});
}

hideElement = (element) => element.style.display = "none";
showElement = (element) => element.style.display = "block";

// Navbar
const userConnectButton = document.getElementById("btnConnect");
userConnectButton.onclick = login;

const userProfileButton = document.getElementById("btnUserInfo");
userProfileButton.onclick = openUserInfo;

const openCreateItemButton = document.getElementById("btnOpenCreateItem");
openCreateItemButton.onclick = () => $('#createItem').modal('show');

//  User profile
const userInfo = document.getElementById("userInfo");
const userUsernameField = document.getElementById("txtUsername");
const userEmailField = document.getElementById("txtEmail");
const userAvatarImg = document.getElementById("imgAvatar");
const userAvatarFile = document.getElementById("fileAvatar");

document.getElementById("btnCloseUserInfo").onclick = () => hideElement(userInfo);
document.getElementById("btnLogout").onclick = logout;
document.getElementById("btnSaveUserInfo").onclick = saveUserInfo;

// Item creation
const createItemForm = document.getElementById("createItem");

const createItemNameField = document.getElementById("txtCreateItemName");
const createItemDescriptionField = document.getElementById("txtCreateItemDescription");
const createItemPriceField = document.getElementById("numCreateItemPrice");
const createItemStatusField = document.getElementById("selectCreateItemStatus");
const createItemFile = document.getElementById("fileCreateItemFile");
document.getElementById("btnCloseCreateItem").onclick = () => hideElement(createItemForm);
document.getElementById("btnCreateItem").onclick = createItem;

// User items
const userItemsSection = document.getElementById("userItems");
const userItems = document.getElementById("userItemsList");
document.getElementById("btnCloseUserItems").onclick = () => hideElement(userItemsSection);
const openUserItemsButton = document.getElementById("btnMyItems");
openUserItemsButton.onclick = openUserItems;


const userItemTemplate = initTemplate("itemTemplate");
const marketplaceItemTemplate = initTemplate("marketplaceItemTemplate");

// Items for sale
const itemsForSale = document.getElementById("itemsForSale");


init();

Dunno if it helps, but I realized that the ItemsForSale displays just fine if the user isn’t logged in, but as soon as you log in, the same JSON error noted above appears.

I’m not sure if it’s something in the Cloud Functions or something in the main.js though

Hey @bature

Take a look at my answer here

Yeah it worked. some part of it not all.
Only user minted nft cards are visible, the remaining nft cards are not visible to users that did not mint them by default.
and whenever i tried pressing the put for sale button. i Receive an error then the transaction will fail.

Meaning, apart from the items user1 personally minted, he/she cant see user2 minted NFT

Hey @bature

Try this:

1 Like