0

I want to iterate over three elements in my HTML, changing the attributes in each section, one section at a atime. I thought I'd get a NodeList with querySelectorAll and then use a counter with the NodeList to iterate. It works in the first section only, and returns this error message:

Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute

I feel like this should be simpler, is there an easier way to iterate over the sections that bypasses the cookies issue?

const button = document.querySelector('button');

generateRandom = () => {
  return Math.floor(Math.random() * 826);
}

getCharacters = () => {
  var sections = document.querySelectorAll('section');

  for (var i = 0; i < 4; i++;) {
    let randomNumber = generateRandom();

    return fetch(`https://rickandmortyapi.com/api/character/${randomNumber}`, {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        "Content-type": 'application/json'
      }
    }).then((response) => response.json()).then((data) => {
      let section = sections[i];
      let image = section.querySelector('img');
      let characterName = section.querySelector('#name');
      let especie = section.querySelector('#species');
      let state = section.querySelector('#status');
      image.src = data.image;
      image.alt = data.name;
      characterName.innerHTML = data.name
      species.innerHTML = data.species;
      state.innerHTML = data.status;
    })
  }
}

button.onclick = getCharacters;
<main>
  <section>
    <img alt="Smiling Rick" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTfO2QcnGNdEZnWgjmwCDTUN1okIqAlXt5UkwZEl7qui4Poc-vO">
    <ul id="config-container">
      <li>Name:
        <p id="name"></p>
      </li>
      <li>Species:
        <p id="species"></p>
      </li>
      <li>Status:
        <p id="status"></p>
      </li>
    </ul>
  </section>
  <section>
    <img alt="Rick and Morty logo" src="https://www.baconfrito.com/wp-content/uploads/2017/10/rick-morty-title.jpg">
    <ul id="config-container">
      <li>Name:
        <p id="name"></p>
      </li>
      <li>Species:
        <p id="species"></p>
      </li>
      <li>Status:
        <p id="status"></p>
      </li>
    </ul>
    <button>Click to see more characters</button>
  </section>
  <section>
    <img alt="Smiling Morty" src="https://static.wikia.nocookie.net/rickandmorty/images/e/ee/Morty501.png/revision/latest/top-crop/width/360/height/360?cb=20210827150137">
    <ul id="config-container">
      <li>Name:
        <p id="name"></p>
      </li>
      <li>Species:
        <p id="species"></p>
      </li>
      <li>Status:
        <p id="status"></p>
      </li>
    </ul>
  </section>
</main>
mplungjan
  • 169,008
  • 28
  • 173
  • 236

2 Answers2

1
  1. You have a semicolon too many in the if
  2. You have duplicate IDs - use class
  3. Misspelled species

I added a counter and a reset to simplify and to allow the fetch to run with 100 milliseconds delay

Note the window.addEventListener which waits for the page to load before running the click script

const generateRandom = () => {
  return Math.floor(Math.random() * 826);
}
const sections = document.querySelectorAll('section');
let cnt = 0;
let tId;

const getCharacters = () => {
  if (cnt == sections.length) return;
  let randomNumber = generateRandom();

  fetch(`https://rickandmortyapi.com/api/character/${randomNumber}`, {
    method: 'GET',
    headers: {
      Accept: 'application/json',
      "Content-type": 'application/json'
    }
  }).then((response) => response.json()).then((data) => {
    let section = sections[cnt];
    let image = section.querySelector('img');
    let characterName = section.querySelector('.name');
    let species = section.querySelector('.species');
    let state = section.querySelector('.status');
    image.src = data.image;
    image.alt = data.name;
    characterName.innerHTML = data.name
    species.innerHTML = data.species;
    state.innerHTML = data.status;
    cnt++;
    tId = setTimeout(getCharacters, 100); // fetch again in 100 milliseconds
  })
}

