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
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 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!!
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.
I have written a UserScript for Greasemonkey (Firefox) and am testing it for compatibility with Chrome's Tampermonkey, and getting errors in the developer console:
Uncaught TypeError: Cannot read property 'profile_url' of undefined
Uncaught TypeError: Cannot read property 'encoded_name' of undefined
The errors seem to be referencing the onreadystatechanged callback of GM_xmlhttpRequest which is called like this:
var flairs = document.querySelectorAll('span.flair');
var steam_re = /(?:(?:https?:\/\/)?www\.)?(?:steam|pc)(?:community\.com\/?(?:(id|profiles)\/?)?|[\s\-_]*id)?[\/:\s\|]*(.{2,}?)(?:[\/|:\-\[(] ?(?:\/?(?:ghost|enforcer|tech|mm|master))+[\[)]?)?$/i
function get_text(e) { return e.innerText || e.textContent; }
function set_text(e, t) {
if (e.innerText)
e.innerText = t;
else
e.textContent = t;
}
var parser = new DOMParser();
for (var i = 0; i < flairs.length; i++) {
var text = get_text(flairs[i]);
var match = steam_re.exec(text);
if (match == null || match.length < 3)
continue;
var type = match[1] || 'id';
var name = encodeURIComponent(match[2]);
var url = 'http://steamcommunity.com/' + type + '/' + name;
var xml_url = url + '?xml=1';
GM_xmlhttpRequest({
method: 'GET',
url: xml_url, // Link to a steam profile with ?xml=1 added
accept: 'text/xml',
context: {
flair_index: i,
flair_text: text, // textContent of span element
encoded_name: name,
profile_url: url, // Link to steam profile
query_url: xml_url
},
onreadystatechange: function(response) {
if (response.readyState != 4)
return;
// Attempt to fall back to alternate forms of context,
// none of which works. response.context works on Firefox/Greasemonkey.
var context = response.context || this.context || context;
var doc = parser.parseFromString(response.responseText, 'text/xml');
var validProfile = doc.documentElement.nodeName == 'profile';
var a = document.createElement('a');
a.href = validProfile ?
context.profile_url : // TypeError here, context is undefined
('http://steamcommunity.com/actions/SearchFriends?K=' + context.encoded_name);
a.className += (validProfile ? 'steam-profile-link' : 'steam-profile-search-link');
var a_text = document.createTextNode(context.flair_text);
a.appendChild(a_text);
set_text(flairs[context.flair_index], '');
flairs[context.flair_index].appendChild(a);
}
});
}
The function itself is called fine, and the callback is invoked, but once I try to access the context var inside it, it's undefined.
It all works as expected in Firefox. What it does is iterating over span elements that have the "flair" class and checking with a regex if they contain a Steam username, and if so, makes it a link to their SteamCommunity page. (Full source on github). The script runs on /r/PaydayTheHeistOnline.
I have tested using an array defined outside the function to store the data instead of using the context property passed to xmlhttpRequest, but I'm getting the exact same error.
Update:
Tampermonkey now reports that this feature is fixed as of version 3.8.4116 (in beta at the moment). See:
The bug report
The change log
Older/generic workaround:
The context property is a relatively new feature of GM_xmlhttpRequest(), in Firefox. I doubt it's been implemented in Tampermonkey yet; see Tampermonkey's docs for GM_xmlhttpRequest().
Meanwhile, the tried-and-true method for this kind of thing is to use a closure.
Change your GM_xmlhttpRequest() call to something like:
( function (flair_index, flair_text, encoded_name, profile_url, query_url) {
GM_xmlhttpRequest ( {
method: 'GET',
url: xml_url, // Link to a steam profile with ?xml=1 added
accept: 'text/xml',
onreadystatechange: function (response) {
if (response.readyState != 4)
return;
var doc = parser.parseFromString (response.responseText, 'text/xml');
var validProfile = doc.documentElement.nodeName == 'profile';
var a = document.createElement ('a');
a.href = validProfile ?
profile_url :
('http://steamcommunity.com/actions/SearchFriends?K=' + encoded_name);
a.className += (validProfile ? 'steam-profile-link' : 'steam-profile-search-link');
var a_text = document.createTextNode (flair_text);
a.appendChild (a_text);
set_text (flairs[flair_index], '');
flairs[flair_index].appendChild (a);
}
} );
} ) (
i,
text, // textContent of span element
name,
url, // Link to steam profile
xml_url
);
I need a way to replace part of a string with another string using Google Apps Script. I tested the following and it worked:
function test(){
var value = 'https://plus.google.com/117520727894266469000';
var googleimageURL = googlePlus(value);
Logger.log('Returned Result: ' + googleimageURL);
}
function googlePlus(value){
var apiKey = ScriptProperties.getProperty('apiKey');
var re = 'http://'
var theURL = value;
Logger.log('Google+ is called: ' + value);
var replacingItem = 'https://';
var theURL = theURL.replace(re, replacingItem);
Logger.log('Google+ Values 2: ' + value + ' : ' + theURL + ' after ' + replacingItem);
return imageURL;
}
But, when I embedded into the following code, it did not work. Any idea?
//If a Google+ column was not specified,put a flag.
if (googleColumn && column == googleColumn) {
if (value == ""){
columns.push(nogoogleColumn);
values.push(flag);
var googleimageURL="";
} else {
var googleimageURL = googlePlus(value);
Logger.log('Returned Result: ' + googleimageURL);
}
}
The script did not work as I wish. It seems to stop at line:
var theURL = theURL.replace(re, replacingItem);
Additional information: Google notified me with the following message
onFormSubmit
TypeError: Cannot find function replace in object https://plus.google.com/117520727894266469000. (line 536) formSubmit
I found the mistake. It is Type Error. value in the second block is not a "string", while the first block is a "string". Hence to fix the second block, I need to use:
var value = value.toString();
before passing to googlePlus(value)