Item don't get added to the marketplace/ Rarible Clone part 11

when i create a new item in my mktplace the item gets minted but when going to be added to the mktplace i get this error in the console: Uncaught (in promise) TypeError: Cannot read property ‘value’ of null
at HTMLButtonElement.createItem (main.js:135)
createItem @ main.js:135
async function (async)
createItem @ main.js:97

i think its a really dumb problem but i cant spot it, already did everything again, compare code etc etc and nothing, here is my js file and my marketplace contract :

Moralis.initialize("2S1i7BlfGKjOjjH913O08FZoZ9eZ9SFnCAsGB8Px");

Moralis.serverURL = 'https://hwjejw7sflts.usemoralis.com:2053/server'

const TOKEN_CONTRACT_ADDRESS = "0x820d3Eb7518A3a90AbDb1E724453B715a6E5eC2c";

const MARKETPLACE_CONTRACT_ADDRESS = "0xA84b42e49032e55c32A0E37254Fe042b654Cec8B";

init = async () => {

    hideElement(userItemsSection);

    hideElement(userInfo);

    hideElement(createItemForm)

 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();

}

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)

        }

        showElement(userInfo);

    }else{

        login();

    }

}

saveUserInfo = async () => {

    user.set('email', userEmailField.value);

    user.set('username', userUsernameField.value);

    if (userAvatarFile.files.length > 0) {

        const avatar = new Moralis.File("avatar.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 nftFileHash = nftFile.hash();

    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 nftFileMetadataFileHash = nftFileMetadataFile.hash();

    const nftId = await mintNft(nftFileMetadataFilePath);

    const Item = Moralis.Object.extend("Item");

    

    // Create a new instance of that class.

    const item = new Item();

    item.set('name', createItemNameField.value);

    item.set('description', createItemDescriptionField.value);

    item.set('nftFilePath', nftFilePath);

    item.set('nftFileHash', nftFileHash);

    item.set('metadataFilePath', nftFileMetadataFilePath);

    item.set('metadataFileHash', nftFileMetadataFileHash);

    item.set('nftId', nftId);

    item.set('nftContractAddress', TOKEN_CONTRACT_ADDRESS);

    await item.save();

    console.log(item);

    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){

        showElement(userItemsSection);

    }else{

        login();

    }

}

loadUserItems = async () => {

    const ownedItems = await Moralis.Cloud.run("getUserItems");

    ownedItems.forEach(item => {

        getAndRenderItemData(item, renderUserItem);

    });

}

initTemplate = (id) => {

    const template = document.getElementById(id);

    template.id = "";

    template.parentNode.removeChild(template);

    return template;

}

renderUserItem = (item) => {

    const userItem = userItemTemplate.cloneNode(true);

    userItem.getElementsByTagName("img")[0].src = item.image;

    userItem.getElementsByTagName("img")[0].alt = item.name;

    userItem.getElementsByTagName("img")[0].innerText = item.name;

    userItem.getElementsByTagName("img")[0].innerText = item.description;

    userItems.appendChild(userItem);

}

getAndRenderItemData = (item, renderFunction) => {

    fetch(item.tokenUri)

    .then(response => response.json())

    .then(data => {

        data.symbol = item.symbol;

        data.tokenId = item.tokenId;

        data.tokenAddress = item.tokenAddress;

        renderFunction(data);

    })

}

ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {

    user = await Moralis.User.current();

    const userAddress = user.get('ethAddress');

    const contract = window.tokenContract = new web3.eth.Contract(tokenContractAbi, tokenAddress);

    const approvedAddress = await contract.methods.getApproved(tokenId).call({from: tokenAddress});

    if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS){

        await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS, tokenId).send({from: userAddress });

    }

}

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 = () => showElement(createItemForm);

// 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(userInfo);

const openUserItemsButton = document.getElementById("btnMyItems");

openUserItemsButton.onclick = openUserItems;

const userItemTemplate = initTemplate("itemTemplate")

init();


pragma solidity ^0.8.0;

