Trying to loop through json received from wikipedia api using .each(), but it returns undefined on everything. What have I missed?
Here is codepen: https://codepen.io/ekilja01/pen/pRerpb
Here is my HTML:
<script src="https://use.fontawesome.com/43f8201759.js">
</script>
<body>
<h2 class="headertext">WIKIPEDIA <br> VIEWER </h2>
<div class="row">
<div class="col-10-md">
<input class="searchRequest blink_me" id="cursor" type="text" placeholder="__"></input>
</div>
<div class="searchIcon col-2-md"> </div>
</div>
<div class="results">
</div>
</body>
Here is jQuery:
$(document).ready(function() {
var icon = "<i class='fa fa-search fa-2x'></i>";
$('#cursor').on("keydown", function() {
$(this).removeClass("blink_me");
var searchIcon = $(".searchIcon");
searchIcon.empty();
if ($(".searchRequest").val().length > 0) {
searchIcon.append(icon);
}
searchIcon.on("click", function() {
console.log("clicked!");
var search = $(".searchRequest").val();
var url = "https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=" + search + "&format=json&callback=?";
$.ajax({
dataType: "jsonp",
url: url,
success: function(data) {
$("ul").empty();
$.each(data[1], function(value, index) {
$(".results").append("<ul><li><h3>" + data[1][index] + "</h3><p>" + data[2][index] + " Read More...</p></li></ul>");
});
searchIcon.empty();
}
});
});
});
});
in $.each(data[1], function(value, index) you've to switch value to index and viceversa like this $.each(data[1], function(index, value)
For reference: jQuery.each()
I have gone through your code. Please change
$.each(data[1], function(value, index) to
$.each(data[1], function(index, value)
This is a bit of a crude way of going about this but one way I verify that the information is what it should be is to iterate with a nested for loop.
It may not solve the immediate problem, but its a way to go to understand how this thing is working.
for(var i = 0; i < data.length; i++)
{
///alert(data[i]); //See what data you're passing to WIKIPEDIA's API
for(var j = 0; j < data[i].length; j++)
{
//See what data WIKIPEDIA's API is passing to you
//From here, you can determin which value (j) to us (e.g. j = 0 is the Title)
//Once you hav that, you can use it to append to you 'results' class
alert('i = ' + i + '| j = ' + j);
alert('data = ' + data[i][j]);
///////////
//$(".results").append("<ul><li><h3>" + data[i][j] + "</h3><p>"
//+ data[i][j] + "<a href=\"" + data[i][j]
//+ "\"> Read More...</a></p></li></ul>");
///////////
}
While this is not a fix for your problem (fixed by Roberto Russo), there is something else going on that's probably not intended: you register searchIcon.on("click") callback inside $('#cursor').on("keydown") callback. What this means is that every time keydown event fires on the $(#cursor) element, a new listener will be added to searchIcon.on("click"). That's why you see "clicked!" printed multiple times for just one click. Also, if you check the network log, you'll see multiple requests sent to the wiki api for the same reason.
I'd suggest moving searchIcon.on("click") outside $('#cursor').on("keydown").
You need to swap value and index to this:
$.each(data[1], function(index, value)
Make sure whenever you call $.each() function, you cannot change the order of the arguments.
Example : $.each(arryName, function(index, value)
index = The index associates with arryName
value = The value associates with the index
Related
What I have is a page which is gathering a large list of data via jQuery. I am trying to limit the amount of results shown to a variable, and change the results shown on the list to create a false-page effect. Everything works via the same JS function, and relies on 1 variable to make everything work. Simple. I've removed all of the extra code to simplify everything
function myFunction() { var page = 1; console.log(page); }
I am looking for a way to call on this function, but change the variable 'page' from within html. Something along the lines of:
2
I have been looking on google (and still am) I just can't seem to find what I am looking for. I'm trying to avoid multiple pages/refreshing as this element is going to be used for a larger project on the same page.
UPDATE: I managed to pass the intended values through to a JS function like so...
function myFunction(page) { console.log(page); }
...and...
<input type='button' onclick='myFunction(value)' value='input page number'>
This seems the simplest way of doing what I need, what do you think?
Thanks for your help btw guys.
To do this you will need to move the page variable to be a parameter of myFunction
function myFunction(page) { console.log(page); }
Then you can just pass in whatever page number you would like
2
Sure, you can add the data-url attribute to your markup and select on the .link class to fetch the data-url attribute for each element thats part of that class.
I'm trying to avoid multiple pages/refreshing as this element is going
to be used for a larger project on the same page.
Sounds like you also want an AJAX solution.
$(document).ready( function()
{
//Add this on your call.html page
$(".link").click(function()
{
//location of test JSON file
var root = 'https://jsonplaceholder.typicode.com';
//your custom attribute acting as your 'variable'
var page = $(this).attr('data-url');
console.log("page = " + page);
//remove any previous html from the modal
$(".modal-content").empty();
//send a request to the server to retrieve your pages
$.ajax(
{
method: "GET",
//this should be updated with location of file
url: root + '/posts/' + page,
//if server request to get page was successful
success: function(result)
{
console.log(result);
var res = result;
var content = "<div class='panel-default'><div class='panel-heading'><h3 class='panel-title'>" + res.title + "</h3></div><i><div class='panel-body'>''" + res.body + "''</i></div><p><u> Master Yoda, (2017)</u></p><p class='page'> Page: " + page + "</p></div>";
$(".modal-content").html(content);
},
//otherwise do this
error: function(result)
{
$(".modal-content").html("<div class='error'><span><b> Failed to retrieve data </b></span><p> try again later </p></div>");
}
});
});
});
.error
{
border: 2px dotted red;
margin: 5px;
}
a
{
font-size: 20px;
}
.page
{
text-align: left;
padding: 0 15px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
<a class="link" data-url="1" data-toggle="modal" data-target="#Modal" href="test.html">Show Page 1</a>
<br />
<a class="link" data-url="2" data-toggle="modal" data-target="#Modal" href="">Show Page 2</a>
<div id="Modal" class="modal fade text-center">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
</div>
I seem to have figured out how to do this. I wanted to stray from using lots of libraries in the project and just wanted to keep things simple, using the above answers for guidance (and a little more digging), basically my end goal was to use jQuery to obtain a long list of data, and format this data into a multiple page list (for which I used a table for formatting purposes). Let's say it's a list of names. The JSON results output as:
[{"first_name":"Bob"},{"last_name":"Jones"}] // (key, value)
But when I passed this through to the HTML Table it was just displaying 1000s of results in a single list, and formatting the list was a pain. This was my solution:
<script>
var pageNum = ""; // define Page Number variable for later.
var resLimit = 35; // variable to specify the number of results per page
function updateList () {
$.getJSON(" Location of JSON results ", function(data) {
var pageCount = Math.round(data.length/resLimit); // calculate number of pages
var auto_id = ((pageNum-1)*resLimit) // use variables to give each result an id
var newListData = ""; // define this for use later
then define and pass "new list data" to HTML Table:
var newListData = "";
$.each(data.slice(auto_id, (pageNum*resLimit)), function(key, value) {
auto_id++;
newListData += '<tr>';
newListData += '<td class="id">' + audo_id + '</td>';
newListData += '<td class="id">' + value.first_name + '</td>';
newListData += '<td class="id">' + value.last_name + '</td>';
newListData += '</tr>';
});
$('# ID of table, data will replace existing rows ').html(newListData);
At this point if you set the value of pageNum to 1 you should see the first 35 results on the list, all with auto-incremented ID numbers. If you change it to 2 and refresh the page you should see the next 35, with the ID numbers following on from the first page.
Next I needed to create a button for each of the pages:
$('# ID of table, data will replace existing rows ').html(newListData);
function createButtons() {
var buttonArray = "";
for(i=0, x=pageCount; i<x; i++) {
buttonArray += '<input type="button" onclick="changePage('
+ (i + 1) + ')" value="' + (i + 1) + '">';
}
$('# ID of Span tags for button container ').html(buttonArray); }
createButtons();
}); }
</script>
Then create changePage() and a function to refresh the data in the list automatically without messing things up
<script>
var pageNum = "";
function changePage(page) {
if (pageNum < 1) { pageNum = 1; } // set pageNum when the page loads
if (page > 0) { pageNum = page; } // overwrite pageNum when 'page' variable is defined
updateList(); }
changePage(); // initialise to prevent delayed display on page load
// refresh function:
function refreshData() {
changePage(0); // define 'page' as 0 so that pageNum is not overwritten
window.setTimeout(refreshData, 5000); } // loop this function every 5 seconds to
refreshData(); //-- keep this list populated with current data.
And that should just about do it! At least it's working for me but I might have missed something (hopefully not lol). Hope this helps someone theres quite a few things involved in this that could be extrapolated and used elsewhere :)
thanks for help everyone.
Hi guys i been trying to figure out for a long time but i suck at this, i found this code on google and i added it adn changed what i need but still doesnt work i really need this for my site: http://www.balkan-party.cf/
I found code here: http://www.samkitson.co.uk/using-json-to-access-last-fm-recently-played-tracks/
My last.fm username i need in js: alicajdin AND
Api key: 24f6b03517ad9984de417be5d10e150b
This is what i did:
$(document).ready(function() {
$.getJSON("http://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user=alicajdin&api_key=24f6b03517ad9984de417be5d10e150b&limit=2&format=json&callback=?", function(data) {
var html = ''; // we declare the variable that we'll be using to store our information
var counter = 1; // we declare a counter variable to use with the if statement in order to limit the result to 1
$.each(data.recenttracks.track, function(i, item) {
if(counter == 1) {
html += 'Currently listening to: <span>' + item.name + ' - ' + item.artist['#text'] + '</span>';
} // close the if statement
counter++ // add 1 to the counter variable each time the each loop runs
}); // close each loop
$('.listening-to h5').append(html); // print the information to the document - here I look for the h5 tag inside the div with a class of 'listening-to' and use the jQuery append method to insert the information we've stored in the html variable inside the h5 tag.
}); // close JSON call
});
I created that file and i tried to add on head section, footer section but it wont show recent tracks.
And yea i have scroblr installed on google crome
below </script> add the following code:
<div class="listening-to"></div>
then remove "h5" on
"$('.listening-to h5').append(html);"
so your code like this:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("http://ws.audioscrobbler.com/2.0/?method=user.getRecentTracks&user=YOUR_USERNAME&api_key=YOUR_API_KEY&limit=2&format=json&callback=?", function(data) {
var html = '';
var counter = 1;
$.each(data.recenttracks.track, function(i, item) {
if(counter == 1) {
html += 'Currently listening to: <span>' + item.name + ' - ' + item.artist['#text'] + '</span>';
}
counter++
});
$('.listening-to').append(html);
});
});
</script>
<div class="listening-to"></div>
Hope you can help. Sorry, my English is very Bad (Google Translate)
I'm creating a small web-app for my girlfriend and I that will allow us to keep track of the movies we want to watch together. To simplify the process of adding a movie to the list, I'm trying to use TheMovieDatabase.org's API (supports JSON only) to allow us to search for a movie by title, let the database load a few results, and then we can choose to just add a movie from the database or create our own entry if no results were found.
I'm using jQuery to handle everything and, having never used JSON before, am stuck. I wrote a short bit of code to get the JSON based on my search query, and am now trying to populate a <ul> with the results. Here's what I have.
var TMDbAPI = "https://api.themoviedb.org/3/search/movie";
var moviequery = $("#search").val();
var api_key = "baab01130a70a05989eff64f0e684599";
$ul = $('ul');
$.getJSON( TMDbAPI,
{
query: moviequery,
api_key: api_key
},
function(data){
$.each(data, function(k,v) {
$ul.append("<li>" + k + ": " + v + "</li>");
}
);
});
The JSON file is structured as
{
"page":1,
"results":[
{
"adult":false,
"backdrop_path":"/hNFMawyNDWZKKHU4GYCBz1krsRM.jpg",
"id":550,
"original_title":"Fight Club",
"release_date":"1999-10-14",
"poster_path":"/2lECpi35Hnbpa4y46JX0aY3AWTy.jpg",
"popularity":13.3095569670529,
"title":"Fight Club",
"vote_average":7.7,
"vote_count":2927
}, ...
"total_pages":1,
"total_results":10
}
but all I'm getting is
page: 1
results: [object Object], ...
total_pages: 1
total_results: 10
I've searched quite extensively on the Internet for a solution, but with the little knowledge I have of JSON I wasn't able to learn much from the various examples and answers I found scattered about. What do?
It looks like what you'd like to do is write out some properties of each movie in the list. This means you want to loop over the list in data.results, like this:
// Visit each result from the "results" array
$.each(
data.results,
function (i, movie) {
var $li = $('<li></li>');
$li.text(movie.title);
$ul.append($li);
}
);
This will make a list of movie titles. You can access other properties of movie inside the each function if you want to show more elaborate information.
I added the title to the li using $li.text rather than simply doing $('<li>' + movie.title + '</li>') since this will avoid problems if any of the movie titles happen to contain < symbols, which could then get understood as HTML tags and create some funny rendering. Although it's unlikely that a movie title would contain that symbol, this simple extra step makes your code more robust and so it's a good habit to keep.
You need to traverse the results object. In the $.each function change data for data.results
You can use a simple for loop to iterate over the list/array. in the example below i am appending a list item containing the value of the key results[i].title. you can append the values of as many valid keys as you would like to the div.
var TMDbAPI = "https://api.themoviedb.org/3/search/movie";
var moviequery = $("#search").val();
var api_key = "baab01130a70a05989eff64f0e684599";
$ul = $('ul');
$.getJSON( TMDbAPI,
{query: moviequery,api_key: api_key},function(data){
var results = data.results;//cast the data.results object to a variable
//iterate over results printing the title and any other values you would like.
for(var i = 0; i < results.length; i++){
$ul.append("<li>"+ results[i].title +"</li>");
}
});
html
<input id="search" type="text" placeholder="query" />
<input id="submit" type="submit" value="search" />
js
$(function () {
$("#submit").on("click", function (e) {
var TMDbAPI = "https://api.themoviedb.org/3/search/movie";
var moviequery = $("#search").val();
var api_key = "baab01130a70a05989eff64f0e684599";
$.getJSON(TMDbAPI, {
query: moviequery,
api_key: api_key
},
function (data) {
$("ul").remove();
var ul = $("<ul>");
$(ul).append("<li><i>total pages: <i>"
+ data.total_pages + "\n"
+ "<i>current page: </i>"
+ data.page
+ "</li>");
$.each(data.results, function (k, v) {
$(ul).append("<li><i>title: </i>"
+ v.original_title + "\n"
+ "<i>release date: </i>" + v.release_date + "\n"
+ "<i>id: </i>" + v.id + "\n"
+ "<i>poster: </i>"
+ v.poster_path
+ "</li>");
});
$("body").append($(ul))
});
});
});
jsfiddle http://jsfiddle.net/guest271314/sLSHP/
I've been tweaking this and that and the other in an attempt to get the "Stop running this script?" error to go away in IE7 - the browser all users are required to use at this time :P I've tried several improvement attempts; all of them have caused the script to stop working, instead of running long. I've tried using setTimeout(), with no luck. It's possible I didn't do it correctly. Can anyone suggest ways to improve this to make it more efficient (and get that dang long running script message to go away)?
Here's the code:
The HTML:
<div class="changeView" style="float:right;">Show All...</div>
<div id="accordion" style="width: 99%;">
<% foreach (var obj in Model.Objects) { %>
<h3><span class="title"><%:obj.Id%></span><span class="status" style="font-size:75%"> - <%:obj.Status%></span></h3>
<div id="<%:obj.Id %>">
<div class="loading"><img src="<%=Url.Content("~/Content/Images/ajaxLoader.gif") %>" alt="loading..." /></div>
</div>
<% } %>
</div>
Then we have an onclick function to start it off...
$(function () {
$(".changeView").click(function () {
var divText = $(this).html();
var src = '<%=Url.Content("~/Content/Images/ajax-loader.gif")%>';
if (divText == "Show All...") {
$(this).html("Show Filtered...");
$('#accordion').accordion('destroy');
$('#accordion').empty();
$('#accordion').addClass("loading");
$('#accordion').append('Loading Information...<img src="' + src + '" alt="loading..." />');
changePartialView("all");
}
else {
$(this).html("Show All...");
$('#accordion').accordion('destroy');
$('#accordion').empty();
$('#accordion').addClass("loading");
$('#accordion').append('Loading Information...<img src="' + src + '" alt="loading..." />');
changePartialView("filter");
}
});
});
Next the changeView function is called:
//change view and reinit accordion
function changePartialView(viewType) {
$.ajax({
type: "POST",
url: "<%:Model.BaseUrl%>" + "ToggleView",
data: "Type=<%:Model.Target%>&Id=<%:Model.Id%>&view=" + viewType,
success: function (result) {
$('#accordion').empty();
$('#accordion').removeClass();
for (var index = 0; index < result.Html.length; index++) {
$('#accordion').append(result.Html[index]);
}
var $acc = $("#accordion").accordion({
collapsible: true,
active: false,
autoHeight: false,
change: function (event, ui) {
var index = $acc.accordion("option", "active");
if (index >= 0) {
var clickedId = ui.newHeader.find("a").find(".title").text();
getRequirements(clickedId);
}
else {
// all panels are closed
}
}
});
},
error: function (xhr, err) {
alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status);
alert("responseText: " + xhr.responseText);
alert("Error in ajax: " + result);
}
});
}
Note: The result.Html returns a generic List of formatted HTML, one for each panel of the accordion. With the exception of the long running script error message, everyone works pretty sweet.
Clarification of returned value: The result.Html consists of about 200-250 instances of these strings:
"<h3><a href=\"#\"><span class=\"title\">" + obj.Id +
"</span><span class=\"status\" style=\"font-size:75%\"> - " + obj.Status + count +
"</span></a></h3><div id=\"" + obj.Id + "\"><div class=\"loading\"><img src=\"" +
Url.Content("~/Content/Images/ajaxLoader.gif") + "\" alt=\"loading...\" /></div></div>")
for (var index = 0; index < result.Html.length; index++) {
$('#accordion').append(result.Html[index]);
}
Appending a lot of nodes one-at-a-time into the DOM is slow, one way you might be able to speed this up is to insert them all into an unattached node and then move them all at once when you're done:
var holder = $('<div></div>');
for (var index = 0; index < result.Html.length; index++) {
holder.append(result.Html[index]);
}
$('#accordion').append(holder.children());
Change the server to return data instead of lots of HTML. Use a client-side templating solution.
Then, once you have an array, you can just update the display asynchronously (like with the setTimeout you mentioned)
You only have two dynamic things in that big HTML string, pretty wasteful.
Or return less items?
Okay, so I'm parsing some data from a webservice here.
I'm just throwing in a bunch of values from a json object into html, however! i need to check if a certain json value is set to true or false. If so, i need to remove/add a word.
So i basicly i need to get a bunch of prices out. That's easy
$.each(data.d, function (i, service) {
$(".services").append('<li class="classes here"><p class="servicePrice">'+service.Price+' kr</p><div class="serviceNames">' + service.Name +'<br />' + service.FirstAvailableSlot + '</div>
});
Now! i have to check for this value called FromPrice in the JSON object. And if that is true, then the word 'fra' should be added to the beginning of the the p tag with the class servicePrice.
Now, i certainly can't do it like this.
$.each(data.d, function (i, service) {
if (service.PriceFrom == false) { $('.servicePrice').prepend('fra '); };
$(".services").append('<li class="classes here"><p class="servicePrice">'+service.Price+' kr</p><div class="serviceNames">' + service.Name +'<br />' + service.FirstAvailableSlot + '</div>
});
That's just gonna add the word a whole bunch of times depending on how many loops we go through.
i've tried doing it the whole if thing inside the servicePrice tag. But that just gave me a whole lot of javascript parse errors.
Anyone wanna throw this guy a bone?
Update: I'm still not sure about this, but is this what you're looking for?
$.each(data.d, function (i, service) {
var txt = (service.PriceFrom == false) ? "fra" : "";
$(".services").append('<li class="classes here">'+txt+'<p class="servicePrice">'+service.Price+' kr</p><div class="serviceNames">' + service.Name +'<br />' + service.FirstAvailableSlot + '</div>');
});
If I understood correctly then this should work.
var isFalse = false;
$.each(data.d, function (i, service) {
if (service.PriceFrom == false && !isFalse) {
$('.servicePrice').prepend('fra ');
isFalse = true;
};
$(".services").append('<li class="classes here"><p class="servicePrice">'+service.Price+' kr</p><div class="serviceNames">' + service.Name +'<br />' + service.FirstAvailableSlot + '</div>
});