window.addEventListener("load", function() {
  const button = document.querySelector('button');


  button.addEventListener("click", function() {
    cnt = 0; // start from 0
    clearTimeout(tId); // stop any running process
    getCharacters();
  })
  getCharacters(); // initialise
})
<main>
  <button>Click to see more characters</button>

  <section>
    <img alt="Smiling Rick" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTfO2QcnGNdEZnWgjmwCDTUN1okIqAlXt5UkwZEl7qui4Poc-vO">
    <ul class="config-container">
      <li>Name:
        <p class="name"></p>
      </li>
      <li>Species:
        <p class="species"></p>
      </li>
      <li>Status:
        <p class="status"></p>
      </li>
    </ul>
  </section>
  <section>
    <img alt="Smiling Rick" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTfO2QcnGNdEZnWgjmwCDTUN1okIqAlXt5UkwZEl7qui4Poc-vO">
    <ul class="config-container">
      <li>Name:
        <p class="name"></p>
      </li>
      <li>Species:
        <p class="species"></p>
      </li>
      <li>Status:
        <p class="status"></p>
      </li>
    </ul>
  </section>
</main>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Thanks for pointing out 1, 2 and 3. Fixed those. I still get only the first character and not the other two. – Miss Amaral Jan 15 '22 at 07:56
  • Fixed - added a counter to the fetch – mplungjan Jan 15 '22 at 07:59
  • Ty! Now I'm getting this error: "Uncaught ReferenceError: getCharacters is not defined at HTMLButtonElement. (script.js:40:9)" Also, I think I should have made it clear that I intended the button to change all three sections with one click, and keep doing it on every click. Should I edit the question to add this? Thanks for your patience. – Miss Amaral Jan 15 '22 at 08:36
  • As you can see the script I posted does that exactly. Perhaps you did not paste it correctly in your page? I need to step out for an hour – mplungjan Jan 15 '22 at 08:37
  • I need a break, too. Will come back to it later, tks a lot! – Miss Amaral Jan 15 '22 at 08:46
  • Please see the bottom of the script now. I moved and wrapped the click in a load handler so it assigns the listener when the page has loaded – mplungjan Jan 15 '22 at 10:08
  • 1
    Solved! Thanks a bunch! – Miss Amaral Jan 15 '22 at 10:40
0

@mplungjan clearly answered the question in all points. Nothing to add there.

However, I had some time to spare and came up with this alternative solution that should also work:

It delivers a random non-repeating sequence of all (numc) characters and can be extended to an arbitrary number of display sections (nums).

One further remark with respect to timing: If you place this script in a <script> tag under your <body> it will start running, as soon as the DOM is loaded.

function shfl(a){ // Durstenfeld shuffle
 for(let j,i=a.length;i>1;){
  j=Math.floor(Math.random()*i--);
  if (i!=j) [a[i],a[j]]=[a[j],a[i]]
 }
 return a
}
const numc=826,nums=2; // 826 characters, 2 sections

// random sequence of all characters:
const seq=shfl([...new Array(numc)].map((_,i)=>i));

// Create the `nums` section elements and store 
// them in an array of objects, together with 
// their IMG and P child nodes:
const sects=[document.querySelector("section")];
for(let i=1; i<nums; i++)
 sects[i-1].after(sects[i]=sects[0].cloneNode(true));
sects.forEach(s=>{
 ["img","p"].forEach(e=>s[e]=s.querySelectorAll(e));
});
sects.i=0;

// define button-click event:
(document.querySelector('button').onclick=ev=>{ 
 sects.forEach(s=>{
  fetch(`https://rickandmortyapi.com/api/character/${seq[sects.i++%numc]}`).then(t=>t.json()).then(j=>{
   s.img[0].title=j.name;
   s.img[0].src=j.image;
   s.p.forEach(e=>e.textContent=j[e.className]);
  })
 })
})() // make it an IIFE, thereby running immediately at start-up
<main>
  <button>Click to see more characters</button>
  <section>
    <img>
    <ul class="config-container">
      <li>Name:
        <p class="name">name</p>
      </li>
      <li>Species:
        <p class="species">species</p>
      </li>
      <li>Status:
        <p class="status">status</p>
      </li>
    </ul>
  </section>
</main>
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43