import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract CryptoFansMarketContract {

    struct AuctionItem {

        uint256 id;

        address tokenAddress;

        uint256 tokenId;

        address payable seller;

        uint256 askingPrice;

        bool isSold;

    }

    AuctionItem[] public itemsForSale;

    mapping (address => mapping (uint256 => bool)) activeItems;

    event itemAdded(uint256 id, uint256 tokenId, address tokenAddress, uint256 askingPrice);

    event itemSold(uint256 id, address buyer, uint256 askingPrice);

    modifier OnlyItemOwner(address tokenAddress, uint256 tokenId){

        IERC721 tokenContract = IERC721(tokenAddress);

        require(tokenContract.ownerOf(tokenId) == msg.sender);

        _;

    }

    modifier HasTransferApproval(address tokenAddress, uint256 tokenId){

        IERC721 tokenContract = IERC721(tokenAddress);

        require(tokenContract.getApproved(tokenId) == address(this));

        _;

    }

    

    modifier ItemExists(uint256 id){

        require(id < itemsForSale.length && itemsForSale[id].id == id, "Could not find item");

        _;

    }

    modifier IsForSale(uint256 id){

        require(itemsForSale[id].isSold == false, "Item is already sold!");

        _;

    }

    function addItemToMarket(uint256 tokenId, address tokenAddress, uint256 askingPrice) OnlyItemOwner(tokenAddress,tokenId) HasTransferApproval(tokenAddress,tokenId) external returns (uint256){

        require(activeItems[tokenAddress][tokenId] == false, "Item is already up for sale!");

        uint256 newItemId = itemsForSale.length;

        itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId, payable(msg.sender), askingPrice, false));

        activeItems[tokenAddress][tokenId] = true;

        assert(itemsForSale[newItemId].id == newItemId);

        emit itemAdded(newItemId, tokenId, tokenAddress, askingPrice);

        return newItemId;

    }

    function buyItem(uint256 id) payable external ItemExists(id) IsForSale(id) HasTransferApproval(itemsForSale[id].tokenAddress,itemsForSale[id].tokenId){

        require(msg.value >= itemsForSale[id].askingPrice, "Not enough funds sent");

        require(msg.sender != itemsForSale[id].seller);

        itemsForSale[id].isSold = true;

        activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false;

        IERC721(itemsForSale[id].tokenAddress).safeTransferFrom(itemsForSale[id].seller, msg.sender, itemsForSale[id].tokenId);

        itemsForSale[id].seller.transfer(msg.value);

        emit itemSold(id, msg.sender, itemsForSale[id].askingPrice);

    }

}

Hey @mub123

Please read READ BEFORE POSTING - How to post code in the forum topic.

After formating the message I’ll be ready for helping you :man_mechanic:

1 Like

@mub123
Could you please provide your html code?

1 Like

is price set before adding item to marketplace?
I guess it may be that…

1 Like

From the error message it looks like there is a problem with input handling. I’ve tested your JS code with HTML CODE from tutorial in github and I had no problem with that.

1 Like
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>CryptoFans</title>

</head>

<body>

     <div>

        <button id="btnConnect">Connect wallet</button>

        <button id="btnUserInfo">Profile</button>

        <button id="btnOpenCreateItem">Create</button>

        <button id="btnMyItems">My Items</button>

    </div>

    <div id="userInfo">

         <h4>User Profile</h4>

         <input type="text" id="txtUsername" required placeholder="Enter username">

         <input type="text" id="txtEmail" placeholder="Enter email">

        <small>Optional</small>

        <img width="50" height="50" src="" id="imgAvatar" alt="">

        <label for="fileAvatar">Select Avatar </label>

        <input type="file" id="fileAvatar">

        <button id="btnLogout">Log Out</button>

        <button id="btnCloseUserInfo">Close</button>

        <button id="btnSaveUserInfo">Save</button>

    </div>

    <div id="createItem">

        <h4>Create Item</h4>

        <input type="text" id="txtCreateItemName" required placeholder="Enter name">

        <textarea id ="txtCreateItemDescription" cols="30" rows="5" placeholder="Enter description"></textarea>

        <input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required>

       

        <label for="selectCreatItemStatus">Status</label>

        <select id="selectCreatItemStatus">

            <option value="0">Not for sale</option>

            <option value="1">Instant buy</option>

            <option value="2">Accept Offers</option>

        </select>

       <label for="fileCreateItemFIle">Select File</label>

       <input type="file" id="fileCreateItemFile">

       <button id="btnCloseCreateItem">Close</button>

       <button id="btnCreateItem">Create!</button>

   </div>

