how to Dynamically generate JSON in a loop with Js? - javascript

I'm making a project with PebbleJS.
i'm a noob and i'm learning little by little..so after recieving a JSON from a webpage and put all the data in localStorage objects, i want to put my variables in a UI.Menu Window, which is basically a JSON variable as you can see in example below:
var main = new UI.Menu({
sections: [{
items: [
{
title: 'street name a',
subtitle: 'ID 1121'
}, {
title: 'street name b',
subtitle: 'ID 1431'
}, {
title: 'street name c',
subtitle: 'ID 1907'
},{
title: 'street name d',
subtitle: 'ID 1002'
},{
title: 'street name e',
subtitle: 'ID 1330'
},
]
}]
});
i tried to make a loop cycle inside but gives me error...(pseudocode)
for (var x=0;x<10;x++)
{
title: localStorage.title+x,
subtitle: 'ID '+localStorage.title+x
}
i need to make this with no jQuery or other JS Frameworks, only pure javascript...

if i understand you question correctly, you want to create the data-structure from your first code example through a loop.
the data structure is a object with some properties and sub-objects like arrays. the structure just defines objects in your code. there is no json involved.
json is a subset of javascript which is used to interchange data-structures. it consists of plain text files with just javascript object declarations and is usually parsed to create a data-structure in memory. by declaring your data-structure in code there is no need to use an additional json-parsing step.
to setup the initial structure as above you would do:
var data = {
sections: [
{
items: []
}
]
}
than you would get the items array:
var items = data.sections[0].items
to this array you can add the items with your loop:
for ( var x = 0; x < 10; x++ ) {
var item = {
title: localStorage.title + x,
subtitle: 'ID ' + localStorage.title + x
};
items.push(item);
}
now you can build your UI.Menu with the data-object.
var main = new UI.Menu(data)

Related

Adding to a Multidimensional Array in Javascript

I have a multidimensional array that I am creating from a JSON Ajax call to my DB.
With in my Web App, I am trying to dynamically add a new row to the array using javascript along the lines of:
list[new_row_id].item_id = new_value ;
list[new_id].item_title = new_title ;
Clearly I am doing something wrong.
Any guidance would be appreciated.
Adding an element to the end of an array is done with the push-function:
array.push({"item_id": 10101, "item_title": "new title"});
If you meant "new_id" and "new_row_id" to be the same and it differs from an index starting from 0, because the keys are individual database keys, then you can solve it that way:
var any_db_id = 33;
var new_title = 'new title';
list[any_db_id] = {
item_id: any_db_id,
title: new_title
}
That will result in a JSON looking like that:
{
1: {
item_id: 1,
title: 'Entry coming from database 1'
},
5: {
item_id: 5,
title: 'Entry coming from database 2'
},
33: {
item_id: 33,
title: 'new title'
}
}
If the new_id and new_row_id are still same but it is actually just an index (each item has 0, 1, 2 and so on as key), then you should use the solution of Virendra Katariya.

Unfolding array of values into distinct categories

