-2
function getResults(querySearch) {
  api.pageNum += 1;
  refs.list.innerHTML = '';
  const imgBlock = fetch(
    `https://pixabay.com/api/?image_type=photo&orientation=horizontal&q=${querySearch}&page=${api.pageNum}&per_page=12&key=${api.key}`,
  )
    .then(data => {
      return data.json();
    })
    .then(pic => pic.hits)
    .map(item => template(item).join(''));
  refs.list.insertAdjacentHTML('beforeend', imgBlock);
}

I'd like to use a handlebars template to each item mapped, but for some reason, I keep getting:

"fetch(...).then(...).then(...).map is not a function"

Here's a full code:

import './styles.css';
import template from './templates/template.hbs';

const api = {
  key: '#',
  querySearch: '',
  pageNum: 1,
};

const refs = {
  list: document.querySelector('.gallery'),
  form: document.querySelector('#search-form'),
  input: document.querySelector('input'),
};

refs.input.addEventListener('input', catchInput);

function catchInput(event) {
  console.log(event.target.value);
  getResults(refs.input.value);
  console.log(refs.input.value);
}

function getResults(querySearch) {
  api.pageNum += 1;
  refs.list.innerHTML = '';
  const imgBlock = fetch(
    `https://pixabay.com/api/?image_type=photo&orientation=horizontal&q=${querySearch}&page=${api.pageNum}&per_page=12&key=${api.key}`,
  )
    .then(data => {
      return data.json();
    })
    .then(pic => pic.hits)
    .map(item => template(item).join(''));
  refs.list.insertAdjacentHTML('beforeend', imgBlock);
}

HANDLEBARS

    <div class="photo-card">
    <img src="{{webformatURL}}" alt="{{webformatURL}}" />
    <div class="stats">
        <p class="stats-item">
            <i class="material-icons">thumb_up</i>
            {{likes}}
        </p>
        <p class="stats-item">
            <i class="material-icons">visibility</i>
            {{visibility}}
        </p>
        <p class="stats-item">
            <i class="material-icons">comment</i>
            {{comments}}
        </p>
        <p class="stats-item">
            <i class="material-icons">cloud_download</i>
            {{downloads}}
        </p>
    </div>
</div>
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
ElMuchacho
  • 300
  • 1
  • 12
  • 5
    Tip: You can't just slap `map()` on the end of a `then()` chain. – tadman Jun 20 '20 at 23:37
  • Can you rewrite this as an `async` function? That'd make the code a lot less convoluted. – tadman Jun 20 '20 at 23:37
  • It's usually better to define functions like `catchInput` before they're referenced in other code, as in the `addEventListener` call. That could be an error. – tadman Jun 20 '20 at 23:46

1 Answers1

2

There's a lot of things you can do with Promises, but map() is not one. You can easily rewrite this, though:

function getResults(querySearch) {
  api.pageNum += 1;
  refs.list.innerHTML = '';

  const imgBlock = fetch(
    `https://pixabay.com/api/?image_type=photo&orientation=horizontal&q=${querySearch}&page=${api.pageNum}&per_page=12&key=${api.key}`,
  )
    .then(data => data.json())
    .then(json => {
      let imgBlock = json.hits.map(item => template(item).join(''));

      refs.list.insertAdjacentHTML('beforeend', imgBlock);
    })
}

Remember imgBlock is a Promise and is of absolutely no use to insertAdjacentHTML until it's resolved. You were executing that code prematurely, it must be put into the then callback.

If you can use async, this code is really simple and a lot easier to follow:

async function getResults(querySearch) {
  api.pageNum += 1;
  refs.list.innerHTML = '';

  const data = await fetch(
    `https://pixabay.com/api/?image_type=photo&orientation=horizontal&q=${querySearch}&page=${api.pageNum}&per_page=12&key=${api.key}`,
  );

  let json = await data.json();
  let imgBlock = json.hits.map(item => template(item).join(''));

  refs.list.insertAdjacentHTML('beforeend', imgBlock);
}

Anything you can do to reduce nesting in JavaScript often turns out to be a huge win, so I'd recommend this approach.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • There's might be a chance I have made a mistake somewhere else, cause after your help with refactoring, I still looking for a way out of the problem...could you please check my code? i have updated a question – ElMuchacho Jun 20 '20 at 23:44
  • 1
    This is the way out of that problem. There's two mistakes in your code: Using `map()` on a Promise and using a value before the promise has been resolved. – tadman Jun 20 '20 at 23:45
  • "Cannot read property 'map' of undefined at eval (index.js?2615:29)" – ElMuchacho Jun 20 '20 at 23:48
  • that's what I am getting, sir – ElMuchacho Jun 20 '20 at 23:48
  • `data.json()` must be `await`ed too. ([docs](https://developer.mozilla.org/en-US/docs/Web/API/Body/json)) – CherryDT Jun 20 '20 at 23:49
  • @CherryDT They should both be up-to-date now. Thanks for pointing that out. – tadman Jun 20 '20 at 23:53
  • I am still getting errors for some reason, what else can we do? – ElMuchacho Jun 20 '20 at 23:56
  • 1
    "getting errors" doesn't help us. You need to be more specific. You may need to step through this in a debugger to see what's wrong. – tadman Jun 20 '20 at 23:56
  • alright, the purpose is to fetch the data from the rest API and apply a handlebars template at each object of the array (.hits) - what should i change in my code for that? – ElMuchacho Jun 21 '20 at 00:19