Find all Divs after being created with JQuery on click event - javascript

I'm trying to find all divs that have been created from my click event and split them into another div (.wrapAll) on a count of 3. I can't seem to get anything back when i console.log the vars length. I know this works when I do that same process on the html thats been statically typed. Below is my code and thank you fo the thoughts!
jQuery(document).ready(function($) {
// load default twitch channels
$.getJSON('https://api.twitch.tv/kraken/streams/freecodecamp?callback=?', function(data) {
//console.log(data);
});
// Bind 'Enter' to click event
$(document).bind('keypress', function(e) {
if (e.keyCode == 13) {
$('#search').trigger('click');
}
});
// manually search for games
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON( "https://api.twitch.tv/kraken/search/streams?q=" + search + "", function(data2) {
// console.log(data2.streams.length);
data2.streams.forEach(function(entry) {
//console.log(entry._links);
var streamURL = entry.channel.url;
url = entry.preview.medium;
$('#results').append('<div class="searchResults"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game + '<br> Viewers: ' + entry.viewers +'<br> Is Mature: ' + entry.channel.mature + '<br> Status: ' + entry.channel.status + ' </p></div><hr>');
});
});
// Get 3 divs and slice into one div to style ** problem child **
var a = $('div[id^=searchResu]').find('div');
console.log(a.length);
for( var i = 0; i < a.length; i+=3 ) {
a.slice(i, i+3).wrapAll('<div class="slide"></div>');
}
});
});

Check out this plunker here. I believe this does what your looking for.
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#2.1.4" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
<script>
jQuery(document).ready(function($) {
function appendHtmlContent(resultHtmlContent) {
resultHtmlContent = '<div class="slide">' + resultHtmlContent + '</div>';
$('#results').append(resultHtmlContent);
}
function processSvcResponse(data2) {
var count = 0,
searchResultContents = '',
$div = $("<div>", { class: "searchResults"});
data2.streams.forEach(function(entry) {
var streamURL = entry.channel.url;
url = entry.preview.medium;
searchResultContents += '<div class="searchResults"><a href="' + streamURL
+ '" target="_blank"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game
+ '<br> Viewers: ' + entry.viewers + '<br> Is Mature: ' + entry.channel.mature
+ '<br> Status: ' + entry.channel.status + ' </p></a></div><hr>';
count++;
if(count === 3) {
appendHtmlContent(searchResultContents);
searchResultContents = '';
count = 0;
}
});
// more results that have not been appended?
if(searchResultContents) {
appendHtmlContent(searchResultContents);
}
}
// load default twitch channels
$.getJSON('https://api.twitch.tv/kraken/streams/freecodecamp?callback=?', function(data) {});
// Bind 'Enter' to click event
$(document).bind('keypress', function(e) {
if (e.keyCode == 13) {
$('#search').trigger('click');
}
});
// manually search for games
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON("https://api.twitch.tv/kraken/search/streams?q=" + search, processSvcResponse);
});
});
</script>
</head>
<body>
<input id="searchTerm" type="text" />
<button id="search" type="button">Search</button>
<div id="results"></div>
</body>
</html>
If I understand correctly you are wanting to iterate over the results and for every third one wrap it inside a div with class "slider". As mentioned in the comments by #charlietfl in order to query newly created DOM elements using jQuery you have to query them after they are created. In the call to jQuery.getJSON the second argument accepts a callback function. The signature is jQuery.getJSON(url, someCallbackFunction). In order to make your code a bit more readable I moved "function(data2)" up and named it processSvcResponse. Inside processSvcResponse I build up an HTML string from the results and track how many results are processed by using a counter variable. Once the counter reaches 3 I append the contents to the results div and reset the counter. This solution does not "find" the divs and slice/wrapAll as you were intending to do originally, however, I believe this still accomplishes your goal.

