Rarible clone NFT marketplace

Hey guys
I’ve been trying to sort out this 404 error and unexpected token < in json at position 0. I have done console.log in the getAndRenderItemData function and I can log out all the data for the NFT including the token.Uri and token.id. My issue is when it says its fetching the token.Uri and it converts the response into a JSON repsonse. It doesn’t convert into a JSON. The response I’m getting is a HTML. I need a solution to parsing JSON so my put for sale button will work aswell. It doesn’t work currently because it cant fetch the correct token.id for the NFT so it can’t approve it for sale. I’m really trying to move forward and I’m wondering if I’m missing something in my getRenderItemData function or I haven’t wrote it correctly.
I will continue with my trial and error.
Thanks in advance :slight_smile:


HTML

<!DOCTYPE html>

<html lang="en">

<head>

    <link rel="shortcut icon" href="">

    <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>Moraribles</title>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">

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

 

</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="#">Morarible</a>

          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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>

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

 </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 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">

          </div>

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

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

       <button class="btn btn-primary"></button>

     </div>

  </div>

</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="selectCreateItemStatus">Status</label>

        <select id="selectCreateItemStatus">        

            <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="itemsForSale"></div>

    <div id="itemTemplate">

      <img src="" alt="">

      <h5></h5>

      <p></p>

      <input type="number" min="1" step="1">

      <button>Put For Sale</button>

    </div>

    <div id="marketplaceItemTemplate">

      <img src="" alt="">

      <h6></h6>

      <img src="" alt="">

      <h5></h5>

      <p></p>

      <button class="btn btn-primary btn-block"></button>

    </div>

           

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

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

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

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

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

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

</body>

</html>

Javascript

const serverUrl = "https://vxnx9mu8hh9u.usemoralis.com:2053/server";

const appId = "z75nQcm3wcoe9xd9MK8c6Lye9akXiMw1QldhfvE6";

const TOKEN_CONTRACT_ADDRESS = "0x99495223da7dFE1A14d5224Bc90bad4a01F0e58A";

const MARKETPLACE_CONTRACT_ADDRESS = "0x5b71C0259d1cFa36DD71A2C308E5A6378db5977f";

Moralis.start({ serverUrl, appId });

init = async () => {

    hideElement(userItemsSection);

    hideElement(userInfo);

    hideElement(createItemForm);

    await Moralis.enableWeb3();

    web3 = new Web3(Moralis.provider);

    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);

    window.marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);

        initUser();

        loadUserItems();

        loadItems();

        const soldItemsQuery = new Moralis.Query('SoldItems');

        const soldItemsSubscription = await soldItemsQuery.subscribe();

        soldItemsSubscription.on('create', onItemSold);

   

        const itemsAddedQuery = new Moralis.Query('ItemsForSale');

        const itemsAddedQuerySubscription = await itemsAddedQuery.subscribe();

        itemsAddedQuerySubscription.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);

    }else{

        showElement(userConnectButton);

        hideElement(userProfileButton);

        hideElement(openCreateItemButton);

        hideElement(createItemForm);

        hideElement(openUserItemsButton);

    }

}

login = async () => {

    try {

        await Moralis.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 = "";

        }

        userNameField.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', userNameField.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();

}

loadUserItems = async () => {

    const params =  { token_address: TOKEN_CONTRACT_ADDRESS };

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

    ownedItems.forEach(item => {

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

        if (userItemListing) return;

        getAndRenderItemData(item, renderUserItem);

    });

}

loadItems = async () => {

    const params =  { token_address: TOKEN_CONTRACT_ADDRESS };

    const items = await Moralis.Cloud.run("getItems", params);

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

    });

}

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;

    }

    mintNFT = async (metadataUri) => {

        console.log("mintNFT :", ethereum.selectedAddress)

        const receipt = await tokenContract.methods.createItem(metadataUri).send({from: ethereum.selectedAddress});;

   

        console.log(receipt);

   

        return receipt.events.Transfer.returnValues.tokenId;

    }

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

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;

   

}}

buyItem = async (item) => {

    user = await Moralis.User.current();

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

    if(!user)

    {

        login();

        return;

    }

    await marketplaceContract.methods.buyItem(item.uid).send({from: user.get('ethAddress'), value: item.askingPrice});

}

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].disbaled = item.askingPrice > 0;

    userItem.getElementsByTagName("button")[0].disbaled = 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') });

    };

    userItems.id = `user-item-${item.tokenObjectId}`

    userItems.appendChild(userItem);

    console.log(userItems);

}

renderItem = (item) => {

    const itemsForSale = 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 = `Buy for ${item.askingPrice}`;

    itemForSale.getElementsByTagName("button")[0].onclick = ()  => buyItem(item);;

    itemForSale.id = `item-${item.uid}`;

    itemsForSale.appendChild(itemForSale);

}

getAndRenderItemData = (item, renderFunction) => {  

    console.log(item);

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

   

    console.log("ensureMarketplaceIsApproved",  userAddress);

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

    }

}

ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {

    console.log(tokenId);

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

    }

}

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

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

