jquery/json - create dynamic array for key - javascript

I didn't find out, how to create a json message in jquery with dynamic values for a key array element.
I'm trying to build a json message like this:
{
"line": {
"name": "Test",
"images": [
{
"order": "1",
"link": "https://google.com/1.jpg",
"name": "1.jpg"
},
{
"order": "2",
"link": "https://google.com/2.jpg",
"name": "2.jpg"
}
]
}
}
I fail to attach the pictures to the message.
jsonObbj = {};
line = {};
line ["name"] = $("#name").val();
counter = 1;
$("div.carousel_image > img").each(function() {
image = {};
image ["order"] = counter;
image ["name"] = $(this).attr('src');
line ["images"].push(image); // How can I edit this image to the images array
counter++;
});
// how can I add the line to the array
Thx for your help!

You need to initialize line.images to an empty array.
jsonObbj = {};
line = {};
line ["name"] = $("#name").val();
line["images"] = []; // add this line
counter = 1;
$("div.carousel_image > img").each(function() {
image = {};
image ["order"] = counter;
image ["name"] = $(this).attr('src');
line ["images"].push(image); // How can I edit this image to the images array
counter++;
});
Note, in general, when your object keys are normal strings, you want to use dot notation: line.images
JSFiddle: https://jsfiddle.net/to4xhewu/

You need to initialise line.images as an array before you can start pushing to it. You should also make sure you declare your variables properly with const, let or var or else they will be implicitly global.
Try this for a simple, object literal initialiser alternative
const jsonObbj = {
line: {
name: $("#name").val(),
images: $("div.carousel_image > img").map((i, img) => ({
order: i + 1,
name: img.getAttribute("src"),
link: img.src
})).get()
}
}
See https://api.jquery.com/map/

Related

Create a Listed (Nested) Element in a Javascript object

My question comes from this answer to a similar question. The comment below the answer sums up my question
how would the code look like if you would like to give depth to the tree? Like for name i would like to give name.firstname and name.lastname. Would I need to define name as var?
This is my current code
var jsonOutput = new Object();;
jsonOutput.workflowID=1234;
jsonOutput.author="jonny"
I want to create a javascript object that looks like the below. I am stuck with creating the list of Tools. How would I do this?
{
"workflowID": "1234",
"author": "jonny",
"tools": [
{
"toolid": "543",
"type": "input",
},
{
"toolid": "3423",
"type": "input",
},
{
"toolid": "1234",
"type": "merge",
"on": "Channel Name"
}
]
}
Create a data object
Populate the inner hierarchy with values
Add a tools array to data
Create tool object and populate
Push tool to the tools array
Repeat
var data = {};
data.workflowID = 1234;
data.author = "jonny";
data.tools = [];
let tool = {};
tool.toolid = 543;
tool.type = "input";
data.tools.push(tool);
tool = {};
tool.toolid = 3423;
tool.type = "input";
data.tools.push(tool);
tool = {};
tool.toolid = "1234";
tool.type = "merge";
tool.on = "Channel Name";
data.tools.push(tool);
console.log(data);
Technically, to create a more complex object, you can just do something like:
tool543 = new Object();
tool543.toolid = "543";
tool543.type = "input";
jsonOutput.tools = []; // Now .tools is an empty array
jsonOutput.tools.push(tool543); // And now you're appending to it.

assign value of a property of "clearsky" from "object" to weather so to pass through src in the image tag

