Storing JSON: Javascript vs HTML - javascript

I'm get a json object from an Ajax request like this:
"items":[
{
"id":923,
"id_str":"608475747557236737",
"uid":407388514,
"date":"Wed Jun 10 03:28:17 +0000 2015",
"status":0,
},
{
"id":923,
"id_str":"608475747557236737",
"uid":407388514,
"date":"Wed Jun 10 03:28:17 +0000 2015",
"status":0,
}
]
I loop the json object and generate HTML elements.
My question is if Is best store the json information in each HTML element such us: data-prop1="", data-prop2="" etc, o i keep the data in a javascript var like array?
The information of the HTML element will be send via Ajax request to the server again, so i want to store and restore to send.

From a performance point of view it is far better to store it in a variable instead of directly on your HTML elements
DOM operations are expensive (selecting/accessing that HTML element
which holds the data).
It's also the most cross-browser compatible way
since data attributes only apply on HTML5 browsers
It also easier to console.log it, and inspect it in your Developer tools.
Personally, I use the data-* attributes only when little information (such as a couple of attributes) is needed to be stored for each element and that information would be send by a direct click/hover event on the element itself - Otherwise it doesn't make much sense to me to store it within the DOM.
None is stopping you from saving whole JSON's on the DOM, if you find it easier - However if you keep on doing it you will end up with a very convoluted markup and a pattern that just looks terrible

I am working with a similar scenario currently and I've chosen to implement a model on the client's side which holds the information, because storing everything in the DOM could be harmful to the overall performance.
In other words I have some HTML code, for example
<div id='element-1' class='element'>foo</div>
<div id='element-2' class='element'>bar</div>
<div id='element-3' class='element'>baz</div>
which corresponds to the recieved data
[{id:1, text:'foo'}, {id:2, text:'bar'}, {id:3, text:'baz'}]
and instead of using DOM I have a model object which holds the data, is accessible from everywhere and has methods to search in the data, render it and so on.
A very simplified example of such object could look like this:
function Model() {
this.data = []; //after recieving the data via Ajax it is stored here
this.find = find;
function find(id) {
//cycle through data and return the correct record
}
this.render = render;
function render(id) {
var obj = find(id);
// find the element with $('#element-'+id) and update it's text
}
this.update = update;
function update(id, text) {
var obj = find(id);
obj.text = text;
}
}
The advantage is that you don't make the DOM heavy and you keep your data in a clean and organized way and the downfall is that you have to keep your displayed data and model data in sync.

I would recommend not to store anywhere in html, as you going to pass elements to another ajax request. So just create variable in javascript and store it temporary.

Related

Web Worker Creating Garbage

I'm working on a project that utilizes web workers. It seems that the workers are generating quite a bit of extra garbage that has to be collected from the message passing.
I'm sending three things to the worker via post message from the main thread. First is just a number, second is an array with 7 numbers, and 3rd is the date. The firs two are properties of an object as seen below. This is called every 16ms on RAF for about 20 objects. The GC ends up collecting 12MB every 2 seconds or so. I'm wondering if there is a way to do this without creating so much garbage? Thanks for any help!
//planet num (property of object) is just a number like: 1
//planetele looks like this (property of an object)
//[19.22942, 313.4868, 0.04441, 0.7726, 170.5310, 73.9893, 84.3234]
//date is just the date object
//posted to worker like so:
planetWorker.postMessage({
"planetnum": planet.num,
"planetele": planet.ele,
"date": datet
});
//the worker.js file uses that information to do calculations
//and sends back the planet number, with xyz coordinates. (4 numbers)
postMessage({data: {planetnum : planetnum, planetpos: planetpos}});
I tried two different avenues and ended up using a combination of them. First, before I sent some of the elements over I used JSON.stringify to convert them to strings, then JSON.parse to get them back once they were sent to the worker. For the array I ended up using transferable objects. Here is a simplified example of what I did:
var ast = [];
ast.elements = new Float64Array([0.3871, 252.2507, 0.20563, 7.005, 77.4548, 48.3305, 0.2408]);
ast.num = 1;
var astnumJ = JSON.stringify(ast.num); // Probably not needed, just example
// From main thread, post message to worker
asteroidWorker.postMessage({
"asteroidnum": astnumJ,
"asteroidele": ast.elements.buffer
},[ast.elements.buffer]);
This sends the array to the worker, it doesn't copy it, which reduces the garbage made. It is now not accessible in the main thread, so once the worker posts the message, you have to send the array back to the main thread or it wont be accessible as a property of ast anymore. In my case, because I have 20 - 30 ast objects, I need to make sure they all have their elements restored via post message before I call another update to them. I did this with a simple counter in a loop.
// In worker.js
asteroidele = new Float64Array(e.data.asteroidele); // cast to type
asteroidnum = JSON.parse(e.data.asteroidnum); // parse JSON
// Do calculations with this information in worker then return it to the main thread
// Post message from worker back to main
self.postMessage({
asteroidnum : asteroidnum,
asteroidpos : asteroidpos, // Calculated position with elements
asteroidele : asteroidele // Return the elements buffer back to main
});
// Main thread worker onmessage function
asteroidWorker.onmessage = function(e){
var data1 = e.data;
ast.ele = data1.asteroidele; // Restore elements back to ast object
}
Not sure this is the best approach yet, but it does work for sending the array to and from the worker without making a bunch of extra garbage. I think the best approach here will be to send the array to the worker and leave it there, then just return updated positions. Working on that still.

