Search code examples
javascriptjqueryif-statementstategiphy-api

Javascript state change reverting


I have a simple jQuery app to display images from Giphy based on an ajax call, and toggle animate/stop them on mouseclick by toggling the src URL and data-state attributes.

I'm also displaying a different set of images based on user input.

I have a bug where it only animates gifs displayed after the first ajax call. It doesn't animate gifs displayed by subsequent calls. console-logging for each condition makes me think that for the latter it changes the state and changes it back, but I can't wrap my head around why.

Screencap: https://screencast.com/t/uZCzH6E6hZ8n

$('document').ready(function () {
    //array with topics
    var topics = [
        "Ronaldinho",
        "Zidan",
        "Messi",
        "Maradona",
        "Pele"
    ]

    //function loop to display all topics in buttons
    function displayTopics() {
        for (var i = 0; i < topics.length; i++) {
            $('#buttons').append('<div class="btn btn-info get-giphy" data-attribute=' + topics[i] +
                '>' + topics[i] +
                '</div>');
        }
    }

    //call function to display all the topic buttons
    displayTopics();

    //on clicking button
    $('#buttons').on('click', '.get-giphy', function () {

        $('#gifs-appear-here').empty();
        //set topic to the clicked button's data-attribute
        var topic = $(this).attr('data-attribute');

        //set query URL to picked topic
        var queryURL = "https://api.giphy.com/v1/gifs/search?q=" + topic +
            "&api_key=O2X0wRMnWEjylyUypx1F5UVxCz5Jp8kr&limit=10";

        //ajax call to Giphy API
        $.ajax({
            url: queryURL,
            method: 'GET'
        }).then(function (response) {
            console.log(response);
            // Storing an array of results in the results variable
            var results = response.data;

            // Looping over every result item
            for (var i = 0; i < results.length; i++) {

                // Only taking action if the photo has an appropriate rating
                if (results[i].rating !== "r") {
                    // Creating a div with the class "item"
                    var gifDiv = $("<div class='item'>");

                    // Storing the result item's rating
                    var rating = results[i].rating;

                    // Creating a paragraph tag with the result item's rating
                    var p = $("<p>").text("Rating: " + rating);

                    // Creating an image tag
                    var topicImage = $("<img>");

                    // Giving the image tag necessary attributes
                    topicImage.attr({
                        "class": "topicImage",
                        "src": results[i].images.fixed_height_still.url,
                        "data-state": "still",
                        "data-still": results[i].images.fixed_height_still.url,
                        "data-animate": results[i].images.fixed_height.url
                    });

                    // Appending the paragraph and personImage we created to the "gifDiv" div we created
                    gifDiv.append(topicImage);
                    gifDiv.append(p);

                    // Prepending the gifDiv to the "#gifs-appear-here" div in the HTML
                    $("#gifs-appear-here").prepend(gifDiv);
                }
            }
        });
        $('#gifs-appear-here').on('click', '.topicImage', function () {
            
            var state = $(this).attr("data-state");
            if (state === "still") {
                $(this).attr("src", $(this).attr("data-animate"));
                $(this).attr("data-state", "animate");
                console.log('still --> animate');
            } else if (state === "animate") {
                $(this).attr("src", $(this).attr("data-still"));
                $(this).attr("data-state", "still");
                console.log('animate --> still');
            }
            else {
                return false;
            }
        });

    });

    //add buttons
    $('button[type="submit"]').click(function () {
        var inputValue = $('.form-control').val().trim();
        //don't add buttons if they're already in topics array
        if (topics.includes(inputValue)) {
            $('.modal').modal('show');
            $('.modal-body').html('You already have a button for <b>' + inputValue +
                '</b>. Use it or add something else');
            setTimeout(function () {
                $('.modal').modal('hide');
            }, 4000);
        //add buttons if they aren't in the topics array
        } else {
            topics.push(inputValue);
            $('#buttons').empty();
            displayTopics();
        }
    });

    //get form input on pressing "enter key"
    $('.form-control').keypress(function (e) {
        if (e.which == 13) { //Enter key pressed
            $('button[type="submit"]').click(); //Trigger search button click event
        }
    });
});
.row {
    margin-top: 30px;
}

.col {
    background-color: #eee;
    padding: 15px;
    border-radius: 10px;
}

.get-giphy {
    margin: 0 15px 15px 0;
}

.topicImage {
    max-width: 100%;
}

@media all and (min-width: 768px) {
#buttons {
    border-right: 15px solid #fff;
}

#formWrap {
    border-left: 15px solid #fff;
}
}

@media all and (max-width: 768px) {
    #buttons {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
    }
    #formWrap {
        border-top-left-radius: 0;
        border-top-right-radius: 0;
    }
}