The expected result is to first find weather string from array of object "objects" and then set value of "weather" variable equal to value of of clearsky value(i.e. link).
let weather = "clearsky";
const objects = [
{ "clearsky": "http://openweathermap.org/img/wn/11d#2x.png" },
{ "cloudy": "http://openweathermap.org/img/wn/19d#2x.png" },
{ "rainny": "http://openweathermap.org/img/wn/10d#2x.png" },
{ "sunny": "http://openweathermap.org/img/wn/12d#2x.png" },
];
//expected result is to first find weather string from array of object "objects" and then set value of weather equal to value of
weather = {
/* <img src={weather} alt=""/> */
};
I assume you would like to write some sort of function that displays your image corresponding to the right value (weather type) in your objects array.
I added these <img> tags (for displaying in your html).
<img id="img-clearsky">
<img id="img-rainy">
I changed the structure of your objects array a bit so that property values can be accessed in a simple way. I made a function that loops through your array and if it finds a match for your objects type, it uses the corresponding imgurl to load as src of the element with given id.
const objects = [{
"type": "clearsky",
"imgurl": "http://openweathermap.org/img/wn/11d#2x.png"
},
{
"type": "rainy",
"imgurl": "http://openweathermap.org/img/wn/10d#2x.png"
}
];
function displayImage(weatherType, elemid) {
const imgelem = document.getElementById(elemid); // Get img element by id.
// If element with given id exists.
if (imgelem !== null) {
// Loop through objects.
for (let i = 0; i < objects.length; i++) {
// Check if there is a match.
if (objects[i].type === weatherType) {
imgelem.src = objects[i].imgurl; // Fill up <img src> with corresponding url.
}
}
} else {
console.log(`No img with id: ${elemid} found.`);
}
}
// Call display with type and id.
displayImage('clearsky', 'img-clearsky');
displayImage('rainy', 'img-rainy');
There are multiple ways of doing this, but I would wrap this logic with a function - especially if you plan on splitting this into several constants.
const WeatherTypeImage = (weatherType = 'clearsky') =>
Object.assign(document.createElement('img'), {
src: {
"clearsky": "http://openweathermap.org/img/wn/11d#2x.png",
"cloudy": "http://openweathermap.org/img/wn/19d#2x.png",
"rainny": "http://openweathermap.org/img/wn/10d#2x.png",
"sunny": "http://openweathermap.org/img/wn/12d#2x.png",
}[weatherType],
alt: '',
})
document.querySelector('.js-container').appendChild(
WeatherTypeImage()
)
<div class="js-container"></div>
Or, if you would prefer to have an HTML string template:
const WeatherTypeImage = (weatherType = 'clearsky') => {
const src = {
"clearsky": "http://openweathermap.org/img/wn/11d#2x.png",
"cloudy": "http://openweathermap.org/img/wn/19d#2x.png",
"rainny": "http://openweathermap.org/img/wn/10d#2x.png",
"sunny": "http://openweathermap.org/img/wn/12d#2x.png",
}[weatherType]
return Object.assign(document.createElement('template'), {
innerHTML: `<img src="${src}" alt="">`
}).content
}
document.querySelector('.js-container').appendChild(
WeatherTypeImage()
)
<div class="js-container"></div>

Javascript - How to define Arrays inside an Object using Loops?

