API exercise: dropdown menu showing no coins

Hello. For the API exercise, I have two questions:

Question 1:
the dropdown menu is not having any coins, which can be shown in the photo below. Can someone tell me what the problem is please?

Below are my codes:

<!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>Top 10 coins exchange</title>
    <link rel="stylesheet" href="./APIex2.css">
</head>
<body>
  <form action="#" method="POST" class="exchange-form">
    <div class="form-row">  
        <label>
        From:
            <select name="from-token"></select>>
        </label>
    </div>
    <div class="form-row">
        <label>
        To: 
            <select name="to-token"></select>>
        </label>
    </div>
    <div class="form-row">
        <button type="submit" class="js-submit-quote">Get Quote</button>
    </div>
  </form>
  <script src="./APIex2.js"></script>

    <p>conversion rate: </p>
    <p>estimated gas: </p>
</body>
</html>
async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();

    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 10)
            .map(token => token.symbol);
}

async function getTickerData(tickerList) {
    const response = await fetch('https://api.1inch.exchange/v3.0/56/tokens');
    const tokens = await response.json();
    const tokenList = Object.values(tokens.tokens);

    return tokenList.filter(token => tickerList.includes(token.symbol));
}

function renderForm(tokens) {
    const options = tokens.map(token =>
        `<option value="${tokens.decimals}-${token.address}">${token.name} (${token.symbol})</option>`);
    document.querySelector('[name=from-token]').innerHTML = options;
    document.querySelector('[name=to-token]').innerHTML = options;
    document.querySelector('.js-submit-quote').removeAttribute('disabled');
}

async function formSubmitted(event) {
    event.preventDefault();
    const fromToken = document.querySelector('[name-from-token]').value;
    const toToken = document.querySelector('[name-to-token]').value;
    const [fromDecimals, fromAddress] = fromToken.split('-');
    const [toDecimals, toAddress] = toToken.split('-');
    const fromUnit = 10 ** fromDecimals;
    const decimalRatio = 10 ** (fromDecimals - toDecimals);

    const url = `https://api.1inch.io/v4.0/56/quote?fromTokenAddress=${fromAddress}&toTokenAddress=${toAddress}&amount=10000000000000000`

    try {
        const response = await fetch(url);
        const quote = await response.json();
        const exchange_rate = Number(quote.toTokenAmount) / Number(quote.fromTokenAmount) * decimalRatio;
        document.querySelector('.js-quote-container').innerHTML = 
            <p>1 ${quote.fromToken.symbol} = ${exchange_rate} ${quote.toToken.symbol}</p>
            <p>Gas fee: ${quote.estimatedGas}</p>
        ;
    } catch(e) {
        document.querySelector('.js-quote-container').innerHTML = `The conversion didn't succeed.`;
    }
}

document
    .querySelector('.js-submit-quote')
    .addEventListener('click', formSubmitted);

getTop10Tokens()
    .then(getTickerData)
    .then(renderForm);
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background-color: antiquewhite; 
}

.exchange-form {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-left: 4rem;
}

.form-row {
    margin: 0.25rem;
}

Question 2:

Also, can someone explain the lines:

const fromUnit = 10 ** fromDecimals;
const decimalRatio = 10 ** (fromDecimals - toDecimals);

and

const exchange_rate = Number(quote.toTokenAmount) / Number(quote.fromTokenAmount) * decimalRatio;

Does the latter code means exchange rate is equals to (amount of To token) / (amount of From token) X Decimal Ratio? I don’t understand why this is the equation of exchange rate. Isn’t the exchange rate equals to (price of From token) / (price of To token)? Is this something I should stress about?

@thecil Are you able to help pleaaaase?

That should be inside curvy quotes ``.

document.querySelector('.js-quote-container').innerHTML = `
            <p>1 ${quote.fromToken.symbol} = ${exchange_rate} ${quote.toToken.symbol}</p>
            <p>Gas fee: ${quote.estimatedGas}</p>`

Carlos Z

1 Like

Hi Carlos. Thanks a lot for the reply! My dropdown menus now contain choices of coins. However, there are still some problems and it’s quite frustrating.

