0

I would like to retrieve the class when I click on the link that contains -> class="prez_col-'+i +'" in the viewPoster function. I don't know if it's because of the html() function or the event that prevents me from retrieving the name of the class from the DOM when I click on

template += '<a href="#" id="prez_jaquetteDiv" class="prez_col-' + i + '"><p class="prez_title">' + data[i].title + '</p><img src="' + condJaq + '" class="prez_jaquette" /></a>';
    $("#prez_choiseJaq").html(template);

I tried to put onclick in the template variable:

template += '<a href="#" onclick="test()" id="prez_jaquetteDiv" class="prez_col-' + i + '"><p class="prez_title">' + data[i].title + '</p><img src="' + condJaq + '" class="prez_jaquette" /></a>';
    $("#prez_choiseJaq").html(template);

I have an error! when on one of the posters displays

File HTML

<div id="prez_rech" class="prez_rech">
                <label for="fname">Recherche du film :</label>
                <input type="text" placeholder="Entrez votre film ici" id="prez_input">
                <xf:button type="button" id="prez_btn">Rechercher</xf:button>
            </div>

            <div id="prez_choiseJaq"></div>
    <footer class="prez_footer"><a href="https://xenfrench.net">Created by Marilyn</a></footer>

    <script type="module" src="js/vendor/prez/prez.js"></script>

File getValue .js

import { array } from './params.js';

const key = array['key'];
const urlMovie = array['urlMovie'];
const noCover = array['noCover'];
const urlImg = array['urlImg'];
const urlJaq = array['urlJaq'];
var jaq = document.getElementById("prez_choiseJaq");
var input = document.getElementById("prez_input");
var myBtn = document.getElementById("prez_btn");
var rech = document.getElementById("prez_rech");
var jaqSelected = $("a.prez_col-" + i);
var data = [];
var inputRep;
var urlNoCover = urlImg + noCover;
var url = urlMovie + key;
var i;
var test = false;

input.addEventListener("keypress", function (event) {
    if (event.key === "Enter") {
        event.preventDefault();
        inputRep = input.value;
        getValue();
    }
});

myBtn.addEventListener("click", event => {
    event.preventDefault();
    inputRep = input.value;
    getValue();
});


jaqSelected.click(function() {
    alert(jaqSelected);
});


async function getValue() {
    console.log(inputRep);
    try {
        const response = await fetch(url + "&language=fr-FR&query=" + inputRep + "&page=1&include_adult=false");
        const responseData = await response.json();
        data = responseData?.results;
        console.log(data);
        if (!data.length) {
            alert("Le film que vous demandez n'est pas disponible !");
        } else {
            viewPoster();
        }
    } catch (error) {
        console.log(error);
    }
    return data;
};

function viewPoster() {
    test = false;
    if (data) {
        var template = "";
        jaq.style.display = "inline-grid";
        i = -1;
        do {
            i += 1;
            console.log(i);
            let condJaq;
            if (data[i].poster_path == null) {
                condJaq = urlNoCover;
            } else {
                condJaq = urlJaq + data[i].poster_path;
            };
            template += '<a href="#" id="prez_jaquetteDiv" class="prez_col-' + i + '"><p class="prez_title">' + data[i].title + '</p><img src="' + condJaq + '" class="prez_jaquette" /></a>';
            $("#prez_choiseJaq").html(template);
        } while (i < data.length);
    };
};

function selected(arg) {
    console.log(arg);
};

export { getValue };

File params.js

var array = {
    key: "exemple",
    urlMovie: 'https://api.themoviedb.org/3/search/movie?api_key=',
    urlSerie: 'https://api.themoviedb.org/3/search/tv?api_key=',
    urlImg: 'styles/prez/img/',
    urlJaq: "https://image.tmdb.org/t/p/w154",
    noCover: "no_cover.jpeg",
};

export { array };

File prez.js

import { array } from './params.js';
import { getValue } from './getValue.js';

do you have an idea ?

Thanks in advance.

marilyn
  • 71
  • 2
  • 11

2 Answers2

1