As #charlietfl said, you'll need to place the code that wraps your divs in the callback for getJSON. Your click event listener would look something like this then:
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON( "https://api.twitch.tv/kraken/search/streams?q=" + search + "", function(data2) {
// console.log(data2.streams.length);
data2.streams.forEach(function(entry) {
//console.log(entry._links);
var streamURL = entry.channel.url;
url = entry.preview.medium;
$('#results').append('<div class="searchResults"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game + '<br> Viewers: ' + entry.viewers +'<br> Is Mature: ' + entry.channel.mature + '<br> Status: ' + entry.channel.status + ' </p></div><hr>');
});
// Get 3 divs and slice into one div to style ** problem child **
var a = $('div[id^=searchResu]').find('div');
console.log(a.length);
for( var i = 0; i < a.length; i+=3 ) {
a.slice(i, i+3).wrapAll('<div class="slide"></div>');
}
});
});

Related

sending data from a search bar to a url

I am having trouble. So I need to get data from an api. I have a search bar and the user needs to input the search bar to look up a super hero api.
How would I get data from a search bar and put in my url all in a .click function.
var userInput;
var url;
var test;
//https://superheroapi.com/api/10215865526738981
$(document).ready(function () {
// when the user types in the data and clicks the button
$(btn1).click(function () {
// this is where the search bar is
userInput = document.getElementById('mySearch').innerHTML;
});
url = 'https://www.superheroapi.com/api.php/10215865526738981/search/batman' + userInput;
// here is where the api link in say type in batman
// and is should pop up with info about batman and
$.getJSON(url, function (data) {
var html = '';
$.each(data.results, function (i, demo) {
html += '<h2>' + demo.name + '</h2>';
//html += "<h2>" + demo.biography.alter-egos + "</h2>";
html += '<h2> Power Stats ' + demo.powerstats.combat + '</h2>';
html += '<p> Connections ' + demo.connections.relatives + '</p>';
html += '<p> appearance ' + demo.appearance.gender + '</p>';
html += '<h2> Work ' + demo.work.base + '</h2>';
html += ' Profile <img src ' + demo.image.url + '>';
});
$('#demo').html(html);
});
}
<p>
<input type="search" id="mySearch" name="mySearch">
<button id="btn1">Search</button>
<p id="demo"></p>
</p>
Here is something that works that you can use to compare with your code and make something out of it. I've used plain javascript and left comments what is going on so that you can learn from it.
There were few wrong assumptions in original question.
code was executing on page load and didn't wait for user input
url was hardcoded to start with batman + what ever user wrote
Code below is not perfect, but it is close enough to original code and it should be easy to understand. I also opted not to use jQuery, but you should be able to use it if wanted. Just replace getElementById with jQuery selectors and replace XMLHttpRequest with getJson.
I hope this helps you move ahead with your problem and that you will be able to learn something new which could help you better understand javascript. Happy coding!
var button = document.getElementById('btn1');
// when user clicks on button, we want to call function start search
button.addEventListener('click', startSearch);
function startSearch(event) {
// when we are starting the search, we want to pick up the value
// input field from user
var userInputValue = document.getElementById('mySearch').value;
// this is base API url on which we can add what user wanted
var urlBase = 'https://www.superheroapi.com/api.php/10215865526738981/search/'
// if user did not provide name in input, we want to stop executing
if (userInputValue === null || userInputValue === '') return;
// if we are still in this function, append what user typed onto urlBase
var searchUrl = urlBase + userInputValue;
// call function which actually executes the remote call
performSearch(searchUrl);
}
function performSearch(searchUrl) {
// this could be jQuery getJSON if you so prefer
// here it is vanila JS solution of how to get data via AJAX call
var requestData = new XMLHttpRequest();
// because AJAX is always async, we need to wait until file is loaded
// once it is loaded we want to call function handleResults
requestData.addEventListener('load', handleResults);
requestData.open('GET', searchUrl);
requestData.send();
}
function handleResults() {
// once we get response, because we used vanilla JS, we got response
// available in this context as "this.response", however it is type string
// we need to take that string and parse it into JSON
var responseJSON = JSON.parse(this.response);
// if there is error, we didn't find any character
if (responseJSON.error) console.log('Character not found');
else {
var html = '';
responseJSON.results.forEach(function (result) {
html += '<h2>' + result.name + '</h2>';
// html += "<h2>" + demo.biography.alter-egos + "</h2>";
html += '<h2>Power Stats ' + result.powerstats.combat + '</h2>';
html += '<p>Connections ' + result.connections.relatives + '</p>';
html += '<p>Appearance ' + result.appearance.gender + '</p>';
html += '<p>Work ' + result.work.base + '</p>';
// html += ' Profile <img src ' + result.image.url + '>';
})
// this is bad thing to do, injecting html like that into DOM
// but let's leave this lesson for later stage
// so, let's take this html and drop it onto the page
document.getElementById('demo').innerHTML = html;
}
}
<input type="search" id="mySearch" name="mySearch">
<button id="btn1">Search</button>
<div id="demo"></div>
const value = document.getElementById('mySearch').value;
And then use this value in your api url.

jQuery, Passing object on click from array to another function

I have a list of objects coming into my web page. One property of the object is firstName. I display some of the properties and have a clickable one that calls another fuction. I want to pass the object from the array to the second function
jQuery.each(x, function () {
$('#results').append("<a href='javascript:void(0)' onClick='workSup(" + '"' + $(this) + '"' + ")' >" + decodeURI(this.firstName) + ' ' + decodeURI(this.lastName) + " - " + decodeURI(this.preApprovalSupervisorName) + " <a/><br/> ");
});
function workSup(x) {
alert(x.firstName);
}
I've tried passing this as well as $(this). The alert reads "undefined"
What am I doing wrong? Thanks!
jQuery has a great function, .data(), I'd recommend you look into:
$('#selector').data("key", "value (string, number, object, etc.)")
$('#selector').data("key"); //Returns the data, or null if not yet set
Also, I highly recommend moving away from onclick to
$('.myClassName').on("eventName (such as click, change or keyup)", "jqSelector", handlerFunction);
var x = [{firstName:"John", lastName:"Lennon"}, {firstName:"Phil", lastName:"Ochs"}]
$(document).ready(function() {
jQuery.each(x, function () {
var linkEl = $('<a class="myLink" href="javascript:void(0)">' + this.firstName + " " + this.lastName + '</a>');
linkEl.data("myObjData", this);
$('#results').append(linkEl);
});
$(document).on("click", ".myLink", function() {
var myObjData = $(this).data("myObjData");
//myObjData.firstName can be accessed here
alert(JSON.stringify(myObjData));
});
});
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<div id="results"></div>
</body>
</html>
$('.myClass').on() is even better than $('.myClass').click() because it will even listen to elements that are dynamically added later
jQuery.each(x, function() {
//create the a element
var $a = $("<a href='javascript:void(0)'>"+
decodeURI(this.firstName) +' '+ decodeURI(this.lastName) +
" - "+ decodeURI(this.preApprovalSupervisorName) +
"</a><br/>");
//bind the event handler to it
$a.on('click', function(){
workSup(x);
});
});
As mentioned by #taplar you're creating inline binding. Basically what happens is that your $(this) gets resolved as string and later inside your workSup() method you're trying to access firstName property of the string which is obviously undefined.
What you have to do instead is to dynamically create your link and attach event listener to it (in which you call the workSup() method) like so:
// Your data
const x = [
{ firstName: 'First', lastName: 'Last', preApprovalSupervisorName: 'Super' },
{ firstName: 'Another', lastName: 'One', preApprovalSupervisorName: 'His super' },
];
// Your workSup method
const workSup = x => alert(x.firstName);
// Loop though each item
$.each(x, function() {
// Create new <a> element
const $element = $('<a></a>')
// Add href attribute
.attr('href', 'javascript:void(0)')
// Set its text
.text(`${decodeURI(this.firstName)} ${decodeURI(this.lastName)} ${decodeURI(this.preApprovalSupervisorName)}`)
// Attach onClick listener
.on('click', () => workSup(this));
// Append the element to the results and add line break
$('#results')
.append($element)
.append('<br />');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="results"></div>
var x =[{firstName: "John", lastName:"DG", preApprovalSupervisorName: "sup"}];
jQuery.each(x, function (index, value) {
$('#results').append(
$("<a>")
.attr("href","#")
.html( decodeURI(value.firstName) + ' ' + decodeURI(value.lastName) + " - " + decodeURI(value.preApprovalSupervisorName))
.click(function(){
workSup(value);
})
);
});
function workSup(x) {
alert(x.firstName);
}

jQuery getJSON and get value from button

I'm download data from JSON file and display button with value:
function iterateOverPrzepisy(best) {
$('#listaPrzepisow').html('');
$.getJSON('przepisy.json', function(data) {
for (var x in przepisyDost) {
$('#listaPrzepisow').append(" <div data-role=\"collapsible\"><h2>" + przepisyDost[x].nazwa + "</h2>" +
"<ul data-role=\"listview\" data-theme=\"d\" data-divider-theme=\"d\">" +
"<li>" +
"<h3>Składniki: " + przepisyDost[x].skladniki + "</h3>" +
"<p class='ui-li-desc' style='white-space: pre-wrap; text-align: justify;'>" + przepisyDost[x].tresc + "</p>" +
"<button id='ulubioneBtn' value='" + przepisyDost[x].id + "'>Ulubione</button></li>" +
"</ul>" +
"</div>");
j++;
}
})
}
When I click to button #ulubioneBtn I would like to get value from this button. So I add done to getJSON
}).done(function(data){
$('button#ulubioneBtn').click(function (event) {
console.log("Ulubione: ");
event.preventDefault();
var id = $("button#ulubioneBtn").val();
console.log("Value: " + id);
//dodajemy do ulubionych
localStorage.setItem("ulubione"+id, id);
});
});
But it's not working. When I click on button Ulubione I always get in console log value = 0
The problem seems to be that you add multiple buttons with the same id. An id of a html element should be unique.
przepisyDost does not appear to be defined at
for (var x in przepisyDost) {
? Try
for (var x in data.przepisyDost) {
Duplicate id's are appended to document at
"<button id='ulubioneBtn' value='" + przepisyDost[x].id
+ "'>Ulubione</button></li>" +
within for loop. Try substituting class for id when appending html string to document
"<button class='ulubioneBtn' value='" + data.przepisyDost[x].id
+ "'>Ulubione</button></li>" +
You could use event delegation to attach click event to .ulubioneBtn elements, outside of .done()
$("#listaPrzepisow").on("click", ".ulubioneBtn", function() {
// do stuff
})
I have created a dummy JSON and executed the same JS with a single change.
In onclick handler instead of getting button I am using $(event.target).
And it is working fine.
Please find the fiddle https://jsfiddle.net/85sctcn9/
$('button#ulubioneBtn').click(function (event) {
console.log("Ulubione: ");
event.preventDefault();
var id = $(event.target).val();
console.log("Value: " + id);
//dodajemy do ulubionych
localStorage.setItem("ulubione"+id, id);
});
Seems like first object doesn't have any id value.
Please check JSON response returned from server.
Hope this helps you in solving.

Using an event handler on a anchor link added in Javascript

I have an Ajax call that returns an array of movie titles. I'd like to click on a button next to each title and add the title to a "currently watching" list. My "add" link doesn't seem to be accepting the event handler. What can I do to add the specified title to my "currently watching" list
$("#search").click(function(event){ event.preventDefault();
var show = $("#showTitle").val().toLowerCase();
console.log("the show title is " + show);
var url = "https://api.themoviedb.org/3/search/movie?query=" + encodeURIComponent(show)+ "&api_key=9b97ec8f92587c3e9a6a21e280bceba5";
console.log(url);
$.ajax ({
url: url,
dataType: "json",
success: function (data) {
// console.log(data.results);
var htmlStr = '';
$.each(data.results, function(i, results){
htmlStr += '' + 'Add' + ' <h2 class="movie-title">' + results.original_title + '</h2>' + "Average Rating " + results.vote_average + '<br>' + '<p class="showDescription">' + results.overview + '</p>' + '<br />' + '<img src=https://image.tmdb.org/t/p/w185' + results.poster_path + '>';
});
// console.log(htmlStr);
$('#searchresults').html(htmlStr);
}
// updateCount(); - count the classes inside the "currentywatching" function
}); //close .ajax
});
$('.addCurrentlyWatching').on('click', function(e){
e.preventDefault();
var movieTitle = $('.movie-title').text();
// console.log(movieTitle);
$('.currently-watching').append('<li>' + movieTitle + '</li>');
});
<section id = "shelf1">
<h2> Currently Watching </h2>
<ul class="currently-watching"></ul>
<div class="number">
<p> You currently have <span id="count"> 0 </span> shows in this list. </p>
</div>
</section>
The solution:
$(document).on('click','.addCurrentlyWatching', function(e){
e.preventDefault();
var movieTitle = $('.movie-title').text();
// console.log(movieTitle);
$('.currently-watching').append('<li>' + movieTitle + '</li>');
});
If you are interested in a more detailed answer:
Explanation
use
$('body').on('click','.addCurrentlyWatching', function(e){
take a look at Event binding on dynamically created elements?
and in
' + 'Add' + '
if you have Add variable defined use
' + Add + '
if you not
Add
and you can use
var movieTitle = $(this).next('.movie-title').text();
instead of
var movieTitle = $('.movie-title').text();
For older versions of jQuery use $.live & $.delegate
Docs:
http://api.jquery.com/live/
http://api.jquery.com/delegate/

Rebind Mapbox popups after filtering

I've built a Mapbox map that has a fairly involved custom popup structure, including photos and formatting. I'm using a .csv file and omnivore to feed my data, and creating the popup .on ready. I've also got a search box that searches the data using jQuery.
Independently, each one works. The popups load fine, and the search is working. But after filtering using the search thing, I lose the popups.
I've looked at this similar post but nothing suggested seems to be working. I think this has to do with my popup variable being contained inside of the .on ready function. Is there something I'm missing here? Do I need to restructure how the popups are created?
Here's my code:
var featureLayer = L.mapbox.featureLayer().addTo(map);
jQuery('#search').keyup(search);
Load data, format popups:
var csvLayer = omnivore.csv('Stats.csv', null, L.mapbox.featureLayer())
.on('ready', function() {
map.fitBounds(csvLayer.getBounds(), {paddingTopLeft: [0,25]});
function updownFormat(updown, change){
if (updown === '—') {
return "No change ";
} else if (updown === "N/A") {
return "New store - no data ";
} else if (updown === '▲') {
return '<span class="upPercent">' + updown + "</span> " + change;
} else {
return '<span class="downPercent">' + updown + "</span> " + change;
}
};
csvLayer.eachLayer(function(layer) {
var prop = layer.feature.properties
var popup = '<div class="popup"><h3>'+ prop.storename +'<\/h3>' +
'<h4>'+ prop.town +'</h4>' +
'<p><b>Rank:</b> #'+ prop.rank +' (of 80 stores) <br>' +
'<b>Sales: </b>' + prop.money14 +' (2014)<br>' +
'<b>Growth: </b>' + updownFormat(prop.updown, prop.change) + ' (from 2013)</p>' +
'<h5>Best selling bottles (2014)</h5>' +
'<img src="'+ prop.pop1img +'" class="liquorimg">' +
'<ol><li><b>'+prop.pop1+'</b></li><li>'+prop.pop2+'</li><li>'+prop.pop3+'</li><li>'+prop.pop4+'</li><li>'+prop.pop5+'</li></ol></div>';
layer.bindPopup(popup);
});
})
.addTo(map);
The search function:
function search() {
// get the value of the search input field
var searchString = jQuery('#search').val().toLowerCase();
csvLayer.setFilter(showStoreTown);
function showStoreTown(feature) {
return feature.properties.storetown
.toLowerCase()
.indexOf(searchString) !== -1;
}
}
Fixed, thanks to Twitter! Setting map bounds on "ready" and setting the popup creation on "addlayer" took care of it.

Categories