When I click “Get quote”, there’s no response. The console said “Uncaught (in promise) TypeError: Cannot read properties of null (reading ‘value’)
at HTMLButtonElement.formSubmitted (APIex2.js:28:66)” as below:

Also, the photo below shows that “fromUnit” is grey out.

I have rewatched the videos but cannot find what’s the problem. Can you help me to spot the problems please? Also, can you review my entire code to see if there are any flaws that would prevent it from working please?

I would appreciate your help.

1 Like

Could you tell me on which lesson are you stuck? That will give me an idea of where the issue is :nerd_face:

Carlos Z

You have a little syntax error on those 2 constant, the query selector should be name=... but you misstype name-... :nerd_face:

Carlos Z

1 Like

Thanks for the reply! But it still have no response when I click “get quote” :slightly_frowning_face:
Can u see what are the other problems?

Here’s my code:

async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();

    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 10)
            .map(token => token.symbol);
}

async function getTickerData(tickerList) {
    const response = await fetch('https://api.1inch.exchange/v3.0/56/tokens');
    const tokens = await response.json();
    const tokenList = Object.values(tokens.tokens);

    return tokenList.filter(token => tickerList.includes(token.symbol));
}

function renderForm(tokens) {
    const options = tokens.map(token =>
        `<option value="${tokens.decimals}-${token.address}">${token.name} (${token.symbol})</option>`);
    document.querySelector('[name=from-token]').innerHTML = options;
    document.querySelector('[name=to-token]').innerHTML = options;
    document.querySelector('.js-submit-quote').removeAttribute('disabled');
}

async function formSubmitted(event) {
    event.preventDefault();
    const fromToken = document.querySelector('[name=from-token]').value;
    const toToken = document.querySelector('[name=to-token]').value;
    const [fromDecimals, fromAddress] = fromToken.split('-');
    const [toDecimals, toAddress] = toToken.split('-');
    const fromUnit = 10 ** fromDecimals;
    const decimalRatio = 10 ** (fromDecimals - toDecimals);

    const url = `https://api.1inch.io/v4.0/56/quote?fromTokenAddress=${fromAddress}&toTokenAddress=${toAddress}&amount=10000000000000000`

    try {
        const response = await fetch(url);
        const quote = await response.json();
        const exchange_rate = Number(quote.toTokenAmount) / Number(quote.fromTokenAmount) * decimalRatio;
        document.querySelector('.js-quote-container').innerHTML = `
            <p>1 ${quote.fromToken.symbol} = ${exchange_rate} ${quote.toToken.symbol}</p>
            <p>Gas fee: ${quote.estimatedGas}</p>
        `;
    } catch(e) {
        document.querySelector('.js-quote-container').innerHTML = `The conversion didn't succeed.`;
    }
}

document
    .querySelector('.js-submit-quote')
    .addEventListener('click', formSubmitted);

getTop10Tokens()
    .then(getTickerData)
    .then(renderForm);
<!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>Top 10 coins exchange</title>
    <link rel="stylesheet" href="./APIex2.css">
</head>
<body>
  <form action="#" method="POST" class="exchange-form">
    <div class="form-row">  
        <label>
        From:
            <select name="from-token"></select>>
        </label>
    </div>
    <div class="form-row">
        <label>
        To: 
            <select name="to-token"></select>>
        </label>
    </div>
    <div class="form-row">
        <button type="submit" class="js-submit-quote">Get Quote</button>
    </div>
  </form>
  <script src="./APIex2.js"></script>

</body>
</html>
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background-color: antiquewhite; 
}

.exchange-form {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-left: 4rem;
}

.form-row {
    margin: 0.25rem;
}
1 Like

It said "Uncaught (in promise) TypeError: Cannot set properties of null (setting ‘innerHTML’)
at HTMLButtonElement.formSubmitted (APIex2.js:46:65) " as below:

1 Like

You have to add the js-quote-container div at the end of the form tag in the html file.

<div class="js-quote-container"></div>

Carlos Z

Thanks a lot for the reply!! I am almost there. It has given me a quote. But the quote said “1 BNB = NaN USDT”. And console said “Failed to load resource: the server responded with a status of 400 ()” as attached in the photo below. What are other flaws in my code? I would appreciate your help!