<div id="userItems">

    <h4>My Items</h4>

    <div id="userItemsList"></div>

    <button id="btnCloseUserItems">Close</button>

</div>

<div id="itemTemplate">

    <img src="" alt="">

    <h5></h5>

    <p></p>

</div>

        <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

        <script src="https://unpkg.com/moralis/dist/moralis.js"></script>

        <script src="abi.js"></script>

        <script src="main.js"></script>

</body>

</html>

here it is
my index.html file

Hey @mub123

Take a look at my answer here:

1 Like

i’ve check that and now im not getting the same error again, i think was a typo problem in the html file, but now i’m getting this error:
TypeError: marketplaceContract.methods.addItemToMarket is not a function
at HTMLButtonElement.createItem (main.js:140)

but my marketplace.sol file has this function idk why it doesn’t get working, maybe its a contract reference problem but idk where
here my Marketplace.sol file

pragma solidity ^0.8.0;

import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract CryptoFansMarketContract {

    struct AuctionItem {

        uint256 id;

        address tokenAddress;

        uint256 tokenId;

        address payable seller;

        uint256 askingPrice;

        bool isSold;

    }

    AuctionItem[] public itemsForSale;

    mapping (address => mapping (uint256 => bool)) activeItems;

    event itemAdded(uint256 id, uint256 tokenId, address tokenAddress, uint256 askingPrice);

    event itemSold(uint256 id, address buyer, uint256 askingPrice);

    modifier OnlyItemOwner(address tokenAddress, uint256 tokenId){

        IERC721 tokenContract = IERC721(tokenAddress);

        require(tokenContract.ownerOf(tokenId) == msg.sender);

        _;

    }

    modifier HasTransferApproval(address tokenAddress, uint256 tokenId){

        IERC721 tokenContract = IERC721(tokenAddress);

        require(tokenContract.getApproved(tokenId) == address(this));

        _;

    }

    

    modifier ItemExists(uint256 id){

        require(id < itemsForSale.length && itemsForSale[id].id == id, "Could not find item");

        _;

    }

    modifier IsForSale(uint256 id){

        require(itemsForSale[id].isSold == false, "Item is already sold!");

        _;

    }

    function addItemToMarket(uint256 tokenId, address tokenAddress, uint256 askingPrice) OnlyItemOwner(tokenAddress,tokenId) HasTransferApproval(tokenAddress,tokenId) external returns (uint256){

        require(activeItems[tokenAddress][tokenId] == false, "Item is already up for sale!");

        uint256 newItemId = itemsForSale.length;

        itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId, payable(msg.sender), askingPrice, false));

        activeItems[tokenAddress][tokenId] = true;

        assert(itemsForSale[newItemId].id == newItemId);

        emit itemAdded(newItemId, tokenId, tokenAddress, askingPrice);

        return newItemId;

    }

    function buyItem(uint256 id) payable external ItemExists(id) IsForSale(id) HasTransferApproval(itemsForSale[id].tokenAddress,itemsForSale[id].tokenId){

        require(msg.value >= itemsForSale[id].askingPrice, "Not enough funds sent");

        require(msg.sender != itemsForSale[id].seller);

        itemsForSale[id].isSold = true;

        activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false;

        IERC721(itemsForSale[id].tokenAddress).safeTransferFrom(itemsForSale[id].seller, msg.sender, itemsForSale[id].tokenId);

        itemsForSale[id].seller.transfer(msg.value);

        emit itemSold(id, msg.sender,itemsForSale[id].askingPrice);

    }

}

i’m not getting this error anymore, i think was a typo in the abi.js file. But now i get a error when signing the contract in Metamask :

ALERT: Transaction error. Exception presented in the contract code.

i’ve already raised up the gas limit but keeps getting the same error.

thanks for the attention guys. really.

@mub123

I’ve checked your smartcontract code. It works.