I'm trying to make a Pixel RPG game, and am a bit confused.
What I'm trying to do:
var character = {
gender: male,
age: 18,
action: walking,
direction: left,
skin: 0,
eyes: aqua,
hairStyle: 0,
hairColor: blue,
hat: 'cap'
};
ctx.drawImage(characterIMG.body[character.gender][character.skinColor], 0, 0);
ctx.drawImage(characterIMG.eyes[character.gender][character, 0, 0);
ctx.drawImage(characterIMG.hair[style0], 0, 0);
if(character.hat != "none"){
ctx.drawImage(characterIMG.hat['cap'], 0, 0);
}
How would I go about defining the images?
So far got here, but am mixed up..
var characterIMG = [male, female]; //I want some separate variables to just write in, in case I need to add more images of the same type, then I can just write the "type" in the variable instead of changing a bunch of stuff :)
for(var i in characterIMG){
characterIMG[i] = {
skin: [],
eyes: [],
hair: [],
accessories: []
}
}
Unless there is a more efficient way to do this?
Thanks!
--In short, I want to do this:
ctx.drawImage(characterIMG.body[character.gender][character.skinColor], 0, 0);
ctx.drawImage(characterIMG.eyes[character.gender][character], 0, 0);
ctx.drawImage(characterIMG.hair[style0], 0, 0);
..with characterIMG containing a huge database of all the relevant images (this)
Use an object and then just new up the object whenever you want to create a new instance of a character. With this, each character can inherit their properties from the main Object (via prototype) and become a separate entity within your game.
var Person = function(payload) {
this.name = payload.name;
this.age = payload.age;
this.gender = payload.gender;
};
Person.prototype.talk = function() {
return console.log('hello, I am ' + this.name);
}
var Person1 = new Person({
name : 'Amanda',
age : 18,
gender : 'Female',
});
var Person2 = new Person({
name : 'Sam',
age : 21,
gender : 'Make',
});
Person1.talk();
Person2.talk();
You can load a set of images as follows
// a list of image name comma delimited
const imageURLs = "image1.jpg,image2.jpg,image3.jpg";
// create an array of images
const myImageList = imageURLs.split(",").map(url => {
const image = new Image;
image.src = url;
return image;
});
If you have many images with different categories and subcategories then it will depend on how you organise the images on your file system. If you have one directory and all the images in that then each image's name should have some description of the image
body_dark_female.jpg
body_light_female.jpg
body_dark_male.jpg
body_light_male.jpg
head_dark_female.jpg
head_light_female.jpg
head_dark_male.jpg
head_light_male.jpg
And so on, or a better option is to set the various categories in directories
body/dark/female/jill.jpg
body/dark/male/tom.jpg
body/light/female/jill.jpg
body/light/male/tom.jpg
head/light/female/jill.jpg
head/light/male/tom.jpg
head/dark/female/jill.jpg
head/dark/male/tom.jpg
You can then use the name or directories to create the data structure
// using the directory structure
function loadImage(imageURL,images){
const cats = imageURL.split("/"); // split the cats into an array
// remove the last item as that is the image name
var name = cats.pop();
// remove the extension and add just the image name to the cats
cats.push(name.split(".")[0]);
// reference the base category
var currentCat = images;
cats.forEach(cat => { // for each category create the objects
if(currentCat[cat] === undefined){ // does this cat exist?
currentCat[cat] = {}; // no them create an object for it
}
currentCat = currentCat[cat]; // reference the category
});
// now create the image and add it to the object
currentCat = new Image;
currentCat.src = imageURL;
}
Then use the directory listing to create the list of images to load
const imageURLs = `
body/dark/female/jill.jpg
body/dark/male/tom.jpg
body/light/female/jill.jpg
body/light/male/tom.jpg
head/light/female/jill.jpg
head/light/male/tom.jpg
head/dark/female/jill.jpg
head/dark/male/tom.jpg
`;
Because the directory listing may be a bit unclean (spaces, tabs, linefeeds, etc) you should ensure each image name is valid
// remove tabs, groups of spaces and returns, and use linefeed to seperate them
const imagesURLClean = imageURLs.replace(/\t|\r| +?/g,"").split("\n");
// create the base category
const characterIMG = {};
// add the images
imagesURLClean.forEach(imageURL => loadImage(imageURL,characterIMG));
When that has run you can access the image as follows
ctx.drawImage(characterIMG.body.light.female.jill,0,0);
Or via strings
var part = "body";
var skin = "light";
var gender = "female";
var name = "jill";
ctx.drawImage(characterIMG[part][skin][gender][name],0,0);
The directory listing will create the following data structure
characterIMG = {
body : {
dark : {
female : {
jill : // the image
},
male : {
tom : // the image
},
},
light : {
female : {
jill : // the image
},
male : {
tom : // the image
},
}
},
head : {
dark : {
female : {
jill : // the image
},
male : {
tom : // the image
},
},
light : {
female : {
jill : // the image
},
male : {
tom : // the image
},
}
}
If your list is very long it may have missing items, during development it would pay to add a default category that will return an image appropriate for that category.
Thus you directory listing would look like
body/default.jpg // default
body/light/default.jpg // default
body/light/female/default.jpg // default
body/light/male/default.jpg // default
body/dark/default.jpg // default
body/dark/female/default.jpg // default
body/dark/female/jill.jpg
body/dark/male/default.jpg // default
body/dark/male/tom.jpg
// and so on
Then create a function that gets a image via category and if it has problems it will use the default image as far as it can find to fit the categories
function getImage(images, ...categories){
const count = 0;
var image = images
while(count < categories.length){
if(image[categories[count]] !== undefined){
image = image[categories[count++]];
}else{
return image.default;
}
}
return image;
}
Then you can draw an image as follows
ctx.drawImage(getImage(characterIMG,"body","dark","female","jill"),0,0);
// when you get the wrong referance
ctx.drawImage(getImage(characterIMG,"leg","dark","female","jill"),0,0);
// it will return characterIMG.default
// or
ctx.drawImage(getImage(characterIMG,"body","dark","female","bill"),0,0);
// as there is no female bill, it will return characterIMG.body.dark.female.default
This is how you define an array inside an object.
var characterIMG = {
male: {
skins: [],
hair: ["black", "brown"]
},
female: {
skins: [],
hair: []
}
};
console.log(characterIMG);
console.log(characterIMG["male"]["hair"]);
console.log(characterIMG.male.hair); //does the same

JS converting an array to a json linked list?

I am new to JS and the concepts of organising data elude me a little, trying to take data from a specific array format (as this is what I have to work with) and output it into another specific JSON format.
This is to pass data to the D3 sankey module
https://github.com/d3/d3-plugins/blob/master/sankey/sankey.js
I can't figure out is how to add the index of the node into the links, rather than the name.
Really I am just totally lost with it!
I made a fiddle here:
https://jsfiddle.net/adamdavi3s/kw3jtzx4/
Below is an example of the data and the output required
var data= [
{"source":"Agricultural 'waste'","target":"Bio-conversion","value":"124.2729"},
{"source":"Bio-conversion","target":"Electricity grid","value":"0.597"},
{"source":"Bio-conversion","target":"Losses","value":"26.862"},
{"source":"Bio-conversion","target":"Liquid","value":"280.322"},
{"source":"Losses","target":"Liquid","value":"280.322"}
];
var output= {
"nodes":[
{"name":"Agricultural 'waste'"},
{"name":"Bio-conversion"},
{"name":"Electricity grid"},
{"name":"Losses"},
{"name":"Liquid"}
],
"links":[
{"source":0,"target":1,"value":124.729},
{"source":1,"target":2,"value":0.597},
{"source":1,"target":3,"value":26.862},
{"source":1,"target":4,"value":280.322},
{"source":3,"target":4,"value":280.322}
]
};
Here is my code from the fiddle thusfar
var data=[{"source":"Agricultural 'waste'","target":"Bio-conversion","value":"124.2729"},
{"source":"Bio-conversion","target":"Electricity grid","value":"0.597"},
{"source":"Bio-conversion","target":"Losses","value":"26.862"},
{"source":"Bio-conversion","target":"Liquid","value":"280.322"},
{"source":"Losses","target":"Liquid","value":"280.322"}
];
var sourceArray=[];
for (var i=0; i <data.length; i++ ) {
var node= {"name":data[i].source};
var found = jQuery.inArray(node, sourceArray);
if (found < 0) {
// Element was not found, add it.
sourceArray.push(node);
}
}
console.log(sourceArray);
In javascript:
[ ] annotations are used to describe an Array, like:
var names=["John","Lisa"]
{ } Its are used to describe an Object
var person = {"name" : "John", "age" : 23}
You can use them inside one another
var people=[{"name" : "John", "age" : 23},{"name" : "Lisa", "age" : 44}]
Try this:
var data=[{"source":"Agricultural 'waste'","target":"Bio-conversion","value":"124.2729"},
{"source":"Bio-conversion","target":"Electricity grid","value":"0.597"},
{"source":"Bio-conversion","target":"Losses","value":"26.862"},
{"source":"Bio-conversion","target":"Liquid","value":"280.322"},
{"source":"Losses","target":"Liquid","value":"280.322"}
];
var sourceArray=[];
var linkArray=[];
for (var i=0; i <data.length; i++ ) {
var node= {"name":data[i].source,};
var link= {
"source":i,
"target":data[i].target,
"value":data[i].value,
};
var found = jQuery.inArray(node, sourceArray);
if (found >= 0) {
// Element was found, remove it.
sourceArray.splice(found, 1);
linkArray.splice(found, 1);
} else {
// Element was not found, add it.
sourceArray.push(node);
linkArray.push(link);
}
}
finalArray={"nodes": sourceArray,"links": linkArray}
console.log(finalArray);
https://jsfiddle.net/9x4rdyy7/
Array.reduce() is perfect for this use case ;)
Take a look.
var data=[{"source":"Agricultural 'waste'","target":"Bio-conversion","value":"124.2729"},
{"source":"Bio-conversion","target":"Electricity grid","value":"0.597"},
{"source":"Bio-conversion","target":"Losses","value":"26.862"},
{"source":"Bio-conversion","target":"Liquid","value":"280.322"},
{"source":"Losses","target":"Liquid","value":"280.322"}
];
var output = data.reduce(function(result, item){
for(key in search = ['source','target']) {
var value = item[search[key]];
if(! result.index.hasOwnProperty(value)){
result.index[value] = Object.keys(result.index).length;
result.nodes.push({name: value});
}
}
result.links.push({
source: result.index[item.source],
target: result.index[item.target],
value: Number(item.value)
});
return result;
}, {nodes: [], links: [], index: {}});
delete output.index;
console.log(output);

js each loop add one more depth to an object or array

I have this array of pages urls, now i need to make a hierarchy of out it.
So from this:
allPages = [
{ "url": "/polygon/color/red.html", "name": "Red" },
{ "url": "/polygon/color/blue.html", "name": "Blue" },
{ "url": "/polygon/shape/tri.html", "name": "Triangle" },
{ "url": "/weight/heavy.html", "name": "Heavy Item" }
];
To this:
siteMap = [
polygon:
color:
[{url:"red.html", name:"Red"}],
[{url:"blue.html", name:"Blue"}],
shape:
[{url:"tri.html", name:"Triangle"}],
weight:
[{url:"heavy.html", name:"Heavy Item"}],
];
The final structure can be object or array. But i can only use JS, not jQuery nor php.
EDIT: Changed Input data into array of objects. Sorry for making this harder.
Fiddle: https://jsfiddle.net/ss92kw4a/2/
several steps:
First we split the strings into arrays:
for(i in all){
all[i] = all[i].substring(1).split("/");
}
Next we do a recursive insertion:
function insert(o, a){
if(a.length == 0){return; }
if(!o[a[0]]){
o[a[0]] = {};
}
insert(o[a[0]], a.slice(1));
}
We start the recursion like this:
ans = {};
all.forEach(function(entry){
insert(ans, entry);
});
All done. The result tree is now in the ans object:
console.log(ans);
UPDATE: this code makes the last level an array: https://jsfiddle.net/ss92kw4a/3/
You may use something like this:
var allPages = [
"/polygon/color/red.html",
"/polygon/color/green.html",
"/polygon/color/blue.html",
"/polygon/shape/tri.html",
"/polygon/shape/rect.html",
"/weight/heavy.html",
"/weight/light.html"
];
var siteMap = {};
for (var i in allPages) {
var fragments = allPages[i].match(/[^\/]+/g);
if (!!fragments) {
var currentMember = siteMap;
for (var j in fragments) {
fragment = fragments[j];
if(!currentMember.hasOwnProperty(fragment)) {
currentMember[fragment] = {};
}
currentMember = currentMember[fragment];
}
}
}
Might be enhanced, notably in the fact that ending leaves are objects,
but it works.

Categories

Resources