Your do {} while () loop condition is trying to loop one beyond your data array. The problem is how you set up and increment your iterator variable: i.

You set your iterator to i = -1; before the loop, then, first thing in the loop you increment it: i += 1;, and the while condition is set to stop looping when i is equal to the array length: while ( i < data.length ). If an array has one element, i must be value 1 to discontinue the loop. At the end of the first pass i is equal to 0. Even in the case of a single array element it is still less than the length of the array so the loop will loop again. One element, two loops. Two elements, three loops. Three elements, four loops, etc.

The easy fix is change:

while (i < data.length);

...to:

while (i < data.length - 1);

let data = ['a','b','c','d','e'];

// ALWAYS ONE TO MANY LOOPS
let i = -1;
do {
  i += 1;
  console.log(i, data[i]);
} while (i < data.length);

// EASY FIX
i = -1;
do {
  i += 1;
  console.log(i, data[i]);
} while (i < data.length - 1); // <-- reduce length by one


// BETTER YET
i = 0;
do {
  console.log(i, data[i]);
  i += 1; // <-- move iterator increment to end of loop
} while (i < data.length);

How to use an iterator variable to control a loop:

Regardless of what type of loop you use: for, while, do while, it makes more sense to me to use your loop iterator, when you need one, as such:

let data = [1,2,3,4,5,6];
let ii = 0;
do {
  console.log(ii, data[ii]);
  ii++;
} while ( ii < data.length );

Before the loop, set ii to 0. The loop starts, use ii as 0, then at the very end of the loop increment ii. Every element is accessed, and only accessed once.


Here's the function (simple fixed) where you're do {} while () loop is:

function viewPoster() {
    test = false;
    if (data) {
        var template = "";
        jaq.style.display = "inline-grid";
        i = -1;
        do {
            i += 1;
            console.log(i);
            let condJaq;
            if (data[i].poster_path == null) {
                condJaq = urlNoCover;
            } else {
                condJaq = urlJaq + data[i].poster_path;
            };
            template += '<a href="#" id="prez_jaquetteDiv" class="prez_col-' + i + '"><p class="prez_title">' + data[i].title + '</p><img src="' + condJaq + '" class="prez_jaquette" /></a>';
            $("#prez_choiseJaq").html(template);
        } while (i < data.length - 1);
    };
};
bloodyKnuckles
  • 11,551
  • 3
  • 29
  • 37
  • 2
    Or just use a `for` loop... Almost as if they were created just to loop a given number of iterations... – Heretic Monkey Jun 02 '22 at 23:27
  • 1
    @heretic-monkey Of course the thing about `do {} while ()` loop is it guarantees one loop, regardless of what you're looping. I agree, I don't think it's appropriate in this application. But the *primary* design flaw here is using the iterator in such a way it will ALWAYS try to loop one more than the length of the array. – bloodyKnuckles Jun 02 '22 at 23:30
  • thank you for your answers, I tried but the problem is that by putting the variable "i = 0" the loop starts at "1" so a part is missing, when increasing the variable "template" . it does not display all covers. and conversely if I put "(i < data.length - 1);" in the loop the problem persists, if my array has 20 elements I would only have 19. like @Tibrogargan I have to review everything :( lol. I condensed my code too much into one and the same function. – marilyn Jun 03 '22 at 09:21
  • 1
    'I tried but the problem is that by putting the variable "i = 0" the loop starts at "1"'... Start with `0` and don't increment your loop var `i` until the very end of the loop. – bloodyKnuckles Jun 03 '22 at 15:25
1

There are so many issues here it's difficult to explain why your code isn't working. The issue with the for loop is a candidate for the error you didn't share, but there others.

The primary problem is that you were not adding a click handler for your links.

I've converted your code from module based JS (because I believe that's difficult to do in a snippet), mocked the Movie API call and cleaned up the code to remove most unnecessary globals, leverage jQuery more, and fix the for loop.

var array = {
    key: "exemple",
    urlMovie: 'https://api.themoviedb.org/3/search/movie?api_key=',
    urlSerie: 'https://api.themoviedb.org/3/search/tv?api_key=',
    urlImg: 'styles/prez/img/',
    urlJaq: "https://image.tmdb.org/t/p/w154",
    noCover: "no_cover.jpeg",
};