Please check if addresses in smartcontract are correct. (like token address)

1 Like

yeah the problem really was the addresses, now it’s working, thank you very much bro
but now i did some changes in the code , already finished the project but now when creating an item it’s gets minted but then i get this error:

main.js:182 Uncaught (in promise) TypeError: Cannot read property 'returnValues' of undefined
    at mintNft (main.js:182)
    at async HTMLButtonElement.createItem (main.js:161)
mintNft @ main.js:182
async function (async)
createItem @ main.js:146

where this 'Values" property is supposed to be defined so i can check what’s the matter with it?

and here is my main.js finished file:

Moralis.initialize("Pn1ilBznuBGcuz3m3CNluBb2lRvCStEwmacdIAnQ");

Moralis.serverURL = 'https://wcunveau0zm1.usemoralis.com:2053/server'

const TOKEN_CONTRACT_ADDRESS = "0x42f5FE656bc6AE752937f1E3eF6CcB3782DF24e7";

const MARKETPLACE_CONTRACT_ADDRESS = "0x6BdDb81c4A308246E0203E13165Bb5c547523199";

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();

thank you very much for the time ,really, moralis is awesome!! :slight_smile:

1 Like

Hi @mub123,

Your index.html does not have any element with id marketplaceItemTemplate and you are trying to create a template using this - const marketplaceItemTemplate = initTemplate("marketplaceItemTemplate"); which will throw an error.

Also, the spelling of this element id is wrong compared to what you are trying to query in your JS

<label for="selectCreatItemStatus">Status</label>
      <select id="selectCreatItemStatus">

Your JS -
const createItemStatusField = document.getElementById("selectCreateItemStatus");

Another thing I noticed, You were missing the input element in your “itemTemplate” div.
It should look like this –

 <div id="itemTemplate">
      <img src="" alt="" />
      <h5></h5>
      <p></p>
      <input type="number" min="1" step="1" />
      <button>Put for sale</button>
    </div>

We expect you to do some basic debugging before reaching out in the forum. You can always compare your code with the original from our GitHub repos of the tutorials to understand what difference you have in your code.

Looking forward to your progress. :raised_hands:

Hope this helps. Happy Building! :man_mechanic:

1 Like

hmm strange because i cloned and compared my index.html from github repo actually, but i will review everthing again now, thanks very much :wink:

actually this index that i posted here is not the one that i’m using now, my bad, this is:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <link rel="stylesheet" href="main.css">

    <title>CryptoFans</title>

</head>

