I am currently running a for loop that takes in A users data for the item name and colour for a clothing product he wishes to purchase..
I am creating a loop to run as many times as the amount of items the user specifies/ putts in..
This loop goes to a JSON url, and looks for an item name using a keyword finder (.includes)
once it finds the array with the specified item name, it takes a value from that array called id, this id is applied to the websites url and it takes you directly to that item.
Then once it gets to that Item It loads the HTML source and parses it from string.
Inside this html data there is a list that has all the items colors listed. It then finds the specified color inside a (li).
Inside that li with the color there is another url, it takes that url and goes to it. And that is the final step.. it succesfully goes to the item that the user wanted..
It does this in a loop with each item until there are none left.
Here is the problem...
When I console and log everything It should work perfectly.
But for some odd reason It always loads the console perfectly,
(console logs all the urls for each item in its proper order)
But for some reason It just goes to the url of the last item.
Im pretty sure a solution to this would be to use async/ await. But.. Im not sure were to put it so It would go to each url in its order..
Here is the code:
function loadHTMLSource(urlSource){
xhttp = new XMLHttpRequest();
xhttp.open("GET", urlSource, false);
xhttp.send();
return xhttp.response;
}
function finder() { // do I put async function finder here?
var json_url = "http://www.example_shop.json";
var xhr = new XMLHttpRequest();
xhr.open("GET", json_url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var resp = JSON.parse(xhr.responseText);
for (i=0; i < data.count; i++) {
var item = data.task[atc_count][0].split(' - '); // splits the item name and color
const searchStr = item[0]; // item name
const lowerSearchStr = searchStr.toLowerCase();
const foundItem = resp.products.find( another category
({ name }) => name.toLowerCase().includes(lowerSearchStr));
console.log(searchStr);
console.log(foundItem);
var id = (getValues(foundItem, 'id', ''));
//atc_count += 1;
//loop += 1;
//var url = []
//url[i] = ("https://shopping_example/shop/" + id);
var url = ("https://shopping_example/shop/" + id);
chrome.tabs.query({currentWindow: true, active: true}, function (tab){
chrome.tabs.update(tab.id, {url: url}); // the url of the users specified item, but default first color, parses this html to get its color url below
})
console.log(i);
//i += 1;
console.log(i);
console.log(url);
var page_html = loadHTMLSource(url);
parser = new DOMParser()
my_document = parser.parseFromString(page_html, "text/html");
search_str = (item[1]); // the color
search_attr_name = "style-name";
var all_styles = my_document.querySelectorAll("[style-name]");
atc_count += 1;
loop += 1;
matching_url = "";
//atc_count += 1;
//loop += 1;
if(all_styles.length){
all_styles.forEach(function(e){
var style_name = e.attributes[search_attr_name].value;
if(style_name.length && style_name.toLowerCase().indexOf(search_str) > -1) {
if(typeof e.attributes["href"].value !== "undefined"){
color = e.attributes["href"].value
}
}
});
console.log(color);
var color_url = ("https://www.shopping_example.com" + color);
chrome.tabs.query({currentWindow: true, active: true}, function (tab){
chrome.tabs.update(tab.id, {url: color_url}); // final url the url of the item with the users specified color
})
console.log(color_url);
//i += 1;
//window.open(color_url);
}
}
my Main question is:
Where would I put async and await in this code to make it go to each url (temporary delay(add to cart process would go here))
and go to the next url and do the same as a loop
I found this but I cant really understand how to implement it into my script:
https://javascript.info/async-await
I would really appreciate If someone could post an example with async and await to go to each url
Thank You <3!!
Related
I'm trying to get post id of image and then get specific size of image.
If I give hardcode single image url then it works fine but if I give url through variable then it returns 0.
It is strange behaviour
here is function
function get_image_id_and_size($image_url)
{
//return $image_url;
$image_id = attachment_url_to_postid($image_url);
return $image_id;
$image_large = wp_get_attachment_image_src($image_id, 'large');
return $image_large[0];
}
and here is javascript code
var picture = document.querySelectorAll(".active");
for (var i = 0; i < picture.length; i++)
{
var src = picture[i].src;
if (typeof src !== 'undefined')
{
var res;
if (src.includes('bedbase') && src.includes('12in_'))
{
var imgurl = src.split('12in_');
var imgres = imgurl[1].split('-');
var orgurl = imgurl[0] + "12in_" + currentcolor + ".png";
//console.log(orgurl);
res = <?php echo get_image_id_and_size(orgurl); ?>;
console.log(res);
//picture[i].src = res;
}
}
}
I checked if I return the urls it works, as you can see I commented that return line. But it don't get the post id it returns 0.
But if I give hardcode single link in argument then it works and returns post id.
I had a similar problem where the domain did not have a www. but the file url did, and that would return a 0.
I'm looking to build an app that searches for a person by name - I have achieved this part - and displays the person name. The second part of the app should also present more details for each person on click (this information should be retrieved from a second URL. Lastly the app should also inject an image when I click on that person. I haven't been able to make this work.
Can you guy help fix this or shine a light?
I have commented out what I have been trying to do.
https://codepen.io/edmonteiro/pen/qKeMLj
document.getElementById("subBtn").onclick = function(event){
//prevent default submission
event.preventDefault();
//grab the typed value in the text box
var name = document.getElementsByClassName("name")[0].value;
//Alternatively give an "id" attribute to the text box in the HTML
//for example, <input type="text" name="textboxname" class="name">, use:
//var name = document.getElementById("textboxname").value();
let ourRequest = new XMLHttpRequest();
//pass this search value as a parameter in URL to get results from database
ourRequest.open('GET', 'https://izrite.com:5555/leads?page=1&name=' + name, true);
//function to call when the AJAX request is completed
ourRequest.onload = function(){
//if request completed successfully
if(ourRequest.status === 200){
let ourData = JSON.parse(ourRequest.responseText);
let list = document.getElementById("list");
//process only if request returned a valid JSON data
if(typeof ourData === 'object'){
//if there are 1 or more results found
if(ourData.length > 0){
list.innerHTML = "<p><b>Matched names from database:</b></p>";
//for each `lead` in the array, print its name
for(lead of ourData){
list.innerHTML += "<p>Name: " + lead.name + "</p>";
/*-----------------------------------------------------------------*/
/* Second and third part of the test - to be continued. Not finished before the 5hours time frame mentioned on the challenge specs*/
// if((lead.id).value()==="0009bd06-a9ce-470e-b13a-acd2aaaa42d4"){
// let ourRequest2 = new XMLHttpRequest();
// ourRequest2.open('GET', 'https://izrite.com:5555/lead/0009bd06-a9ce-470e-b13a-acd2aaaa42d4', true);
// let moreDetails = document.getElementById('moreDetails');
// let ourData2 = JSON.parse(ourRequest2.responseText);
// if(typeof ourData2 === 'object'){
// //if there are 1 or more results found
// if(ourData2.length > 0){
// moreDetails.innerHTML = "<p><b>More details</b></p>";
// //for each `lead` in the array, print its name
// for(detl of ourData2){
// moreDetails.innerHtml += "<p>Name: " + detl.name + "</p><br><p>Make: " + detl.make + "</p><br><p>Model: " + detl.model + "</p><br><p>Derivative: " + detl.derivative + "</p>";
// // var myImage = new Image(100, 200);
// // myImage.src = 'https://izrite.com:5555/image/71890';
// // document.body.appendChild(myImage);
// }
// }
// }
// }
// ourRequest2.send();
/*-----------------------------------------------------------------*/
};
}else{
//no results found for this search query
list.innerHTML = "<p><b>No match found in database!</b></p>";
}
}else{
//response not in JSON format
list.innerHTML = "<p><b>Response is not in valid JSON format!</b></p>";
}
}
}
//send the AJAX request
ourRequest.send();
}
As far as I can understand your question, you want to type in the search box, hit "Search" and get the matched results from your database via AJAX.
Here is the JavaScript that works: (Remove your javascript in your CodePen and paste this to see it working.)
document.getElementById("subBtn").onclick = function(event)
{
//prevent default submission
event.preventDefault();
//grab the typed value in the text box
//getElementsByClassName is used because in your HTML, the text box has no "id" attribute
var name = document.getElementsByClassName("name")[0].value;
//if you give an "id" attribute to the text box in your HTML
//for example, <input type="text" name="textboxname" class="name">, use:
//var name = document.getElementById("textboxname").value();
let ourRequest = new XMLHttpRequest();
//pass this search value as a parameter in URL to get results from database
ourRequest.open('GET', 'https://izrite.com:5555/leads?page=1&name=' + name, true);
//function to call when the AJAX request is completed
ourRequest.onload = function()
{
//if request completed successfully
if(ourRequest.status === 200)
{
let ourData = JSON.parse(ourRequest.responseText);
var list = document.getElementById("list");
//process only if request returned a valid JSON data
if(typeof ourData === 'object')
{
//if there are 1 or more results found
if(ourData.length > 0)
{
list.innerHTML = "<p><b>Matched names from database:</b></p>";
//for each `lead` in the array, print its name and id
for(lead of ourData)
{
list.innerHTML += "<p>Name: " + lead.name + "<br />Id: " + lead.id + "</p>";
}
}
else
{
//no results found for this search query
list.innerHTML = "<p><b>No match found in database!</b></p>";
}
}
else
{
//response not in JSON format
list.innerHTML = "<p><b>Response is not in valid JSON format!</b></p>";
}
}
}
//send the AJAX request
ourRequest.send();
}
The forEach callback takes the current value as the first parameter and index as the second. Try:
ourData.forEach((element, index) => {
document.getElementById("app").innerHTML = `<p>${element.name}</p>`;
});
Try this
ourData.forEach((element, index) => {
document.getElementById("app").innerHTML += <p>${element.name}</p>;
});
innerHTML +=
Add to the HTML on each cycle.
My receive() function parses through data from a backend server and I use that data to create a renderHTML() function which displays the parsed data as an HTML string. I get the data to display and can also attach checkboxes perfectly fine. I am trying to get the value of questionid so that when the user clicks on the checkbox, I can use Ajax to send the values of which question was selected, which can be done by questionid. I am not sure on how to get the value of the questionid, store it, and send it through Ajax.
function receive() {
var text = document.getElementById("text").value;
var data = {
'text': text
};
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var ourData = xhr.responseText;
var parsedData = JSON.parse(ourData);
console.log(parsedData);
renderHTML(parsedData);
}
};
xhr.open("POST", "URL", true);
xhr.send(JSON.stringify(data));
}
var questionid;
function renderHTML(data) {
var htmlString = "";
for (i = 0; i < data.length; i++) {
htmlString += "<p><input type='checkbox' value='data[i].questionid'>" +
data[i].questionid + "." + "\n";
htmlString += '</p>';
}
response.insertAdjacentHTML('beforeend', htmlString);
var t = this;
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].onclick = function() {
if (this.checked) {
console.log(this.questionid.value);
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var Data = xhr.responseText;
console.log(Data);
var parseData = JSON.parse(Data);
};
xhr.send(JSON.stringify(data));
}
}
}
There are many ways in which you can achieve what you are looking for. For that, you will need to understand one of two concepts:
bind
closures
None of them is easy to understand for beginners but will help you vastly improve your coding skills once you get them. You can read about them here and here respectively.
The problem with your code (amongst other details) is that the value of i is global, and so by the time the DOM is rendered and the user can click in one of the checkboxes, all the checkboxes have the same value of i (the last one).
bind helps you solve this by setting an argument to the function that will always remain the same.
closures help you solve this by storing the value of a variable declared in a scope that is accessible only from a function that stores a reference to that variable.
Here is some code I wrote that does what you want using a most modern syntax, which I would highly recommend.
Specially, I would recommend you to read about the fetch api; which is a much cleaner way to make http request.
This code does what you are looking for:
function receive() {
const text = document.getElementById('text').value;
const options = {
method: 'POST',
body: JSON.stringify({ text })
}
fetch("<the url here>", options)
.then( response => response.json())
.then( data => {
renderHTML(JSON.parse(data));
})
}
function renderHTML(data){
for (const x of data) {
const content = x.questionid;
// i'm asuming that the response html element already exists
response.insertAdjacentHTML('beforeend', `<p><input value="${content}" type="checkbox">${content}</p>`);
}
document.querySelectorAll('input[type="checkbox"]').forEach( input => {
input.addEventListener((e) => {
const options = {
method: 'POST',
body: JSON.stringify(e.target.value)
};
fetch('<the second url here>', options).then( response => response.json())
.then( data => {
// 'data' is the response you were looking for.
})
})
})
}
I'm trying to rewrite my code to utilize promises correctly.
The full program is supposed to scrape the data from a tshirt site. This first block of code is supposed to enter the front page of the site, grab the product pages that are immediately available and then store the URL's in an array. The remainder URL's will be stored in 'remainder' for a secondScrape to be performed later on.
Currently manually unit testing each section:
//TASK: Create a command line application that goes to an ecommerce site to get the latest prices.
//Save the scraped data in a spreadsheet (CSV format).
//Modules being used:
var cheerio = require('cheerio');
var request = require('request');
//harcoded url
var url = 'http://shirts4mike.com/';
//url for tshirt pages
var urlSet = new Set();
var remainder;
const requestPromise = function(url) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, html) {
if(error) return reject(error);
if(!error && response.statusCode == 200){
return resolve(html);
}
});
});
}
function firstScrape (url) {
return requestPromise(url)
.then(function(html) {
var $ = cheerio.load(html);
var links = [];
//get all the links
$('a[href*=shirt]').each(function(){
var a = $(this).attr('href');
//add into link array
links.push(url + a);
});
return links;
// return this array you've made
});
}
function nextStep (arrayOfLinks) {
var promiseArray = [];
for(var link in arrayOfLinks){
promiseArray.push(requestPromise(link));
return Promise.all(promiseArray);
}
}
function lastStep (arrayOfHTMLresults){
for(var html in arrayOfHTMLresults){
var $ = cheerio.load(html);
//if page has a submit it must be a product page
if($('[type=submit]').length !== 0){
//add page to set
urlSet.add(scrapeLink);
} else if(remainder == undefined) {
//if not a product page, add it to remainder so it another scrape can be performed.
remainder = scrapeLink;
}
}
console.log(urlSet);
console.log(remainder);
}
firstScrape(url)
.then(nextStep)
.then(lastStep);
I'm currently getting the following error:
(node:71094) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Invalid URI "0"
This is the code I'm trying to promisify:
// Load front page of shirts4mike
function firstScrape(){
request(url, function(error, response, html) {
if(!error && response.statusCode == 200){
var $ = cheerio.load(html);
//iterate over links with 'shirt'
$('a[href*=shirt]').each(function(){
var a = $(this).attr('href');
//create new link
var scrapeLink = url + a;
//for each new link, go in and find out if there is a submit button.
//If there, add it to the set
request(scrapeLink, function(error,response, html){
if(!error && response.statusCode == 200) {
var $ = cheerio.load(html);
//if page has a submit it must be a product page
if($('[type=submit]').length !== 0){
//add page to set
urlSet.add(scrapeLink);
} else if(remainder == undefined) {
//if not a product page, add it to remainder so it another scrape can be performed.
remainder = scrapeLink;
}
}
});
});
}
});
}
What I can't work out is how can I use urlSet.add(scrapeLink); in lastStep() when it doesn't know what scrapeLink is?
Any idea why? Thank you
.add() is not an Array.prototype method, you also return promiseArray within for loop instead of pushing a Promise to promiseArray and using Promise.all()
function nextStep (arrayOfLinks) {
var promiseArray = [];
for(var i = 0; i < arrayOfLinks.length; i++) {
var link = requestPromise(arrayOfLinks[i]);
promiseArray.push(link);
}
return Promise.all(promiseArray)
}
UPDATE due to question changing:
So from firstScrape() you could return a results Object instead of just an array of links:
return { scrapeLink: link, result: links }
You would then get that in nextStep() as the result of the promise where you could return something with the same shape again:
return { scrapeLink: firstStepResult.scrapLink, result: Promise.all(promiseArray) }
Then in lastStep() instead of arrayOfHTMLresults getting passed in you would then have an Object which would look like:
{ scrapeLink: "http://someurl.com", result: arrayOfHTMLresults }
PREVIOUS answer:
You will need to initialize your variable in the for...in loop. e.g. with const, var or let depending on your use case and JS version.
for(var link in arrayOfLinks){
promiseArray.add(requestPromise(link));
return promiseArray;
}
I'm trying to make a menu with artist names and images pulled from the last.fm API. Currently, it generates the list of images and names fine, except it prints "undefined" at the top of the list. I've tried commenting out the part that populates the elements with artist names/images, and just had it generate the elements, but it still prints undefined. I'm totally stumped as to what it's saying is undefined.
First it makes an AJAX call to get the information it needs:
if (window.XMLHttpRequest) { // Non-IE browsers
httpRequest = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE 8 and older
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
httpRequest.open("GET", 'http://ws.audioscrobbler.com/2.0/?method=chart.gettopartists&api_key=b25b959554ed76058ac220b7b2e0a026&format=json', true);
httpRequest.onreadystatechange = function () {
var done = 4, ok = 200;
// Parse the JSON into JavaScript immediately on receipt
if (httpRequest.readyState == done && httpRequest.status == ok) {
artistList = JSON.parse(httpRequest.responseText);
Then it processes that information and generates HTML that it implements with inner.HTML
var artistsAndImage = {};
for (var i=0; i < artistList["artists"]["artist"].length; i++) {
var name = artistList["artists"]["artist"][i]["name"];
artistsAndImage[name] = artistList["artists"]["artist"][i]["image"][0]["#text"];
};
var code;
// Generate HTML for sidebar with artist names and iamges
for (var name in artistsAndImage) {
nameid = name.
replace(/ /g, "_").
replace(/&/g, ":amp").
replace(/\+/g, ":plus");
code += "<element id=\"" + nameid + "\" onclick=\"details(this)\">\n<p style = \"cursor:default\">\n <img src=\"" + artistsAndImage[name] + "\" alt=\"alt\" width = \"50\" height = \"50\">\n" + name + "\n</p> </element>\n";
};
document.getElementById("sidebar").innerHTML = "<div style = \"padding:20px\">" + code + "</div>";
Where's the "undefined" coming from, and how can I fix it? You can see the current incarnation of the page uploaded here: http://test.yukot.corp.he.net/
Instantiate your var code; with an empty string:
var code = '';
At first glance, I can see three possible causes of the undefined showing up, either artistList["artists"]["artist"][i]["image"][0]["#text"] doesn't always exist (this line artistsAndImage[name] = artistList["artists"]["artist"][i]["image"][0]["#text"];)After that, you define a variable, code, but its value is (automatically) set to undefined, you don't initialize it to a string: var code = ''; should solve that. An other explanation is your looping through the object, without checking if the property you're processing is defined on the instance itself:
var code = ''; //initialize code to empty string
for (var name in artistsAndImage)
{
if (artistsAndImage.hasOwnProperty(name))
{
code += 'First string';
//only process those that are instance properties
}
}
To be absolutely sure, you could check for undefined, too:
var code = '';
for (var name in artistsAndImage)
{
if (artistsAndImage.hasOwnProperty(name) && artistsAndImage[name] !== undefined)
{
//only process those that are instance properties
}
}
Try this in your console:
var code;//code is set to undefined
code += 'part of a string';
console.log(code);//logs: undefinedpart of a string