function mock_fetch(url, rep) {
    const query = url + "&language=fr-FR&query=" + rep + "&page=1&include_adult=false"
    // response = await fetch(query);
    // return await reponse.json()
    return { results: [{ poster_path: "This is the poster path"
                       , title: rep
                       }
                      ,{ poster_path: "Some other path"
                       , title: "Some other movie"
                       }
                      ]
           }
}

var data; // this will hold whatever data retrieved by the last query to the movie API (may be null/undefined)

async function getValue(inputRep) {
    try {
        const responseData = mock_fetch(array.urlMovie + array.key, inputRep);
        data = responseData?.results;
        if (!data.length) {
            alert("Le film que vous demandez n'est pas disponible !");
        } else {
            viewPoster(data);
        }
    } catch (error) {
        console.error(error);
    }
    return data;
};

function viewPoster() {
    $("#prez_choiseJaq").css("display", "inline-grid");
    var template = "";
    data.forEach( (film, index) => {
        template += `<a href="#" id="prez_jaquetteDiv" class="prez_col" data-index=${index}><p class="prez_title">${film.title}</p><img src="${film.poster_path?(array.urlJaq + film.poster_path):array.urlImg+array.noCover}" class="prez_jaquette" /></a>`;
    })
    $("#prez_choiseJaq").html(template);
};

function selectMovie(event) {
    event.preventDefault();
    getValue($('#prez_input').val());
}

function doSomethingWithFilm(event) {
    let index = $(this).data('index');
    console.log(`The index you clicked was ${index}`)
    if (data && data[index]) {
      console.log(`The data for that index is ${JSON.stringify(data[index])}`)
    } else {
      console.log(`The data for that index is not available`)
    }
}

function init() {
    $('#prez_input').keypress(event => { event.key === "Enter" && selectMovie(event) });
    $('#prez_btn').on("click", selectMovie);
    // Add the click handler for the links as a delegate because the links do not exist at the time this code is executed
    $(document).on("click", ".prez_col", doSomethingWithFilm);
}

$(init)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</script>
</head>
<body>
<div id="prez_rech" class="prez_rech">
    <label for="fname">Recherche du film :</label>
    <input type="text" placeholder="Entrez votre film ici" id="prez_input">
    <xf:button type="button" id="prez_btn">Rechercher</xf:button>
</div>

<div id="prez_choiseJaq"></div>
</body>
</html>
Tibrogargan
  • 4,508
  • 3
  • 19
  • 38
  • thank you for your answer, I will test all that, I think you are right my code is badly built. I'll come back to you as soon as I've tried. – marilyn Jun 03 '22 at 09:26
  • So i tried, i'm working on xenforo 2 which has jquery 3.5.1 for info. So I encounter a problem in the "mock_fetch" function which returned a promise, I modified it to return json. Then in the function getValue the variable "responseData" registers a promise again so the variable "data=responseData?.results" is "undefined" **jsfiddle ->** [link](https://jsfiddle.net/marilyn91/zeryot6b/4/) – marilyn Jun 03 '22 at 18:13
  • You should create another question for the new issue. – Tibrogargan Jun 03 '22 at 19:32
  • my problem is still not solved, I couldn't check if I could intersect an element in the HTML generated by the loop. If it is really necessary to redo a new question I will do it. – marilyn Jun 04 '22 at 09:28
  • 1
    Your question was "I would like to retrieve the class when I click on the link". Since all the links are determined by the index into `data` all you really need is the index. That's what the answer you were given provides. I've modified the answer to make that clearer. – Tibrogargan Jun 05 '22 at 02:39
  • ok great thank you, it works with jquery 3.3.1 but not with 3.5.1 and I can't find why, I'll reapply. – marilyn Jun 05 '22 at 07:44
  • Here is the link for the jquery 3.5.1 problem I'm having. -> [link](https://stackoverflow.com/q/72506164/6736695) – marilyn Jun 05 '22 at 09:27