@media all and (max-width: 575px) {
    .row {
        margin-left: 0;
        margin-right: 0;
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
        crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
        crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
        crossorigin="anonymous"></script>
    <script src="main.js"></script>
    <title>Homework 6</title>
</head>

<body>

    <div class="container">
        <div class="row">
            <div class="col col-12">
                <h1>Who's your favorite Futbol star?</h1>
            </div>
        </div>
        <div class="row">
            <div id="buttons" class="col col-12 col-md-6 col-lg-6">Click a button!
                <br>
                <br>
            </div>
            <div id="formWrap" class="col col-12 col-md-6 col-lg-6">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="You can also add more buttons!">
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </div>
        </div>
        <div class="row">
            <div id="gifs-appear-here" class="col col-12">
                Your gifs will appear here
            </div>
        </div>
    </div>
    <!-- Modal -->
    <div class="modal fade" id="answerModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="exampleModalLongTitle">Not so fast!</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">

                </div>
            </div>
        </div>
    </div>


    <script type="text/javascript">
    </script>
</body>

</html>


Solution

  • As it stands, ('#gifs-appear-here').on('click', '.topicImage', ...) is executed inside the buttons' onclick handler, causing that delegated click handler to accumulate every time one of the buttons is clicked.

    To fix, simply move ('#gifs-appear-here').on('click', '.topicImage', ...) out of the buttons' onclick handler.

    Here it is (significantly tidied) :

    $('document').ready(function () {
        var topics = [
            "Ronaldinho",
            "Zidan",
            "Messi",
            "Maradona",
            "Pele"
        ];
        function displayTopics() {
            for (var i = 0; i < topics.length; i++) {
                $('#buttons').append('<div class="btn btn-info get-giphy" data-attribute=' + topics[i] + '>' + topics[i] + '</div>');
            }
        }
        displayTopics();
        $('#buttons').on('click', '.get-giphy', function () {
            $('#gifs-appear-here').empty();
            var queryURL = "https://api.giphy.com/v1/gifs/search?q=" + $(this).data('attribute') + "&api_key=O2X0wRMnWEjylyUypx1F5UVxCz5Jp8kr&limit=10";
            $.ajax({
                'url': queryURL,
                'method': 'GET'
            }).then(function (response) {
                var results = response.data;
                for (var i = 0; i < results.length; i++) {
                    if (results[i].rating !== "r") {
                        var gifDiv = $("<div class='item'/>").prependTo("#gifs-appear-here");
                        $("<img class='topicImage'/>").attr({
                            'src': results[i].images.fixed_height_still.url
                        }).data({
                            'state': 'still',
                            'images': results[i].images
                        }).appendTo(gifDiv);
                        $('<p/>').text("Rating: " + results[i].rating).appendTo(gifDiv);
                    }
                }
            });
        });
    
        $('#gifs-appear-here').on('click', '.topicImage', function () {
            var data = $(this).data();
            if (data.state === 'still') {
                $(this).attr('src', data.images.fixed_height.url);
                data.state = 'animate';
            } else {
                $(this).attr('src', data.images.fixed_height_still.url);
                data.state = 'still';
            }
        });
    
        //add buttons
        $('button[type="submit"]').click(function () {
            var inputValue = $('.form-control').val().trim();
            //don't add buttons if they're already in topics array
            if (topics.includes(inputValue)) {
                $('.modal').modal('show');
                $('.modal-body').html('You already have a button for <b>' + inputValue + '</b>. Use it or add something else');
                setTimeout(function () {
                    $('.modal').modal('hide');
                }, 4000);
            //add buttons if they aren't in the topics array
            } else {
                topics.push(inputValue);
                $('#buttons').empty();
                displayTopics();
            }
        });
    
        //get form input on pressing "enter key"
        $('.form-control').keypress(function (e) {
            if (e.which == 13) { //Enter key pressed
                $('button[type="submit"]').click(); //Trigger search button click event
            }
        });
    });
    .row {
        margin-top: 30px;
    }
    
    .col {
        background-color: #eee;
        padding: 15px;
        border-radius: 10px;
    }
    
    .get-giphy {
        margin: 0 15px 15px 0;
    }
    
    .topicImage {
        max-width: 100%;
    }
    
    @media all and (min-width: 768px) {
    #buttons {
        border-right: 15px solid #fff;
    }
    
    #formWrap {
        border-left: 15px solid #fff;
    }
    }
    
    @media all and (max-width: 768px) {
        #buttons {
            border-bottom-left-radius: 0;
            border-bottom-right-radius: 0;
        }
        #formWrap {
            border-top-left-radius: 0;
            border-top-right-radius: 0;
        }
    }
    
    @media all and (max-width: 575px) {
        .row {
            margin-left: 0;
            margin-right: 0;
        }
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
            crossorigin="anonymous">
        <link rel="stylesheet" href="style.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
            crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
            crossorigin="anonymous"></script>
        <script src="main.js"></script>
        <title>Homework 6</title>
    </head>
    
    <body>
    
        <div class="container">
            <div class="row">
                <div class="col col-12">
                    <h1>Who's your favorite Futbol star?</h1>
                </div>
            </div>
            <div class="row">
                <div id="buttons" class="col col-12 col-md-6 col-lg-6">Click a button!
                    <br>
                    <br>
                </div>
                <div id="formWrap" class="col col-12 col-md-6 col-lg-6">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="You can also add more buttons!">
                    </div>
                    <button type="submit" class="btn btn-primary">Submit</button>
                </div>
            </div>
            <div class="row">
                <div id="gifs-appear-here" class="col col-12">
                    Your gifs will appear here
                </div>
            </div>
        </div>
        <!-- Modal -->
        <div class="modal fade" id="answerModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="exampleModalLongTitle">Not so fast!</h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
    
                    </div>
                </div>
            </div>
        </div>
    
    
        <script type="text/javascript">
        </script>
    </body>
    
    </html>