I have a JSON object(array) coming from a sharepoint table and I need to restructure the rows, but having a bit of a struggle (I'm fairly beginner in JS).
I have something like this:
[{'ID':'1', 'Title': 'First record', 'blue':'3', 'red':'6', 'yellow':'2'},
{'ID':'2', 'Title': 'Second record', 'blue':'1', 'red':'3', 'yellow':'6'}]
and I need to transform it into:
[{'ID':'1', 'Title': 'First record', 'category':'blue', 'count':'3'},
{'ID':'1', 'Title': 'First record', 'category':'red', 'count':'6'},
{'ID':'1', 'Title': 'First record', 'category':'yellow', 'count':'2'},
{'ID':'2', 'Title': 'Second record', 'category':'blue', 'count':'1'},
{'ID':'2', 'Title': 'Second record', 'category':'red', 'count':'3'},
{'ID':'2', 'Title': 'Second record', 'category':'yellow', 'count':'6'}]
What I'm trying to achieve:
Create separate rows to 'unlold' three category fields (blue, red, yellow), so one row becomes three
Preserve other fields in each newly created row (ID, Title)
I'm trying to reformat this data so that I can feed the array into Dimple/D3 chart to create a categorised chart showing value counts for each category.
I tried doing for...each and doing loops inside of loops and _.map from examples I've found, but not getting the output I'm after (debugging in browser is a pain, so not sure where the code fails for me :/ ). Would you be so kind as to show an example of how to do this manipulation properly (probably Underscore's .chain .each and .map)? Preferably without arrow functions (I need to make it work in IE11).
Thank you in advance!
It can be done by rebuilding new object collection; here is a sample;
var myData = JSON.parse('JsonString');
var transformedData = [];
myData.forEach(function(data){
transformedData.push({ ID: data.ID, Title: data.Title, category: "blue", count = data.blue });
transformedData.push({ ID: data.ID, Title: data.Title, category: "red", count = data.red });
transformedData.push({ ID: data.ID, Title: data.Title, category: "yellow", count = data.yellow });
});
var transformedJson = JSON.stringify(transformedData);
Remember JSON names should use double quotes " not single quotes '.

Two Way Link Using Normalizr

I have a list of regions, which I get from an API. In this list, there are multiple buildings. This will look like this in JS:
const regions = [
{
guid: 'REGION1-GUID',
name: 'Region 1',
buildings: [
{
guid: 'REGION1-BUILDING1-GUID',
name: 'Region 1 Building 1'
},
{
guid: 'REGION1-BUILDING2-GUID',
name: 'Region 1 Building 2'
}
]
},
{
guid: 'REGION2-GUID',
name: 'Region 2',
buildings: [
{
guid: 'REGION2-BUILDING1-GUID',
name: 'Region 2 Building 1'
},
{
guid: 'REGION2-BUIDLING2-GUID',
name: 'Region 2 Building 2'
}
]
}
];
Now I want to normalize this JS Object using normalizr. What I want to do later is to get the region from a building.
So I tried to do the following:
// Define the buildings schema
const building = new schema.Entity('building', {}, { idAttribute: 'guid' });
// Define the regions schema
const region = new schema.Entity(
'regions',
{
buildings: [building]
},
{ idAttribute: 'guid' }
);
const regionList = [region];
const normalizeData = () => {
const normalizedData = normalize(data, regionList);
This does normalize my object, the normalizedData is like this:
{
"entities":{
"building":{
"REGION1-BUILDING1-GUID":{
"guid":"REGION1-BUILDING1-GUID",
"name":"Region 1 Building 1"
},
"REGION1-BUILDING2-GUID":{
"guid":"REGION1-BUILDING2-GUID",
"name":"Region 1 Building 2"
},
"REGION2-BUILDING1-GUID":{
"guid":"REGION2-BUILDING1-GUID",
"name":"Region 2 Building 1"
},
"REGION2-BUIDLING2-GUID":{
"guid":"REGION2-BUIDLING2-GUID",
"name":"Region 2 Building 2"
}
},
"regions":{
"REGION1-GUID":{
"guid":"REGION1-GUID",
"name":"Region 1",
"buildings":[
"REGION1-BUILDING1-GUID",
"REGION1-BUILDING2-GUID"
]
},
"REGION2-GUID":{
"guid":"REGION2-GUID",
"name":"Region 2",
"buildings":[
"REGION2-BUILDING1-GUID",
"REGION2-BUIDLING2-GUID"
]
}
}
},
"result":[
"REGION1-GUID",
"REGION2-GUID"
]
}
But to get the Region of a building i need to iterate over every region and check if the building is contained in the list. I will not get any added value trough the normalization.
It would be perfect if I am able to link in both direction. Every region entitiy has a list of building guids and every building has one region guid.
Is there any way to archieve this in normalizr? What would be the best approach?
Thank you for your help.
I tried some things and found a working solution. I don't know if there is any better approach, but it's very clean code and it's working.
I just had to change the definition of the building entity to:
// Define buildings schema
const building = new schema.Entity(
'building',
{},
{
idAttribute: 'guid',
processStrategy: (entity, parent) => ({ ...entity, regionGuid: parent.guid })
}
);
This will add the property "regionGuid" to the building which holds the guid from the region.

Prevent Javascript function running out of memory because too many objects

I'm building a web scraper in nodeJS that uses request and cheerio to parse the DOM. While I am using node, I believe this is more of a general javascript question.
tl;dr - creating ~60,000 - 100,000 objects, uses up all my computer's RAM, get an out of memory error in node.
Here's how the scraper works. It's loops within loops, I've never designed anything this complex before so there might be way better ways to do this.
Loop 1: Creates 10 objects in array called 'sitesArr'. Each object represents one website to scrape.
var sitesArr = [
{
name: 'store name',
baseURL: 'www.basedomain.com',
categoryFunct: '(function(){ // do stuff })();',
gender: 'mens',
currency: 'USD',
title_selector: 'h1',
description_selector: 'p.description'
},
// ... x10
]
Loop 2: Loops through 'sitesArr'. For each site it goes to the homepage via 'request' and gets a list of category links, usually 30-70 URLs. Appends these URLs to the current 'sitesArr' object to which they belong, in an array property whose name is 'categories'.
var sitesArr = [
{
name: 'store name',
baseURL: 'www.basedomain.com',
categoryFunct: '(function(){ // do stuff })();',
gender: 'mens',
currency: 'USD',
title_selector: 'h1',
description_selector: 'p.description',
categories: [
{
name: 'shoes',
url: 'www.basedomain.com/shoes'
},{
name: 'socks',
url: 'www.basedomain.com/socks'
} // x 50
]
},
// ... x10
]
Loop 3: Loops through each 'category'. For each URL it gets a list of products links and puts them in an array. Usually ~300-1000 products per category
var sitesArr = [
{
name: 'store name',
baseURL: 'www.basedomain.com',
categoryFunct: '(function(){ // do stuff })();',
gender: 'mens',
currency: 'USD',
title_selector: 'h1',
description_selector: 'p.description',
categories: [
{
name: 'shoes',
url: 'www.basedomain.com/shoes',
products: [
'www.basedomain.com/shoes/product1.html',
'www.basedomain.com/shoes/product2.html',
'www.basedomain.com/shoes/product3.html',
// x 300
]
},// x 50
]
},
// ... x10
]
Loop 4: Loops through each of the 'products' array, goes to each URL and creates an object for each.
var product = {
infoLink: "www.basedomain.com/shoes/product1.html",
description: "This is a description for the object",
title: "Product 1",
Category: "Shoes",
imgs: ['http://foo.com/img.jpg','http://foo.com/img2.jpg','http://foo.com/img3.jpg'],
price: 60,
currency: 'USD'
}
Then, for each product object I'm shipping them off to a MongoDB function which does an upsert into my database
THE ISSUE
This all worked just fine, until the process got large. I'm creating about 60,000 product objects every time this script runs, and after a little while all of my computer's RAM is being used up. What's more, after getting about halfway through my process I get the following error in Node:
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
I'm very much of the mind that this is a code design issue. Should I be "deleting" the objects once I'm done with them? What's the best way to tackle this?

Programmatically Set Constructor Parameters in Javascript

I am trying to interact with a javascript api (bare in mind I have never done this before). An example of what I am attempting to work with is here:
SearchSpring.Catalog.init({
leaveInitialResults : true,
facets : '.leftNav',
results : '#results',
result_layout: 'list',
results_per_page : 12,
layout: 'top',
loadCSS: false,
filters: {
color: ['Blue']
},
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens']
},
maxFacets: 5,
maxFacetOptions: 10,
sortText: 'Sort By ',
sortType: 'dropdown',
filterText: 'Refine Search Results',
previousText: 'Previous',
scrollType: 'scroll',
scrollTo: 'body',
backgroundSortField: 'price',
backgroundSortDir: 'desc',
compareText: 'Compare Items',
summaryText: 'Current Filters',
showSummary: true,
subSearchText: 'Subsearch:',
showSubSearch: true,
forwardSingle: false,
afterResultsChange: function() { $('.pagination').hide(); },
filterData: function(data) { console.debug(data); }
});
In the example I want to add a "backgroundFilter" to this with a value:
var cat="MyNewCategory";
cat.value="ANewValue;
How would I add this category and value to the backgroundFilters: listed above?
This is a very common framework initialization pattern when working with frameworks.
Your example code is passing a JavaScript Object {} as a parameter into a function () that is called init.
Taking out all definitions the pattern looks like this:
SomeFramework.frameworkFunction({});
In the above code the {} is an empty object used for initialization. There are two ways that you can work with that object in practice.
Regarding your first code snippet, you can add code into that 'object literal'.
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens'],
cat: ['My value']
},
Notice the added comma, this is an important tripping point. This may or may not fit your needs, depending on a few factors.
Regarding your second code snippet, you can apply members to JavaScript objects at runtime. What I mean is, your var cat can be added to the anonymous object-literal that is being passed in. Hard to say, but a simple concept. Here is how:
//Say this is initialized in some separate way. //There is a bug here I'll describe later.
var cat="MyNewCategory";
cat.value="ANewValue";
//Extract and name the initialization object. It is verbatim at this point.
var initObject = {
leaveInitialResults : true,
facets : '.leftNav',
results : '#results',
result_layout: 'list',
results_per_page : 12,
layout: 'top',
loadCSS: false,
filters: {
color: ['Blue']
},
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens']
},
maxFacets: 5,
maxFacetOptions: 10,
sortText: 'Sort By ',
sortType: 'dropdown',
filterText: 'Refine Search Results',
previousText: 'Previous',
scrollType: 'scroll',
scrollTo: 'body',
backgroundSortField: 'price',
backgroundSortDir: 'desc',
compareText: 'Compare Items',
summaryText: 'Current Filters',
showSummary: true,
subSearchText: 'Subsearch:',
showSubSearch: true,
forwardSingle: false,
afterResultsChange: function() { $('.pagination').hide(); },
filterData: function(data) { console.debug(data); }
};
//Now we can add variables (and functions) dynamically at runtime.
initObject.cat = cat;
//And pass them into the framework initialization in a separated way.
SearchSpring.Catalog.init(initObject);
Now for the bug. I don't know the solution because I do not know what it is intended to do, but I can point out what is potentially incorrect.
var cat="MyNewCategory";
cat.value="ANewValue;
This code is: 1 creating a String Object called cat. 2 changing the value to a new string.
I do not think this is what you really want.
To add a new backgroundFilter, in the separated way above, it would be:
initObject.backgroundFilters.cat = ['A', 'B'];
//Line above would give you this type of definition within the initObject (at runtime):
backgroundFilters: {
category: ['Shirt', 'Shoes'],
department: ['Mens'],
cat: ['A','B']
},
For this to work it will depend on what the framework is expecting regarding backgroundFilters.
Hope that helps.
All the best!
Nash
I don't quite understand - do you want to have the backgroundFilters categories as structured objects rather than plain strings? If you are in control of the entire API, you can do something like
...
backgroundFilters: {
category: [
new SearchSpring.Catalog.Category("Shirt"),
new SearchSpring.Catalog.Category("Shoes"),
new SearchSpring.Catalog.Category("MyNewCategory", "ANewValue")
],
department: 'Mens'
}
...

Categories