My search bar is not synchronous with the YouTube API? - javascript

The YouTube API takes a very short amount of time for a request to its server to come back (In my case, I'm sending a search query). However, it's still too slow to make my program synchronous.
This is the Search Bar handler:
Template.search_bar.events({
'keypress #query' : function (evt,template) {
// template data, if any, is available in 'this'
if (evt.which === 13){
var url = template.find('#query').value;
$("#query").val('');
//YoutubeAPI calls go here
Template.list.search_get(url);
Links.insert({sess:Template.list.my_playlist_id,youtube_link:Session.get("search_results").items[0].snippet.title});
}
}
});
And this is what carries out the GET call:
Template.list.search_get= function(str){
var request = gapi.client.youtube.search.list({part:'snippet',q:str});
request.execute(function(response) {
str = JSON.stringify(response.result);
str = JSON.parse(str);
Session.set("search_results",str);
});
}
The top search result is displayed in a list, however the result is always displayed one result behind. Meaning the first search will yield undefined because the Session variable wouldn't have updated by that time, the second search will yield the results of the first search, and so on.
Any input on how I could go about resolving this would be great.

You don't need to use Session for this one. Try moving the Links.insert routine to your request callback, and things should start to look better ;)

Related

Rest API Search Results is not the same as the results returned by the search page

I have A search rest API, when I run it through Share point Designer, i don't Get the Same Number if results as Returned by the Search page on the Share point site, I have tried Using different Source ids , also tried to use the default source id from results source but I always get the same results so i am not sure what I am doing wrong.
My Other Thought is, IS there a way to Get all the results From the Default search function Built in to Share-point?
var ct = new SP.ClientContext.get_current();
var keywordQuery = new Microsoft.SharePoint.Client.Search.Query.KeywordQuery(ct);
var queryStr = ctx.DataProvider.get_currentQueryState().k;
keywordQuery.set_queryText(queryStr);
keywordQuery.set_trimDuplicates(false);
keywordQuery.set_enableSorting(true);
keywordQuery.set_sourceId=("xxxxxx-xxxx-xxxx-xxx-xxxxxxx");
keywordQuery.set_rowLimit(500);
keywordQuery.set_trimDuplicates(false);
var searchExecutor = new Microsoft.SharePoint.Client.Search.Query.SearchExecutor(ct);
var results = searchExecutor.executeQuery(keywordQuery);
ct.executeQueryAsync(onQuerySuccess, onQueryFail);
function onQuerySuccess()
{
results.m_value.ResultTables[1].ResultRows.forEach(function (row)
{
var Aname1 = row.name;
console.log(row);
if (!$isNull(Aname1))
{
var name= Aname1;
console.log(name);
}
});
}
function onQueryFail()
{
}
Usually, the results are paginated. What it means is that, instead of returning all the results at once, they are divided into parts and each part (page) is sent once.
For example, when you search in google.com, instead of returning all 1,50,00,000.... results, Google returns only 10 results or so. To get the next 10 results, you click the next button in the pagination menu at the bottom of the page.
This is done so that the API and network don't get overloaded. Imagine how large a response with 1,50,00,000 records would be.
This is what's happening with you. In the response you recieved, see if there's a record with a URL for the next page, Microsoft usually does things this way. If you call that URL, you'll get the next page. If that's not there, see if the URL you called has a parameter somewhere, where you can select the page.

Right way or method Do While If Condition set inside loop?

I can't figure out the right way to do that:
I'm calling external API for products and I get a response I want to add those products to my database and if the response contains a next_page url loop it again until there is no next_page left
Here is what I came up with:
var products = api.ProductsActive('GET', {includes: 'Images', limit: 1});
requestProducts = function(){
products.results.forEach(function(product){
var sameproduct = apiProducts.findOne({listing_id: product.listing_id});
if (sameproduct) {
console.log('found sameproduct');
return;
}
//Add userId to current product so we can assosicate products belong to "X" user
var productExtend = _.extend(product, {userId: Meteor.userId()});
apiProducts.insert(productExtend);
});
//If there is next page get the next page number and get products
var nextPage = products.pagination.next_page;
if (nextPage !== null) {
products = api.ProductsActive('GET', {includes: 'Images', page: nextPage, limit: 1});
console.log(products);
}
};
//loop at least once, and then if more pages found
do {
requestProducts();
}
while (products.pagination.next_page !== null);
Which doesn't seems to work right I'm not sure if this is the right method for such function I really help your input! Please help me figure out the right way for this!
Keep in mind javascript is asynchronous, so you need to handle your loop with callbacks instead of do. The reason for this is requestProducts likely uses a callback and the javascript interpreter doesn't "wait" for requestProducts() to finish running before it runs the next line of code.
You haven't provided any details of how the api works so I have to generalise.
If requestProducts() takes a parameter as a callback (which it should), use that to re-run itself:
var callback = function(err, result) {
if(products.pagination.next_page !== null) requestProducts(callback);
};
requestProducts(callback);
You would have to check the your api's documentation to check how the callback is defined but it would be something like the above where err is returned if there is a problem.
How this works is, when requestProducts is called the callback fires and if its not the last page to repeat itself until ..next_page == null

Javascript: multiple events, one ajax request

I'm somewhat new to JS and I'm trying to think of the best way to design some asynchronous interaction in an application I'm working on.
I've got a list of records that are related to some live API-backed data. I show the user a list of these records, and the user can select specific records that they want to see more information about. I load this additional data from the API via an ajax call.
To make this a more real world example, let's say what I have is a list of stocks. I've got the name and yesterday's closing price for each stock. There's a check box next to each stock name, and if the user checks this box it plots the historic price of the stock for the past year on a graph.
When the user selects one stock in the way, the behavior is simple. I send one API request for the historical data for one stock, and I plot it on the graph.
However, the user might select a bunch of stocks at once, or in rapid succesion. I don't want to fire 10 or 20 or 50 requests back-to-back, I want to make one request for 10 or 20 or 50 stock histories.
Let's say my application has an event listener that looks up the stock history when the check box is toggled, something like this:
$('input.stock_toggle').change( function(event){
var symbol = $(this).data('symbol');
lookupStockHistory(symbol);
});
How could I define a lookupStockHistory function, or some other kind of event listener etc., that would wait a second and pool all the events that came in to send a single request instead of firing many times in row?
var lookupStockHistory = (function () {
"use strict";
var qeue = [], timeoutHandler = null, timeoutTime = 1000,
sendCall = function () {
//process qeue array and trigger ajax call
//and clean qeue
qeue = [];
},
add = function (symbol) {
if (timeoutHandler) {
clearTimeout(timeoutHandler);
timeoutHandler = null;
}
qeue.push(symbol);
timeoutHandler = setTimeout(sendCall, timeoutTime);
};
return add;}());
To trigger just call lookupStockHistory(symbol). This will gather symbol to array which will be processed after 1 second since last call
You can use push your request into a "global variable" with your namespace, and then use setTimeout to delay the AJAX call (a second or two maybe?).
The setTimeout would call a function that gets the requests from the "global variable", empties the variable, and then constructs your request. Any subsequent calls to the setTimeout function would see that the "global variable" was empty and not construct future AJAX requests.
In the example below, I also remove the current pending timeout as a new one has been initiated.
Here's a pseudo-code example using jQuery for selection and event capture:
var DELAY_FOR_INPUT = 2000; // 2 seconds
var g_MyDataToRequest = [];
var g_currentAJAXCallTimeout = null;
function _callAPI = new function() {
g_currentAJAXCallTimeout = null;
var dataToGet = g_MyDataToRequest;
g_MyDataToRequest = []; // clear out global request cache
// TODO: Loop over dataToGet and construct AJAX request
// TODO: Perform AJAX call...
}
$('.myCheckbox').click(function() {
var myRequest = $(this).attr("ID"); // or Val(), or whatever you'd like to track your item
g_MyDataToRequest.push( myRequest );
// If have a pending request, kill it
if (g_currentAJAXCallTimeout != null) {
clearTimeout(g_currentAJAXCallTimeout);
g_currentAJAXCallTimeout = null;
}
g_currentAJAXCallTimeout = setTimeout( _callAPI, DELAY_FOR_INPUT );
});
This is, as noted, pseudocode and may not quite work right, but it should get you going.
You could implement a timer and start it with the first click or change event. And with each additional click or change event you can reset the timer. Also, with each event you can add or remove the symbol value to an array accordingly. Once the timer expires, you join the array to be a comma-delimited string and post that back via ajax and get a JSON result.

How to avoid repeated requests in textbox, textarea interacting with server

In Javascript, does someone/anyone have a exhaustive list of key combination to avoid. For example a textbox sending webservice requests for each keypress. It often happens for key combinations like HOME[for cursor returning to start of textbox] , DELETE, SHIFT + HOME + DELETE the event fires and same request params is sent to webservice.[I know caching query results will solve for this scenario but what about other]. I would love to see a list for this, i couldn't find a similar question before hence this
Update:
Since the earlier question title seemed too way off and likely closable i changed it. I would like to know how to optimize this process of sending request in ajax manner less intensive.
Assuming the user is writing in a textarea or input, you can check the value of that element for each keystroke; if it's different from its last value, send it to the server. If it's the same, then do nothing.
Example:
function updateOnKeypress(input) {
var lastValue;
input.addEventListener('keypress', function() {
if( input.value.trim() !== lastValue ) {
// trim() isn't available in every browser, but you can add it
// Of course, if leading/trailing whitespace is supposed to trigger
// a request, then skip the trim()
lastValue = input.value.trim();
// … send value to server
}
});
}
You might also want to throttle the number of requests with a timer, so not every change results in a request to the server. For instance, for each change start a timeout (say, 0.3 seconds), and then send the value when the timer executes.
function updateOnKeypressDelayed(input) {
var lastValue, timer;
input.addEventListener('keypress', function() {
if( !timer ) {
timer = setTimeout(function () {
if( input.value.trim() !== lastValue ) {
lastValue = input.value.trim();
timer = null;
// … send value to server
}
}, 300);
}
});
}
Instead of avoiding all those combinations, why don't you just limit what you accept.
For example make a JS function that checks if this is a character, letter or special character, if not then do not submit to server.

Request to Asp page misses if called very fast

I have a website with is made in classic asp. On one page there are 5 textboxes and 5 labels. When users type some value in the textbox then using javascript (added on Onchange event) another asp page is called which done some calculations, fetches some database values based on the value typed and return the result to caller page to be displayed in the corresponding label. Same Page is called for all the textboxes for fetching result. My problem is if user types at normal speed and move to other textbox(using tab) at a normal speed the second page is called properly and result displayed properly in labels, but if the user type very fast then the request for the value of one textbox is not completed and other is send and as a result there is no result value coming for first one. Is there is any way to handle this.
Thanks
If you don't want to refactor the whole thing to use XHRequests, there's a simple solution. Have a "request in progress" flag that is checked in your onchange event. If a request is in progress, queue the current action. In the result display code, check the queue and execute the next action, if any. If there are no remaining actions, reset the flag.
Here's a basic outline in code:
var requestInProgress = false;
var pendingActions = [];
function OnChangeHandler(onChangeFunction) {
if(requestInProgress) {
pendingActions.push(onChangeFunction);
}
else {
requestInProgress = true;
onChangeFunction();
}
}
function ResponseHandler()
{
//Your regular response handling code
if(pendingActions.length > 0) {
var nextFunction = pendingActions.shift();
nextFunction();
}
else {
requestInProgress = false;
}
}
I'm no JS expert, so I'm sure that this could be cleaned up a little bit, but it should handle overlapping events just fine.

Categories

Resources