Trying to switch image states - from still to animate - using giphy API - javascript

So I'm in a bootcamp, bout to begin the 7th week. We have an API assignment, and I chose to use the Giphy API. Okay, I've made the ajax call, have the json object, am displaying gifs with a button click. Once the gifs load, you should be able to make image animate, then upon next click, the image becomes still again. the process should be able to repeat itself ad nauseam. I have it set up the way that makes sense; however, I cant seem to get the urls to change upon click the way it's currently written. I tried .splice url, and using concat to complete updated url; however, I cant seem to figure out how to get the image to revert back to still state upon next click... been working on this for sooooo many hours, will someone please lend me a fresh set of eyes?
here's my js and jquery
// $("#loadTimer, .buttonGallery, #btnGeneratingbtn").hide();
var topics = ["Brandon", "Biggie Smalls", "Dr. Seuss", "Paul McCartney", "John Lennon", "Will Ferrell", "Jimmy Fallon", "Chris Farley", "Dane Cook", "Eminem", "Nas", "Jay-Z", "Rakim", "William Shakespeare","Jim Morrison", "James Maynard", "Serj Tankian"];
var gifcount = 0;
var gifLocation;
var clickCount = 0;
var buttonFactory = function() {
$(".buttonGallery").empty();
for (i = 0; i < topics.length; i++) {
var imAbutton = $("<button>");
imAbutton.addClass("yup");
imAbutton.attr("data-name", topics[i]);
imAbutton.text(topics[i]);
$(".buttonGallery").append(imAbutton);
}};
buttonFactory();
$("#anotherButton").on("click", function(event) {
event.preventDefault();
// This line grabs the input from the textbox
var onemorebutton = $("#user-input").val().trim();
// Adding movie from the textbox to our array
topics.push(onemorebutton);
// Calling renderButtons which handles the processing of our movie array
buttonFactory();
});
$(".yup").on("click", function(){
$("#gif-Gallery").empty();
var searchTermUpdate;
var searchTerm = $(this).attr("data-name");
// removing white space between two-word strings, replacing with a "+" \\
searchTermUpdate = searchTerm.replace(/ +/g, "+");
var queryURL = "http://api.giphy.com/v1/gifs/search?q=" + searchTermUpdate + "&api_key=dc6zaTOxFJmzC&limit=10";
$.ajax({
url: queryURL,
method: 'GET'
}).done(function(response) {
console.log(response);
var results = response.data;
for (var i = 0; i < results.length; i++){
gifcount = gifLocation;
var gifDIV = $("<div class='unit' data-state='still'>");
var pRating = $("<p>").text("Rating: " + results[i].rating);
var gifImg = $("<img id='gifimg' class='col-md-4'>");
gifImg.attr("src", results[i].images.fixed_height_still.url);
gifImg.attr({'data-animate' : results[i].images.fixed_height.url});
gifImg.attr({'data-state' : "still"});
gifImg.attr({'data-still' : results[i].images.fixed_height_still.url});
gifDIV.append(pRating);
gifDIV.append(gifImg);
gifDIV.append(gifLocation);
gifcount++;
// appending gif div to DOM \\
if (results[i].rating !== "g" || "pg" || "pg-13" || "y"){
$("#gif-Gallery").append(gifDIV);
}}
$(".unit").on("click", function(){
var state = $(this).attr('data-state');
if (state === "still") {
$(this).attr("src", $(this).attr("data-animate"));
$(this).attr("data-state", "animate");
} else {
$(this).attr("src", $(this).attr("data-still"));
$(this).attr("data-state", "still");
}
// var imgPath = this.children[1].src;
clickCount++;
var a;
var b;
var c;
var d;
var f;
// if (clickCount % 2 === 0 ){
// for (i=0; i < imgPath.length; i++){
// // locating index of underscore, storing that value in var a\\
// var a = imgPath.indexOf("_");
// // removing all characters to the right of the underscore \\
// var b = imgPath.slice(0, a);
// f = b;
// // setting var c to a string value of .gif \\
// var c = ".gif";
// // combining var b and var c to complete updated image path \\
// var d = b.concat(c);
// }
// setting image url to animated url \\
// $(gifImg).attr("src", d);
// this.children[1].src = d;
});
});}); //
and here is the html if needed :
<body>
<div class="jumbotron">
<div class="container">
<div class="myHeader">
<h1>WordSmiths</h1>
<span class="text-muted" id="jtronText">
<div id="sometimeGone">Sometimes</div><div id="loadTimer">someone opens their mouth and you can't help but to be dazzled with the magic.</div>
</span>
<p class="text-success" id="instructionsOne">
Click a button, see what happens!
</p>
<p class="text-success" id="instructionsTwo">
Now you can create your own buttons!!!
</p>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="buttonGallery"></div>
<h4>Create buttons, find Gifs!: </h4>
<form id="btnGeneratingForm">
<label for="input">Anything: </label>
<input type="text" id="user-input">
<br>
<input type="submit" id="anotherButton" value="More buttons">
</form>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div id="gif-Gallery"></div>
</div>
</div>
again, thanks in advance!
Robert

