I have urls like this:
data:
{
"zip": 442,
"code": "AG",
"capital": "london",
"currency": {
"code": "XCD",
"name": "East"
"link": "https://en.wikipedia.org/wiki/",
"url": "https://en.wikipedia.org/"
}
I want to write an if statement that checks if the object starts with a 'https:' and then tell it what to do.
This is what I have, but it doesn't make my urls clickable or returns its data.
if (jsonObject.startsWith("http://")) {
const text = document.createElement("a");
k.textContent = jsonObject;
k.setAttribute("href", jsonObject);
j.appendChild(k);
You're close I believe, you just aren't accessing the actual values inside of the object.
If you want to check the Object's properties values and if they start with http/https you can loop through the object and use the same check.
jsonObject.values.forEach((value) => {
if(value.startsWith("https://") {
const text = document.createElement("a");
k.textContent = value;
k.setAttribute("href", value);
j.appendChild(k);
}
});
Related
I am having trouble trying to present an array of objects on the tooltip of an Anychart.js map. I understand that we can access the dataset by doing something like: %[name of property in data set]. My data set has the following form:
{
"country": "Austria",
"id": "AT",
"continent": "Europe",
"songs": [
{
"rank": 33,
"title": "Stuck with U (with Justin Bieber)",
"artists": "Ariana Grande, Justin Bieber",
"album": "Stuck with U",
"explicit": 0,
"duration": "3:48"},
{
"rank": 34,
"title": "Late Night",
"artists": "Luciano",
"album": "Late Night",
"explicit": 0,
"duration": "3:20"
},
... more objects
]
}
}
If I wanted to access the Country property I would simply add it to the tooltip by doing:
tooltip.format("Country: " + {%country});
The issue is when trying to access an array of objects, I have tried different variations and none of them worked. Trying to show the title of every song:
tooltip.format({%songs}.{%title});
tooltip.format({%songs.%title});
tooltip.format({%songs}[{%title}]);
I also saw in the documentation that we can send a function as argument so I tried the following where I would concatenate every title of the collection but did not succeed either:
tooltip.format(function() {
let concatenated = '';
this.songs.forEach(song => {
concatenated += song + ' ';
});
return concatenated;
});
I would really appreciate your help guys.
String tokens do not support nested objects/properties. But you can use the callback function of the formatted to get access to songs. The context prototype includes getData() method provides that. Like this:
series.tooltip().format(function() {
console.log(this.getData('songs'));
return 'tooltip';
});
For details, check the live sample we prepared.
In case any one else is looking for a solution to this answer. I figured out how to loop through an embed array, and call on specific information.
chart.edges().tooltip().format(function () {
var format = ''
var songs = this.getData('songs');
songs.forEach(function (data, builtin, dom) {
format = '<p>'+data['title']+' by '+data['artists']+' </span></p>' + format
});
console.log(format)
return format
});
Disclaimer: I know some Java but almost nothing about Javascript and have about 2 days to fix someone else's issues, of which this is one small part.
I have a nested array. I know the shop number, but need to get an array of only the parts in that shop.
"shops": [
{
"shopID": "15231",
"city": "Anytown",
"state": "MO",
"inventory": [
{
"description": "filter",
"partnumber": "MGL57047",
"shelf": "Z",
},
{
"description": "filter",
"partnumber": "84060",
"shelf": "A",
}
},
{
"shopID": "15232",
"city": "Springfield",
"state": "IL",
"inventory": [
{
"description": "filter",
"partnumber": "MGL57048",
"shelf": "B",
},
{
"description": "filter",
"partnumber": "84061",
"shelf": "A",
}
}
Here's what I tried:
const enteredShopID = '15231' // This isn't hard-coded in my app.
// Pull the list of all consumables for the current shop
var currentShop = application.data.shops.filter(s => s.shopID == enteredShopID)
This gets me an array with the shop and all of the inventory for that shop, but I need an array of the inventory. I tried
var currentShop = application.data.shops.inventory.filter(s => s.shopID == enteredShopID)
but that didn't work. Really, I'm just fumbling here. Is there a way to make the latter statement work, and somehow refer to the shopID of the parent?
Just use map() after the filter.
var currentShop = application.data.shops
.filter(s => s.shopID == enteredShopID)[0]
// checking if the current shop is actually null because no shops matched the ID
var currentShopInventory = (currentShop || {}).inventory || []
or use find()
// Note: If you use find(), there's a chance that there is no matching object
// So you'll have to check for that before you access the "inventory" key
// Otherwise you'll get "Cannot access 'inventory' of null"
var matchingShop = application.data.shops
.find(s => s.shopID == enteredShopID)
// Doing the checking here using an "or" if the matchingShop is null
var currentShop = matchingShop || {}
var currentShopInventory = currentShop.inventory || []
I'm trying to create a function that when called will update a specific object in json file. However, it updates the object as well as creating a new one.
I've tried many different methods in trying to get this to work, but all have failed. The closest I've got to it working is the code shown below, but it still doesn't do what is required.
This is my function:
var fs = require('fs');
var _ = require("underscore");
module.exports = {
personalUpdate: function (id, forename, surname, dob, gender, callback) {
let rawdata = fs.readFileSync('data.json');
let data = JSON.parse(rawdata);
let filtered = _.where(data['students'], { id: id });
let all = filtered[0];
all.forename = forename;
all.surname = surname;
all.dob = dob;
all.gender = gender;
data["students"].push(all);
fs.writeFileSync('data.json', JSON.stringify(data, null, 2), (err) => {
if (err) throw err;
});
callback("success");
}
}
And this is the JSON file that I want to update:
{
"teachers": [
{
"name": "",
"email": "",
"password": "",
"formGroup": "",
"id": ""
}
],
"students": [
{
"surname": "test",
"forename": "test",
"dob": "",
"homeAddress": "",
"homePhone": "",
"gender": "",
"tutorGroup": "",
"schoolEmail": "",
"grades": [
{
"french": 8,
"maths": 7
}
],
"id": ""
},
{
"surname": "test2",
"forename": "test2",
"dob": "",
"homeAddress": "test2",
"homePhone": "",
"gender": "",
"tutorGroup": "",
"schoolEmail": "",
"grades": [
{
"french": 9,
"maths": 8
}
],
"id": ""
}
]
}
I had to remove and change the objects and info inside them, as it contained confidential information.
When running this function, it finds the object that is specified in the parameter. It then updates that object, but it then creates another object at the bottom of the original JSON object, which it is not supposed to.
Also, is there a better way to update the specific objects in the JSON file?
tl;dr
The result set is duplicating because you are pushing it into the array
The change is being applied due to the variables holding the same object reference, so they are being mirrored across objects that share the same pointer.
Explanation
It creates a new one due to the data["students"].push(all); instruction.
When you manipulate objects in javascript you need to be aware of how the reference between them work, so you can avoid bugs and use them in your benefit.
For example, take this set of instructions:
let a = {"x": 1};
let b = a;
b.x = 3;
console.log(a) // it will output {"x": 3}
Notice that we:
Create an object with the prop x equal 1 and assign it to the variable a
Initialize a variable b with the value of a
Change the property x on the variable/object b
Then we can observe that the change was also reflected in the variable a, due to the object reference.
So, basically this is exactly what is happening with your instructions when you do all.forename = forename; it changes the variable all, but also the original object which it derives from.
Here is a nice reference that explains this concept more in-depth
#EDIT
I strongly advise you not using the sync version of functions like readFileSync since this blocks the event loop. Here is the official guidelines about it
I am having trouble to display the top tracks of a searched artist using the LastFM api to get data. The api returns an object toptracks. I would like to grab details about each of the top tracks from that api data.
I am not sure if I am on the right track. Can someone take a look and let me know if I am doing something wrong?
Sample data from api:
{
"toptracks": {
"track": [{
"name": "Best I Ever Had",
"playcount": "3723918",
"listeners": "1086968",
"mbid": "00bde944-7562-446f-ad0f-3d4bdc86b69f",
"url": "https://www.last.fm/music/Drake/_/Best+I+Ever+Had",
"streamable": "0",
"artist": {
"name": "Drake",
"mbid": "b49b81cc-d5b7-4bdd-aadb-385df8de69a6",
},
"#attr": {
"rank": "1"
}
},
{
"name": "Forever",
"playcount": "1713492",
"listeners": "668998",
"url": "https://www.last.fm/music/Drake/_/Forever",
"streamable": "0",
"artist": {
"name": "Drake",
"mbid": "b49b81cc-d5b7-4bdd-aadb-385df8de69a6",
},
"#attr": {
"rank": "2"
}
}
}
function renderTracks(trackArray) {
function createHTML(track){
return `<h1>${track.name}</h1>
<h2>${track.artist[0]}</h2>
<h3>${toptracks[1].rank}</h3>
<h3>${track.playcount}</h3>`;
};
trackHTML = trackArray.map(createHTML);
return trackHTML.join("");
};
var searchString = $(".search-bar").val().toLowerCase();
var urlEncodedSearchString = encodeURIComponent(searchString);
const url = "lastFMwebsite"
axios.get(url + urlEncodedSearchString).then(function(response) {
// createHTML.push(response.data.track);
// $(".tracks-container").innerHTML = renderTracks(response.data.track);
// comented out old code above
createHTML.push(response.toptracks.track);
$(".tracks-container").innerHTML = renderTracks(response.toptracks.track);
})
I've notice that you have not parsed the response:
axios.get(url + urlEncodedSearchString).then(function(response) {
var parsed = JSON.parse(response);
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks.track)
});
Another correction that I can suggest is to change the track.artist[0] to track.artist["name"] once this property returns an object instead of an array.
And about this: <h3>${toptracks[1].rank}</h3>. You will be not able to access that property because at your function you are providing just the trackproperty.
In this case you have two options: provide the whole response array or add a new parameter providing this.
function renderTracks(trackArray) {/**...*/};
//...
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks)
Or
function renderTracks(trackArray, toptracks) {/**...*/};
//...
$(".tracks-container").innerHTML = renderTracks(parsed.toptracks.track, parsed.toptracks)
I hope this can help you :)
Your input JSON is not valid. You'll need to format it correctly. Once the data is correct:
createHTML.push(response.toptracks.track[0])
or
let i = 0;
for(; i < response.toptracks.track.length; i++){
createHTML.push(response.toptracks.track[i]);
}
Let's imagine that we have sap.m.UploadCollection and we bind the data to this collection which is done like this:
bind: function () {
this._oUploadCollection.bindAggregation("items", {
path: "/attachments",
factory: jQuery.proxy(this._bindUploadCollectionItem, this)
});
},
The example of the binding data is here:
{
"attachments": [
{
"size": 123,
"filename": "pdf.pdf",
"id": "pdfId"
},
{
"size": 440,
"filename": "text.txt",
"id": "textId"
}
],
"source":"personWhoAddedAttachments"
}
So, in _bindUploadCollectionItem I successfully can get size, filename and id by oContext.getProperty("nameOfParameter"), but cannot get source:
_bindUploadCollectionItem: function (sID, oContext) {
return new sap.m.UploadCollectionItem({
"id": oContext.getProperty("id"),
"fileName": oContext.getProperty("filename"),
"attributes": [
{
"title": "author",
"text": oContext.getProperty("../source") // <- problem
}]
});
},
So, because I bind attachments it is kind of clear that I could not get source, but how to reach it if I need it?
It depends a little on what property of the model you want to get to. If it is really like you described it and the target property is in the /source absolute model path, then the easiest way of getting it inside the factory function is by using: oContext.getModel().getProperty("/source").
If you need something which is inside a collection (and somehow depends on the current context), you can achieve an effect similar to the .. path construct that you tried by using something along the lines:
var sPath = oContext.getPath(),
sParent = sPath.substring(0, sPath.lastIndexOf("/")),
sText = oContext.getModel().getProperty(sParent + "/source");
return new sap.m.UploadCollectionItem({
"id": oContext.getProperty("id"),
"fileName": oContext.getProperty("filename"),
"attributes": [{
"title": "author",
"text": sText
}]
});
You basically obtain the parent object path by searching for the last / inside the path. You can apply this repeatedly (or use a split, pop some elements, followed by a join) to get to the ancestors (e.g. parent of parent).