<body class="bg-dark">

    <nav class="navbar navbar-expand-lg navbar-dark bg-transparent border-bottom border-light">

        <a class="navbar-brand btn btn-outline-moralis"  href="#">CryptoFans</a>

        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">

          <span class="navbar-toggler-icon"></span>

        </button>

        <div class="collapse navbar-collapse" id="navbarNav">

            <form class="mx-2 d-inline flex-md-fill">

                <input type="search" class="bg-transparent border-light form-control text-light mr-sm-2 rounded-pill" placeholder="Search by item or creator">

            </form>

          <ul class="navbar-nav mr-auto">

            <li class="nav-item">

              <a class="nav-link" id="btnMyItems" href="#">My items</a>

            </li>

          </ul>

          <div class="d-flex">

            <button class="btn btn-primary rounded-pill my-2 my-sm-0 mr-md-2" id="btnOpenCreateItem">Create</button>

            <button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0 " id="btnConnect">Connect wallet</button>

            <button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0" id="btnUserInfo">Profile</button>

          

        </div>

        </div>

      </nav>

    <div class="container">

        <div class="row row-cols-1 row-cols-md-4 mt-5" id="itemsForSale">

        </div>

    </div>

  

    <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 width="30" height="30" class="d-inline-block align-top rounded-circle" src="" alt="">

                <span></span>

            </nav>

         

            <img src="..." class="card-img-top" alt="...">

            <div class="card-body d-flex align-items-end">

                <div class="w-100">

                    <h5 class="card-title"></h5>

                    <p class="card-text"></p>

                    <button class="btn btn-primary btn-block"></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 d-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">Put for sale</button>

                        </div>

                      </div>

                </div>

        

            </div>

          </div>

    </div>

    <!-- Modal -->

    <div class="modal fade" id="userInfo" tabindex="-1">

        <div class="modal-dialog">

        <div class="modal-content bg-dark text-light">

            <div class="modal-header">

            <h5 class="modal-title" >User Profile</h5>

            <button type="button" class="close" data-dismiss="modal" aria-label="Close">

                <span aria-hidden="true">&times;</span>

            </button>

            </div>

            <div class="modal-body">

                <div class="form-group">

                    <label for="txtUsername">Username</label>

                    <input type="text" class="form-control" id="txtUsername" required placeholder="Enter username">

                </div>

                <div class="form-group">

                    <label for="txtEmail">Email address</label>

                    <input type="email" class="form-control" id="txtEmail" aria-describedby="emailHelp" placeholder="Enter email">

                    <small id="emailHelp" class="form-text text-muted">Optional</small>

                </div>

        

                <img width="50" height="50" src="" id="imgAvatar" alt="">

                <div class="form-group">

                    <label for="fileAvatar">Select Avatar</label>

                    <input type="file" class="form-control-file" id="fileAvatar">

                </div>

            </div>

            <div class="modal-footer">

            <button type="button" id="btnLogout" class="btn btn-secondary" data-dismiss="modal">Log out</button>

            <button type="button" id="btnCloseUserInfo" class="btn btn-secondary" data-dismiss="modal">Close</button>

            <button type="button" id="btnSaveUserInfo" class="btn btn-primary">Save</button>

            </div>

        </div>

        </div>

    </div>

        <!-- Modal -->

        <div class="modal fade" id="createItem" tabindex="-1">

            <div class="modal-dialog">

            <div class="modal-content bg-dark text-light">

                <div class="modal-header">

                <h5 class="modal-title" >Create Item</h5>

                <button type="button" class="close" data-dismiss="modal" aria-label="Close">

                    <span aria-hidden="true">&times;</span>

                </button>

                </div>

                <div class="modal-body">

    

                    <div class="form-group">

                        <label for="txtUsername">Name</label>

                        <input type="text" class="form-control" id="txtCreateItemName" required placeholder="Enter name">

                    </div>

    

                    <div class="form-group">

                        <label for="txtCreateItemDescription">Description</label>

                        <textarea class="form-control" id="txtCreateItemDescription"  cols="30" rows="5" placeholder="Enter description"></textarea>

                    </div>

                    <div class="form-group">

                        <label for="txtUsername">Price</label>

                        <input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required class="form-control">

                    </div>

                    <div class="form-group">

                        <label for="selectCreateItemStatus">Status</label>

                        <select class="form-control" id="selectCreateItemStatus">        

                            <option value="0">Not for sale</option>

                            <option value="1">Instant buy</option>

                            <option value="2">Accept Offers</option>

                        </select>

                    </div>

                    <div class="form-group">

                        <label for="fileCreateItemFile">Select file</label>

                        <input type="file" class="form-control-file" id="fileCreateItemFile">

                    </div>

                </div>

                <div class="modal-footer">

                <button type="button" id="btnCloseCreateItem" class="btn btn-secondary" data-dismiss="modal">Close</button>

                <button type="button" id="btnCreateItem" class="btn btn-primary">Create!</button>

                </div>

            </div>

            </div>

        </div>

        

        <!-- Modal -->

        <div class="modal fade" id="userItems" tabindex="-1">

            <div class="modal-dialog modal-xl">

            <div class="modal-content bg-dark text-light">

                <div class="modal-header">

                <h5 class="modal-title" >My Items</h5>

                <button type="button" class="close" data-dismiss="modal" aria-label="Close">

                    <span aria-hidden="true">&times;</span>

                </button>

                </div>

                <div class="modal-body row row-cols-1 row-cols-md-4 mt-5" id="userItemsList">

    

                </div>

                <div class="modal-footer">

                    <button type="button" id="btnCloseUserItems" class="btn btn-secondary" data-dismiss="modal">Close</button>

                </div>

            </div>

            </div>

        </div>

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>

    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>

    <script src="abi.js"></script>

    <script src="main.js"></script>

</body>

</html>