I am actually doing the same project! I did it a pretty a similar way. I think the issue may be that you're appending the animated src to the image holder div instead of the child image itself. This line:
$(this).attr("src", $(this).attr("data-animate"));
Is what is giving you trouble I think.
Best of luck with the project, I hope that helps.

Related

Why is document.ready being called twice?

$(document).ready(function() {
var page = 1;
var notEOF = true;
var client = new XMLHttpRequest();
var temp = "string";
client.open('GET', '/blog/blogdata.txt');
client.onreadystatechange = function() {
if (client.responseText != '') {
var txt = client.responseText.split("\n");
if (notEOF && txt[page * 6 - 6] != "EOF") {
var data = txt[page * 6 - 6].split("#");
document.getElementById("link1").setAttribute("href", data[0]);
document.getElementById("image1").setAttribute("src", data[1]);
document.getElementById("title1").innerHTML = data[2];
document.getElementById("text1").innerHTML = data[3];
document.getElementById("tags1").innerHTML = data[4];
document.getElementById("date1").innerHTML = data[5];
} else {
notEOF = false;
$("#article1").hide();
}
}
}
var blog_html = "/blog/page";
document.getElementById("prev").setAttribute("href", blog_html.concat((page - 1).toString()));
document.getElementById("next").setAttribute("href", blog_html.concat((page - 1).toString()));
if (page == 1) {
$("#prev").addClass("disabled tm-mr-20");
}
if (page == 2) {
document.getElementById("prev").setAttribute("href", "/blog/");
}
if (!notEOF) {
$("#next").addClass("disabled tm-mr-20");
}
client.send();
});
<script src="/blog/js/jquery.min.js"></script>
<script src="/blog/js/templatemo-script.js"></script>
<script src="https://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
This is a simplified version of a script I wrote in my blog html file to automate the blog part.
blog/blogdata.txt is a textfile consisting of lines of the form url#image url#title#text#tags#date, with the last line as just EOF. (If necessary, I can restructure this). This is the structure of a blog post (ripped from here)
<article class="col-12 col-md-6 tm-post" id="article1">
<hr class="tm-hr-primary">
<a href="post.html" class="effect-lily tm-post-link tm-pt-60" id="link1">
<div class="tm-post-link-inner">
<img src="/blog/img/img-01.jpg" alt="Image" class="img-fluid" id="image1">
</div>
<h2 class="tm-pt-30 tm-color-primary tm-post-title" id="title1">Simple and useful HTML layout</h2>
</a>
<p class="tm-pt-30" id="text1">
There is a clickable image with beautiful hover effect and active title link for each post item. Left side is a sticky menu bar. Right side is a blog content that will scroll up and down.
</p>
<div class="d-flex justify-content-between tm-pt-45">
<span class="tm-color-primary" id="tags1">Travel . Events</span>
<span class="tm-color-primary" id="date1">June 24, 2020</span>
</div>
</article>
And this is the structure of the previous and next buttons
<div class="row tm-row tm-mt-100 tm-mb-75">
<div class="tm-prev-next-wrapper">
Prev
Next
</div>
</div>
There's obviously more to the script (if there's anything necessary I'm omitting, I'll add it) but this is the important part of it.
I'm trying to run the file but it's not functioning as intended (currently, the blogdata.txt file has one non-EOF line, and thus the blog should contain exactly one post. Instead, it contains none). When I added alerts to try to debug, I observed that this script is being called twice. Why?
In your case
client.onreadystatechange = function() {
if (client.readyState === XMLHttpRequest.DONE && client.responseText != '') {
but this is better
client.open('GET', '/blog/blogdata.txt');
client.onload = function() { ... }
client.send()
Since you have jQuery
$(function() {
var page = 1;
var notEOF = true;
var temp = "string";
$.get('/blog/blogdata.txt', function(responseText) {
if (!responseText || responseText.toString().trim() === "") return
const txt = responseText.split("\n");
...
});
});

Set a dynamic variable?

This may be extremely simple, but my brain's just not grasping this for some reason.
I'm making a Tic-Tac-Toe/Hollywood Squares game, and all the square variables are set to null
square0Value = "";
square1Value = "";
etc.
When you click on one of the squares, it launches a bootstrap modal with a closeup of the square and two buttons, X and O, and passes all of the data from the grid square into the modal, so that I only need one modal markup block.
When you click the X or the O, I need it to dynamically set the square variable, that is associated with the modal to either X or O, once the modal is closed, another javascript function checks all the variables to see if there's a 3-in-a-row occurrence, and displays a console.log that X or O has won the game. But I'm not writing this correctly, and none of the square variables are being set.
Here's my code:
HTML:
<button class="squareButton" data-toggle="modal" data-target="#squareModal" data-square="" data-nameplate="" data-xo="" data-id="square0">
<div class="xo"></div>
<div class="nameplate"></div>
<div class="desk"></div>
</button>
(I have this replicated 9 times.)
[Modal markup]
<div class="modal fade-scale" id="squareModal" tabindex="-1" role="dialog" aria-labelledby="squareModal">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="square">
<div class="squareModal">
<div class="xo"></div>
<div class="nameplate"></div>
<div class="desk"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" id="modalX" class="btn btn-default btn-xo" data-dismiss="modal">X</button>
<button type="button" id="modalO" class="btn btn-default btn-xo" data-dismiss="modal">O</button>
</div>
</div>
</div>
</div>
JS:
I have an array built that populates each square with a celebrity/personality, and an document.ready function that shuffles the array populates the squares:
$(document).ready(function(){
shuffle(squares);
for (i = 0; i < 9; i++) {
$("#square"+i).find('.squareButton').addClass(squares[i][0]);
$("#square"+i).find('.squareButton').data("square", squares[i][0]);
*// the [0] block of the array is a class filler*
$("#square"+i).find('.squareButton').data("nameplate", squares[i][1]);
*// the [1] block of the array is the celebrity's name*
$("#square"+i).find('.nameplate').html(squares[i][1]);
}
});
var square0Value = "";
var square1Value = "";
var square2Value = "";
var square3Value = "";
var square4Value = "";
var square5Value = "";
var square6Value = "";
var square7Value = "";
var square8Value = "";
var squareClass = "";
var squareName = "";
var squareXO = "";
var squareId = "";
$('#squareModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
squareClass = button.data('square');
squareName = button.data('nameplate');
squareXO = button.data('xo');
squareId = button.data('id');
console.log(squareId);
var modal = $(this)
modal.find('.modal-body').addClass(squareClass);
modal.find('.modal-body .nameplate').html(squareName);
modal.find('.modal-body .xo').html(squareXO);
})
$('#squareModal').on('hidden.bs.modal', function (event) {
var modal = $(this);
modal.find('.modal-body').removeClass(squareClass);
checkWin();
});
function clickX(){
$(eval(squareId+'Value')).val("X");
$(eval(squareId)).addClass('selected');
$(eval(squareId)).find(".squareButton").data("xo", "X");
$(eval(squareId)).find(".xo").html("X");
}
function clickO(){
$(eval(squareId)).addClass('selected');
$(eval(squareId+'Value')).val("O");
$(eval(squareId)).find(".squareButton").data("xo", "O");
$(eval(squareId)).find(".xo").html("O");
}
$("#modalX").on("click", function(e){
e.preventDefault();
clickX();
});
$("#modalO").on("click", function(e){
e.preventDefault();
clickO();
});
function checkWin() {
for (i = 0; i < 9; i++) {
console.log("Square"+i+": " + eval('square'+[i]+'Value'));
}
checkWinX();
checkWinO();
if (square0Value != "" && square1Value != "" && square2Value != "" && square3Value != "" && square4Value != "" && square5Value != "" && square6Value != "" && square7Value != "" && square8Value != ""){
checkBoardFull();
}
}
The issue lies in the clickX() and clickO() functions where I am trying to set the value of the (eval(squareId+'Value')) as the X or the O value that is needed. I want to make this as dynamic as possible so don't have to write a function for every modal.
Not sure why you are using eval.
$("#"+squareId).addClass()
may be enough
Here would be my suggestion.
var button = $(event.relatedTarget);
If I am reading this right, that is the button that was clicked that caused the modal to show. If that is the case, then I believe it is a far assumption that only one modal can show at a time. If that is true, then what you can do is make that variable scoped higher, not within that handler.
What does that do for you? Well, if you do that, then you can use that element within your clickX and clickY. For instance...
function clickX(){
button.data('xo', 'X');
button.find('.xo').html('X');
}
I'm unclear what the others are referencing, but if you have the button then you have access to finding it's nested children or looking for parent elements if you need to find them.
So yeah... rebuilding my global Square Values into an array was a MUCH easier way of organizing things... sorry everyone.

How to display images one at a time through loop with HTML/Javascript?

I'm not one of those people that grew up with programming, or have experienced in high school. I just recently started the basics in College. What I have below is my javascript/html that I have been working on Visual Studio 2012. My goal for it is to display the images one at a time by pressing a button called "Next Name" (as you can see I created a "form" at the bottom of my code). But as I have it now, it prints out all the images in my "hw1.txt" at the same time. Under my for loop, I tried "result = "";" and then "displayList.innerHTML = result;" hoping to just print out one image at least. I tried other things, but it just left my code messy. Please I need help. Any advice, pointers, or whatever is good. Can you also explain your answers in a way that I'll understand too? Just think of me as you're talking to a child or something haha. Thanks.
Note: in "hw1.txt" every 3rd index (starting from index 0) is the name of people, and the index next to it (myArray[i + 1]) is the image file (inside the .txt it goes like 1.jpg, 2.jpg, 3.jpg, and so on...)
<br/>
<span id="displayList">Photo here.</span>
<script type=text/javascript>
if (typeof ActiveXObject != "undefined") // IE
var req = new ActiveXObject("Microsoft.XMLHTTP");
else // Other browsers
var req = new XMLHttpRequest();
req.open('GET', 'hw1.txt', false);
req.send(null);
s = req.responseText;
var myArray = s.split(";");
var result = "";
function nextItem() {
for (i = 3; i < myArray.length; i = i + 3)
result = result + "<img src='" + myArray[i + 1] + "'/>";
displayList.innerHTML = result;
}
</script>
<form name="ClickNext">
<input type="button" value="Next Name" onclick="nextItem()" />
</form>
<span id="displayList">Photo here.</span>
<script type=text/javascript>
if (typeof ActiveXObject != "undefined") // IE
var req = new ActiveXObject("Microsoft.XMLHTTP");
else // Other browsers
var req = new XMLHttpRequest();
req.open('GET', 'hw1.txt', false);
req.send(null);
s = req.responseText;
var myArray = s.split(","); //if images are comma(,) seperated then just split it from comma
var index = 0;
function nextItem() {
if(typeof myArray[index] !== 'undefined') {
displayList.innerHTML = "<img src='" + myArray[index] + "'/>";
index += 1;
}
}
</script>
<form name="ClickNext">
<input type="button" value="Next Name" onclick="nextItem()" />
</form>
First off you don't need the form around that input since you don't really send a form.
Secound you should add an id to your input ( or <a></a> or <button></button> ) such as id="next_name" or I guess you can keep the old way of calling an event. :P
Then, you should:
var position = 0;
var result = '';
document.getElementById('next_name').onclick = function(){
if(position < myArray.length){
result = result + "<img src='" + myArray[position + 1] + "'/>";
displayList.innerHTML = result;
position++;
}
};
The idea is to use a variable to memorize your position within your list of image srouces. Once you use one, you increment your position within the list so next time a user clicks that button you add a different image.

Regular expression getElementById

I need to use pure Javascript for the first time in a long while, and having gotten used to the comfy mattress of jQuery, all the important stuff is escaping me.
I need to select a bunch of divs on regular expression. So I have stuff like this;
<div id="id_123456_7890123"> .. </div>
<div id="id_123456_1120092"> .. </div>
<div id="id_555222_1200192"> .. </div>
<div id="id_123456_9882311"> .. </div>
And I'd need to create a loop that goes through all the divs with an id that begins with id_123456_. How would I go about doing that?
I used jQuery with the :regex filter plugin before, but looking at it, it doesn't seem like there's much I could salvage in a pure javascript rewrite.
In plain javascript, you could do this generic search which should work in every browser:
var divs = document.getElementsByTagName("div"), item;
for (var i = 0, len = divs.length; i < len; i++) {
item = divs[i];
if (item.id && item.id.indexOf("id_123456_") == 0) {
// item.id starts with id_123456_
}
}
Working example: http://jsfiddle.net/jfriend00/pYSCq/
HTML DOM querySelectorAll() method will work here.
document.querySelectorAll('[id^="id_"]');
Borrowed from StackOverFlow here
This works by recursively traversing the whole DOM.
It's possibly not the most efficient, but should work on every browser.
function find_by_id(el, re, s) {
s = s || [];
if (el.tagName === 'DIV' && re.exec(el.id) !== null) {
s.push(el);
}
var c = el.firstChild;
while (c) {
find_by_id(c, re, s);
c = c.nextSibling;
}
return s;
}
var d = find_by_id(document.body, /^id_123456_/);
See http://jsfiddle.net/alnitak/fgSph/
Here you are: http://jsfiddle.net/howderek/L4z9Z/
HTML:
<div id="nums">
<div id="id_123456_7890123">Hey</div>
<div id="id_123456_1120092">Hello</div>
<div id="id_555222_1200192">Sup</div>
<div id="id_123456_9882311">Boom</div>
</div>
<br/>
<br/>
<div id="result"></div>​
Javascript:
divs = document.getElementsByTagName("div");
divsWith123456 = new Array();
for (var i = 0;i < divs.length;i++) {
if (divs[i].id.match("id_123456") != null) {
divsWith123456.push(divs[i]);
document.getElementById("result").innerHTML += "Found: divs[" + i + "] id contains id_123456, its content is \"" + divs[i].innerHTML + "\"<br/><br/>";
}
}​

find difference in two dom elements then make them same

If I have two elements :
Element A :
<div id="myID">
<div id="a"></div>
<div id="b"><div id="ba"></div></div>
<div id="c"><span id="ca"></span></div>
</div>
and Element B :
<div id="myID">
<div id="a"></div>
<div id="b"><div id="ba"></div></div>
<div id="c"><span id="ca"></span></div>
<div id="d"></div>
</div>
Is it possible to find out that Element B has more children than Element A, then find where is additional element and create it in Element A?
P.S: In real code new element is loaded with Ajax Request, but I don't want to replace all content with loaded content, I need to add only new content and skip existing one.
P.S.S : In my current code I have Md5 checksum to check if new content is not the same as existing, but if new content have only little changes it replaces all content and this is the problem for me.
A piece of my current code :
window.processResponse = function(data) {
// Note : "data" is Ajax responseText;
if(!data) return false;
var $data = document.createElement("div");
$data.innerHTML = data;
var em = $data.getElementsByTagName("*");
for(var i = 0; i < em.length; i++)
{
var parent = sget(em[i].id); // sget function is : document.getElementById
if(parent)
{
var html = em[i].innerHTML.replace(/(\s)+/gim, "").replace(/(\n|\r\n)+/gim, "");
var id = em[i].id;
savedPages[id] = savedPages[id] || [];
var _md5 = md5(html);
if(savedPages[id][0] == _md5) continue;
savedPages[id] = [_md5, getTime()];
parent.innerHTML = em[i].innerHTML;
}
if(em[i].tagName === "SCRIPT")
{
var code = em[i].innerHTML.replace(/(\s)+/gim, "").replace(/(\n|\r\n)+/gim, "");
var id = em[i].id;
savedPages[id] = savedPages[id] || [];
var _md5 = md5(code);
if(savedPages[id][0] == _md5) continue;
savedPages[id] = [_md5, getTime()];
try{eval(em[i].innerHTML)}catch(ex){log(ex)};
}
}
};
So, you can optimize it but it depends also in which browser are you running this code.
I assumed the follows:
All IDs are unique, and you rely on that. You want to compare basically elements that have the same ID, not the same structure.
As you said, all children have IDs, and you want to compare only children – not nested node
The elements received from the server have only additional children not less. For removing children, you have to add some other code.
Therefore, if you have the same number of children, we assume they're the same (to optimize). If this is not true, then you have to implement the removal of children as well
Said that, I believe that this kind of stuff is more suitable on server side, that should send to the client only the part that are actually modified. That what we do usually – or, if we don't care, replace everything.
var div = document.createElement('div');
div.innerHTML = s;
var root = div.firstChild;
var children = root.children;
var documentRoot = document.getElementById(root.id);
if (documentRoot && documentRoot.children.length < children.length) {
var node = null;
var previousNode = null;
var index = 0;
while ( node = children[index++] ) {
var documentNode = document.getElementById(node.id);
if (!documentNode) {
if (previousNode)
documentRoot.insertBefore(node, previousNode.nextSibling);
else
documentRoot.insertBefore(node, documentRoot.firstChild);
documentNode = node;
}
previousNode = documentNode;
}
previousNode = null;
} else {
// probably append as is somewhere
}
The solution is not so simple. What if the parent, myID, did not exist in sample A but the child nodes were in both samples indicating 3 layers in the DOM that need to be compared and adjusted? How would you compare this:
<div id="papa">
<div id="myID">
<div id="a"></div>
<div id="b">
<div id="ba"></div>
</div>
<div id="c">
<span id="ca"></span>
</div>
</div>
</div>
vs
<div id="papa">
<div id="a"></div>
<div id="b">
<div id="ba"></div>
</div>
<div id="c">
<span id="ca"></span>
</div>
</div>
In this case the comparison becomes more complicated. You will actually need a fully fleshed out XML/HTML language aware diff utility with a merge function. You can play around with Pretty Diff to demonstrate just how complicated this can get, but unfortunately it does not have a merge function so it cannot be a fully automated solution to your problem.

Categories