AngularJS: How to use ngOption to iterate data from cached Api call

I have an application in which I am making multiple API calls and caching that data for later. Then someone else in the app, I want to retrieve that data and list it in a drop down using ng-option.
To get the cached data for each call, I am doing
var httpCache = $cacheFactory.get('$http');
var cachedImpactedEntities = httpCache.get('my api url');
This returns an object of an array in an array like so:
[200,"[ {
"entity_id": 1,"entity_desc": "test1" },
{"entity_id": 2,"entity_desc": "test2"}]",
{"content-type":"application/json;
charset=utf-8"},"OK"]
What would be a good way to extract just the inside array in quotes and output each "entity_desc" to the drop down using ng-option like:
test1
test2
...
The way the cached information comes back is confusing me.
Thanks.
If I understand you correctly the following shall be sufficient:
$scope.cachedEntities = eval(cachedImpactedEntities[1]);
<select ng-options="item as item.entity_desc for item in cachedEntities track by item.entity_id" ng-model="selected"></select>
But that means you will need to update "manually" the cachedEntities each time you get the data back from api call.
Consider of using promise construct:
$http.get("url+parameters").then(function(data) { $scope.cachedEntities = data}, function(){ // do something on error });

How do I load data for Dojo Dgrid Table using AJAX?

I am exploring using DGrid for my web application. I am trying to have a table similar to this.
The code for the example above is here.
The table uses a memory store as the source of its data - the summary field there is what shows up when we click and expand each row.
I want the details(i.e the text shown when we click a row) to be fetched from the server on clicking on the row instead of being statically loaded along with rest of the page.
How do I modify the above code to be able to do that?
(My requirement is that of an HTML table, each row expandable on clicking, where the data on each expansion is fetched from the server, using AJAX for instance. I am just exploring dgrid as an option, as I get sortable columns for free with dgrid. If there is a better option, please let me know)
EDIT: Basically I am looking for ideas for doing that and not expecting anyone to actually give me the code. Being rather unfamiliar with Dojo, I am not sure what would be the right approach
If your ajax call returns html, you could place a dijit/layout/ContentPane in your renderer, and set the url of the contents you want to fetch in the ContentPane's href property. Assuming that your initial data (the equivalent of the example's memory store) would have a property called "yourServiceCallHref" containing the url you want to lazy load, your could try this :
require(["dijit/layout/ContentPane", ...], function(ContentPane){
renderers = {
...,
table: function(obj, options){
var div = put("div.collapsed", Grid.prototype.renderRow.apply(this, arguments)),
cp = new ContentPane({
href : obj.yourServiceCallHref
}),
expando = put(div, "div.expando", cp.domNode);
cp.startup();
return div;
}
});
If your service returns json, you could probably do something with dojo/request in a similar fashion. Just add your dom creation steps in your request callback and put them inside the div called "expando"...
Another option would be to replace the Memory store by a JsonRest store, and have the server output the same json format than the one you see on the Memory store. That means all the data would be fetched in a single call though...

How to set a global variable so to keep data related to multiple jQuery objects?

I am using jQuery and jQuery UI, and I am almost new to JavaScript. I would like to set a global variable in the window object so to keep custom data related to multiple jQuery objects. That is, at this time I am using the following (poor) code:
// Given
window.myDataObject = {};
// Then, in the same file, I run multiple times (one time for each 'tag_id_1',
// 'tag_id_2', ..., 'tag_id_N') the following code
var tag = $('#tag_id_N')
myDataObject = { pagination: { page : 1, per_page: 10 } } // This aims to keep pagination data for tags.
Since I am trying to keep data for multiple tags, running the above code multiple times makes the window.myDataObject to be continuously "re-initialized" (making the keeping process inefficient). Because that, I thought to add "namespaced" properties (maybe, namespaced with "something" related to each tag object) to window.myDataObject so that each tag has its own pagination data.
How can I make that? Is that approach a "good" / "proper" way to proceed?
I think you're just looking for the .data() method:
The .data() method allows us to attach data of any type to DOM
elements in a way that is safe from circular references and therefore
from memory leaks.
We can set several distinct values for a single element and retrieve
them later:
First of all you should be using the window object not windows.
Secondly if you want to use multiple tags you could try to do the following:
// Given
windows.taggedObjects = {};
// Then, in the same file, I run multiple times (one time for each 'tag_id_1',
// 'tag_id_2', ..., 'tag_id_N') the following code
var tagId = 'tag_id_N';
// This aims to keep pagination data for tags.
window.taggedObjects[tagId] = { tag: $('#' + tagId), pagination: { page : 1, per_page: 10 } };
To retrieve your data just use the tag id again like so:
alert(window.taggedObjects[tagId]);

How to generate parent/child nest on client side?

I've searched through the myriad parent/child array/object/whatever questions here and elsewhere and haven't been able to solve my issue. I know this is a bit long, but I wanted to ensure I'm providing enough info to you guys.
Here's what I want to do:
I have a number of <div>-delineated items on the page with parent/child relationships, generated via php from my database
I want to use these items as the data source for a D3.js Dendrogram (a node-link tree diagram http://mbostock.github.com/d3/ex/cluster.html)
I'm storing them with left/right nested set values but also parentID values, so I can add ID, parentID, rgt, lft and depth attributes to the <div> elements, so I should have available whatever's needed to generate the parent/child relationships on the client side
For various reasons, instead of creating a JSON file on the server side to use as the data source, I need to create it on the client side based on the attributes in #3
I've had difficulty getting various suggested javascript functions to work and all the D3 examples I've found use either a preexisting JSON file or generated math-based file, not attributes of elements already on the page
Here is an example of what already works for me with the D3 Dendrogram, but it's not generated dynamically:
var tree3 =
{"sid": "1", "children": [
{"sid": "2", "children": [
{"sid": "5", "children": [
{"sid": "75"},
{"sid": "85", "children": [
{"sid": "87"}, ...
To give you an idea of where these attributes are in the DOM, I originally tried the below, but of course it doesn't generate any hierarchy:
function tree() {
var tree=[];
$("article").each(function(){
tree.push({
sid:$(this).attr("sid"),
l:$(this).attr("l"),
r:$(this).attr("r"),
pid:$(this).attr("pid")
});
});
return tree;
}
I've been messing around unsuccessfully with variants of the below to get a nested array:
function tree2() {
$("article").(function(d) {
return d.parent().attr("pid") === 0;
}, function(parent, child) {
return parent.attr("pid") === child.parent().attr("sid");
}).toArray();
}
So, I'm driving myself crazy trying to create the javascript array nested correctly, but it's dawned on me that I may not need to and that D3's data selectors and methods could be sufficient. Could you please help me with the code to:
Pull the needed attributes to generate the parent/child relationship within a D3 function ("sid" is the identifier) or, if this isn't possible,
Create the needed array or array-like object in javascript for use by D3 (still with "sid" as the identifier).
Thanks in advance.
You need to get recursive! Basically the trick is to pass the current parent in as you go, which changes the context and allows you to walk down the tree.
Update: Working fiddle.
Assuming your HTML structure is something like this:
<div sid="1" pid="">
<div sid="1.1" pid="1">
<div sid="1.1.1" pid="1.1">
</div>
</div>
</div>
You could do something like this:
var _json = {};
function addTreeNode(div, parentObj) {
var childObj = {
sid: $(div).attr("sid"),
pid: $(div).attr("pid")
}
// add this to it's parent in the JSON hierarchy
if (!parentObj.children) parentObj.children = [];
parentObj.children.push(childObj);
// keep adding for all children div's
$(div).find("div").each(function() {
addTreeNode(this, childObj);
});
}
// start at the roots, it will magically work it's way out to the leaves
$("body > div").each(function(){
addTreeNode(this, _json);
});
console.log(_json);
Note that if your tree is big enough, you will cause stack overflows, especially in IE. In that case, you'll need to switch this over from recursion to iteration. It's not as pretty that way, though.

Categories