openUserItems = async () => {

    user = await Moralis.User.current();

    if (user){    

        showElement(userItemsSection);

    }else{

        login();

    }

}

//Navbar

const userConnectButton = document.getElementById("btnConnect");

userConnectButton.onclick = login;

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

userProfileButton.onclick = openUserInfo;

//Userinfo

const userInfo = document.getElementById("userInfo");

const userNameField = 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");

const openCreateItemButton = document.getElementById("btnOpenCreateItem");

openCreateItemButton.onclick = () => showElement(createItemForm);

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

Cloud function

Moralis.Cloud.define("getUserItems", async (request) => {
  const options = { address: request.params.token_address, chain: "ropsten" };
  const NFTowners = await Moralis.Web3API.token.getNFTOwners(options);
  const queryResults = NFTowners.result.filter(x => x.owner_of == request.user.attributes.accounts);
const results = [];
 for (let i = 0; i < queryResults.length; ++i) {
  results.push({
    "tokenObjectId": queryResults[i].id,
    "tokenid": queryResults[i].token_id,
    "tokenAddress": queryResults[i].token_address,
    "symbol": queryResults[i].symbol,
    "tokenUri": queryResults[i].token_uri,
  });
}
return results;
});
Moralis.Cloud.beforeSave("ItemsForSale", async (request) => {
const query = new Moralis.Query("EthNFTTransfers");
  query.equalTo("token_address", request.object.get('tokenAddress'));
  query.equalTo("token_id", request.object.get('tokenId'));
const object = await query.first();
if (object){
    const owner = object.attributes.owner_of;
    const userQuery = new Moralis.Query(Moralis.User);    
    userQuery.equalTo("accounts", owner);
    const userObject = await userQuery.first({useMasterKey:true});
    if (userObject){
        request.object.set('user', userObject);
    }
        request.object.set('token', object);
}
});
Moralis.Cloud.beforeSave("SoldItems", async (request) => {
const query = new Moralis.Query("ItemsForSale");
query.equalTo("uid", request.object.get('uid'));
const item = await query.first();
if (item){
  request.object.set('item', item);
  item.set('isSold', true);
  await item.save();
  const userQuery = new Moralis.Query(Moralis.User);
    userQuery.equalTo("accounts", request.object.get('buyer'));
  const userObject = await userQuery.first({useMasterKey:true});
  if (userObject){
      request.object.set('user', userObject);
  }
}
});    

 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", "symbol","token.owner_of","token.token.id", "user.avatar","user.username");
  
    const queryResults = await query.find({useMasterKey:true});
    const results = [];
  
    for (let i = 0; i < queryResults.length; ++i) {
  
      if (!queryResults[i].attributes.tokenId || !queryResults[i].attributes.user) continue;
  
       results.push({
        "uid": queryResults[i].attributes.uid,
        "tokenId": queryResults[i].attributes.tokenId,
        "tokenAddress": queryResults[i].attributes.tokenAddress,
        "askingPrice": queryResults[i].attributes.askingPrice,
  
        "symbol": queryResults[i].attributes.token.symbol,
        "tokenUri": queryResults[i].attributes.token.token_uri,
        "ownerOf": queryResults[i].attributes.token.owner_of,
        "tokenObjectId": queryResults[i].attributes.token.id,
        
        "sellerUsername": queryResults[i].attributes.user.username,
        "sellerAvatar": queryResults[i].attributes.user.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.tokenId,
    "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,
  };
});

Can you give an example of the token uri which is causing the error?
Is the error only happening when getAndRenderItemData function is called?

yes its only not working when the getAndRenderItemData function is called. I can console.log out the token.Uri and all other data from inside the getAndRenderItemData function. I just get the JSON error in the console pointing to the line of code that says fetch (item.tokenUri). everything in my Moralis database that should be there is there. I’m just not sure why I keep getting this error. I have been trying everything and looking for others that have had same problem but cant find anyone with this exact issue.
Cheers

try with the below code. It probably should throw the same error but you will be able to see the fetched data in the console, and we may get more details on the error.

fetch(item.tokenUri)
    .then(response => response.text())
    .then(data => {
        console.log(data);
        data = JSON.parse(data);
        item.name = data.name;
        item.description = data.description;
        item.image = data.image;
        renderFunction(item);
    })

And what does the function renderFunction(item) do? I don’t see the definition of this function here.

Hi John
I’ve just tried your piece of code. Your correct it gives the same error but I logged out the information in the screenshot below.
The render Function logged out the userItemListing data but I don’t think its needed so I got rid of it.

Did you add any console.log at line 407? It is returning a html.

Yes I can remove that console.log?

You can keep it if that is not the cause of any error.

Do you see any data that does not look like a JSON format and might be a cause of the error?

all of these undefined should be json but the response comes out as a HTML.

Is it possible for you to share your code on github, so i can test it from my end.