I'm working on the API project now in javascript, and I have not been able to find any answers for how to place the json data from the New York Times API into my html. I have successfully linked to the NYT API.
In the js below, the findSearch() function successfully gets the data from the NY site, but when I use the $.each() to call to the showData(i, result) function, the data comes back as undefined.
I can see that the data is making it’s way up to this function because of a console.log() I did in the showData() function, but I think I am calling the json data incorrectly.
To see the entire project (it’s not the big; don't worry), you can go here.
var showData = function (i, result) {
var template = $(".results .template .searchDisplay").clone();
var headline = template.find('.headline');
headline.text(result.response.docs.headline);
var abstract = template.find('.abstract');
abstract.text(result.response.docs.abstract);
var snippet = template.find('.snippet');
snippet.text(result.response.docs.snippet);
var url = template.find('.url');
url.text(result.response.docs.url);
console.log(result)
console.log(result.response.docs.headline)
$('.searchDisplay').show('fast');
return result;
};
// THIS FUNCTION CALLS OUT TO THE NYT API, GETS DATA
var findSearch = function(search){
var request = {tagged: search,
site: 'New York Times',
order: 'decs',
sort: 'creation'};
var result = $.ajax({
url: 'http://api.nytimes.com/svc/search/v2/articlesearch.json?q=' + search + '&fq=source:("The New York Times")&page=0&sort=oldest&api-key=a1eeb62c8df499298c449983e6967154:3:69423736',
type: 'GET',
dataType: 'json',
data: search,
})
.done(function(result) {
console.log("success");
console.log(result.response);
var searchResults = showSearchData(request.tagged, result.response.docs.length );
$('.info').html(searchResults);
$.each(result.response.docs, function(i, item) {
var showing = showData(item, result);
$('.searchDisplay').append(showing);
});
}).fail(function() {
console.log("error");
$('.results').html('This feature is not working. :-(');
});
Related
Browser: IE 11
PlatForm: SharePoint 2016
I am trying to cache data into an array when page loads, so that the array can be used throughout the rest of my code for efficiency purposes. I have 4 arrays and the data to populate the arrays will be coming form 4 different SharePoint lists. I am using jQuery to make the calls to the lists and to retrieve the data. I believe that the way I have done it is wrong because though the calls are successfully made the arrays are not populated by the time I use them. Here's an excerpt of the code:
var cacheNavData = [];
var cacheSubNavData = [];
var cacheMegaMenuData = [];
var cacheCategoryMenuData = [];
$(document).ready(function(){
getNavData();
getSubNavData();
getMegaMenuData();
getCategoryMenuData();
})
function getNavData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheNavData = data.d.results;
}
});
}
function getSubNavData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items?$select=parentNav/URL, parentNav/URLNAME,subLink&$expand=parentNav";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheSubNavData = data.d.results;
}
});
}
function getMegaMenuData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheMegaMenuData = data.d.results;
}
});
}
function getCategoryMenuData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var endPointUrl = "_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheCategoryMenuData = data.d.results;
}
});
}
console.log(cacheNavData);
console.log(cacheSubNavData);
console.log(cacheMegaMenuData);
console.log(cacheCategoryMenuData);
Now, I know that the problem is Asynchronous and I'm still trying to wrap my head around it. I've looked at several problems and explanations on this site. I've also looked at different articles and watched videos but I still don't fully get it. In this situation, I know that when I'm looking to check the data in the console.log(), the Ajax call has not returned the data yet. Through all of my readings, I have come to understand that. The part that I'm not getting is the fix or the how do I prevent that from happening. I tried the following to fix this problem but it didn't work. Maybe I did something wrong. Any help would be much appreciated. Thanks!
var cacheNavData = [];
var cacheSubNavData = [];
var cacheMegaMenuData = [];
var cacheCategoryMenuData = [];
$(document).ready(function() {
var cache1 = getData("Navigation", "cacheNavDataVar");
var cache2 = getData("Sub Navigation", "cacheSubNavDataVar");
var cache3 = getData("category menu", "cacheCategoryMenuDataVar");
var cache4 = getData("Mega Menu Category", "cacheMegaMenuDataVar");
$.when(cache1, cache2, cache3, cache4).done(function(results){
if(results){
createNavigation(cacheNavData)
}
})
});
I hope above highlighted line is self explanatory. If you call multiple ajax async : true requests then browser opens new tcp port for every request and as soon it get response from any request, it starts calling ajax success function.
I am new to js.
I am trying to call the API and save the data in a variable (obj = [])
But i go thru the console, my ajax call called two times. May i know why?
This is the console on my browser that i found out it is called two time:
Below is my code:
$(function (){
var obj = [];
var selected = $("select.dr-down option:selected").click().val();
var markup = '';
getAPI();
console.log('obj = ', obj);
function getAPI() {
$.ajax({
url: 'http://www.mocky.io/v2/5d73bf3d3300003733081869',
method: 'GET',
}).done(function (data) {
data.forEach(function (data) {
obj.push(data);
});
})
}
})
I am trying to call an API and get and display all orders and then for each order to call another endpoint which returns the details about the worker who has placed the order and display these details along with the order details.
Using Ajax, I call the first endpoint which returns all the order. I looped through all returned orders and display the details about each order. Inside the loop I call a function which take as parameter the WorkerId (getWorker(WorkerId). This function is created outside the for loop and contains another ajax call to the second API endpoint, which returns the details about the worker.
var app = {}; // creating a empty object to hold the data
// getAllOrders method will make the Ajax request to the API
app.getAllOrders = function() {
$.ajax({
url: 'https://www.hatchways.io/api/assessment/work_orders',
method: 'GET',
dataType: 'json',
data: {
format: 'json'
},
success: function(result) {
console.log('Ajax is working.');
app.displayAllOrders(result);
},
error: function(error) {
console.log('Something went wrong.');
console.log(error);
}
});
}; //end app.getAllOrders function
app.getAllOrders();
app.displayAllOrders = function(allOrders) {
console.log(allOrders);
// getWorker method will make the Ajax request to the API
app.getWorker = function(id) {
console.log('Ajax is working.');
$.ajax({
url: 'https://www.hatchways.io/api/assessment/workers/' + id,
method: 'GET',
dataType: 'json',
data: {
format: 'json'
},
success: function(result) {
console.log('Ajax is working.');
app.workersInfo(result);
},
error: function(error) {
console.log('Something went wrong.');
console.log(error);
}
});
}; //end app.getWorker function
// creating a method to inject our data into the DOM
app.workersInfo = function(worker) {
console.log(worker);
// Creating var for each piece of data for worker id
var comp = $('<p>').text(worker.worker.companyName);
var nameWorker = $('<p>').text(worker.worker.name);
var email = $('<p>').text(worker.worker.email);
var workerId = $('<p>').text(worker.worker.id);
var workerInfo = $('<div>').append(nameWorker, comp, email, workerId);
$('#allOrders').append(workerInfo);
}; //end app.workersInfo function
for (var i = 0; i < allOrders.orders.length; i++) {
// creating var for each piece of data for order
var id = $('<p>').text(allOrders.orders[i].id);
var nameOrder = $('<h3>').text(allOrders.orders[i].name);
var desc = $('<p>').text(allOrders.orders[i].description);
var deadline = $('<p>').text(allOrders.orders[i].deadline);
var workerId = $('<p>').text(allOrders.orders[i].workerId);
// appending in div all info for the order
var orderInfo = $('<div>').addClass('orderInfo').append(nameOrder, id, desc, deadline, workerId);
// appending in div all info for worker
$('#allOrders').append(orderInfo);
// call getWorker function to display worker
var myWorkerId = allOrders.orders[i].workerId;
app.getWorker(myWorkerId);
};
};
When getWorker(myWorkerId) is called, the Ajax call inside it is not called. This is called only after iterating through the loop is done. I tried with another function inside getWorker() instead of Ajax call and this is working. Please let me know if you can spot what I am doing wrong and how this can be fixed.
I am working on modifying a web application built by someone else a few years ago. In it, he built an API function in JS which when called, will pull data from SharePoint. I am adding a feature to the application, and will need to do another API call to retrieve some different data. So far, I haven't been able to figure out how to modify the code so that it waits for the ajax call to complete. All of the research that I have done indicates that I should be using a callback to accomplish this, but I am not sure how to implement it properly.
The existing code looks like this:
API = function(apiFunction, dataToPost, successCallback) {
var baseApiUrl = '/SomeWebApp/API/';
var apiUrl = baseApiUrl + apiFunction;
$.ajax({
url: apiUrl,
data: JSON.stringify(dataToPost),
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
dataFilter: function(data) { return data; },
success: successCallback,
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('Error calling webservice: ' + apiFunction);
}
});
}
And the call to the API is:
API('Lists.asmx/GetStuff', dataToPost, function(data) {
var options = [];
$.each(data.d, function(index, value) {
options.push(new Category(value.Field, value.AnotherField, value.YetAnotherField));
});
var viewModel = new ViewModel(options);
ko.applyBindings(viewModel);
});
What I need to do is perform the second API call to retrieve the rest of the data, and then create the view model, passing it both sets of data.
What I've tried:
Moving options outside of the callback function, but it seems that because it is asynchronous, the script isn't waiting for the data to be returned. If it did work, I could move ko.ApplyBindings outside of the callback function, and just create the new view model with both sets of data
Assigning the API call to a variable, and having the callback function return options. For example:
var x = API('Lists.asmx/GetStuff', dataToPost, function(data) {
var options = [];
$.each(data.d, function(index, value) {
options.push(new Category(value.Field, value.AnotherField, value.YetAnotherField));
});
return options;
});
What would be the best way to modify the code to accomplish this? Should I create a wrapper function that includes the API function as a callback? How would I put that together?
The quick and dirty solution is to put the second API call within the callback function of the first API call. Return statements really don't do anything in an async function unless it's returning a "promise" (see option 2).
API('Lists.asmx/GetStuff', dataToPost, function(data) {
var options = [];
$.each(data.d, function(index, value) {
options.push(new Category(value.Field, value.AnotherField, value.YetAnotherField));
});
API('Lists/asmx/GetStuff2', secondDataToPost, function(data2){
var viewModel = new ViewModel(options, data2);
ko.applyBindings(viewModel);
});
});
Option 2 - since your API function is already using jQuery to handle the ajax you can change it to return the result of the ajax call, a type of deferred object, on which you can call .done to attach a callback method instead. jquery-deferred-and-promise walkthrough
API = function(apiFunction, dataToPost, successCallback) {
var baseApiUrl = '/SomeWebApp/API/';
var apiUrl = baseApiUrl + apiFunction;
return $.ajax({
...
});
}
The returned deferred object can be used similarly to the passed in callback by using the .done method on the object.
API('Lists.asmx/GetStuff', dataToPost).done(function(data) {
callback stuff...
});
This is a little more flexible and can let you do chaining and simultaneous execution like the following where both api calls get sent at the same time instead of having to wait for the response from the first call before sending the second one.
$.when(
API('Lists.asmx/GetStuff', dataToPost),
API('Lists.asmx/GetStuff2', dataToPost2)
).done(function(data1, data2) {
var options = [];
$.each(data.d, function(index, value) {
options.push(new Category(value.Field, value.AnotherField, value.YetAnotherField));
});
var viewModel = new ViewModel(options, data2);
ko.applyBindings(viewModel);
});
I have a series of ajax calls that fill columns on a page.
var doneDefers = function(defer) {
// leftColDefer is another deferred that sets some header info
$.when(defer, leftColDefer).done(function(req1, req2){
var data = req1[0],
head = req2[0];
// spit this data out to elements on the page
});
};
for(i=0;i<window.ids.length;i++){
defer[i] = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
});
doneDefers(defer[i]);
}
This works fine. If an ajax call fails, nothing is spit out and all is right with the world.
Now I want to do some calculations based on all the data that got spit out.
$.when.apply(null, defer)
.done(function() {
var args = Array.prototype.slice.call(arguments);
calcDeltas();
})
.fail(function() {
var args = Array.prototype.slice.call(arguments);
console.log('in list fail');
});
The done function works fine none of the ajax calls fail. If one of them fail, I go into the fail function and I don't have access to any of the return data from the other runs. The arguments array only has the failed call's data.
I would like to do my calculations on the data sets that passed. How can I get to the data from the good calls when one of them fails?
I'm not sure this is the simplest solution but it stands a chance of working.
var ajax_always_promises = [],//to be populated with promises that (barring uncaught error) are guaranteed to be resolved.
data_arr = [],//an array to be (sparsely) populated with asynchronously delivered json data.
error_arr = [];//an array to be (sparsely) populated with ajax error messages.
$.each(window.ids, function(i, id) {
var dfrd = $.Deferred();
var p = $.ajax({
url: 'api/get_runs_stats.php',
type: 'GET',
dataType: 'json',
data: {
run_id: window.ids[i]
}
}).done(function(json_data) {
data_arr[i] = json_data;//intentionally not `data_arr.push(json_data);`
}).fail(function(jqXHR, textStatus, errorThrown) {
error_arr[i] = textStatus;//intentionally not `error_arr.push(textStatus);`
}).always(dfrd.resolve);
ajax_always_promises[i] = dfrd.promise();
doneDefers(p);
});
$.when.apply(null, ajax_always_promises).done(function() {
//The data in the (sparsely) populated arrays `data_arr` and `error_arr` is available to be used.
var i, id, success_count=0, error_count=0;
for(i=0; i<Math.max(data_arr.length,error_arr.length); i++) {
//Here, the index i corresponds to the original index of window.ids ...
//...that's the advantage of sparsely populating the arrays.
id = window.ids[i];
if(data_arr[i]) {
//Here, do whatever is required with `data_arr[i]`, and `id` if needed.
success_count++;
}
else if(error_arr[i]) {
//Here, do whatever is required with `error_arr[i]`, and `id` if needed.
error_count++;
}
}
console.log("Success:errors: " + success_count + ':' + error_count);
});
Untested - may well need debugging