understanding the chained data() function in Unslider.js - javascript

was just poking a plugin online called Unslider.js , a simple lightweight carousal plugin i am having a great difficulty understanding the following ine of code in the plugin :
me.data(key, instance).data('key', key);
now let me explain the context of this line , in the plugin the above line is preceded by the following lines of code :
$.fn.unslider = function(o) {
var len = this.length;
// Enable multiple-slider support
return this.each(function(index) {
// Cache a copy of $(this), so it
var me = $(this),
// if len less than 1 , the below line returns "Unslider"
// Else it returns Unslider-1 , Unslider-2 and so on ..
key = 'unslider' + (len > 1 ? '-' + ++index : '');
instance = (new Unslider).init(me, o);
I ran a few tests and found out about the below line ,
key = 'unslider' + (len > 1 ? '-' + ++index : '');
that, key returns 'slider', if len "is less then" 1 and if more than 1, then the results would look something like 'slider-1', 'slider-2' , 'slider-3' and so on .
The next line that is :
instance = (new Unslider).init(me, o);
is createing a new instance of Unslider and storing it in instance and after that .
init(me,o) function is executed where ,
me = $(this) and o is nothing but an object literal passed by the user to the plugin .
now i gave all the above explanation , so that everything is not out of context .
now i did go to the Jquery official docs and checked the usage of data().
i saw examples such as :
$( "body" ).data( "foo", 52 );
$( "body" ).data( "bar", { myType: "test", count: 40 } );
$( "body" ).data( { baz: [ 1, 2, 3 ] } );
$( "body" ).data( "foo" ); // 52
$( "body" ).data(); // { foo: 52, bar: { myType: "test", count: 40 }, baz: [ 1, 2, 3 ] }
These examples are quite cute to be honest, but somehow they don't help me understand what i want to .
So coming back to my question ,
me.data(key, instance).data('key', key);
What does the above line really Doing ?
EDIT ::
and if i take off that line everything seems to be working just fine , the plugin still works fine and the carousal still slides .
thank you.
Alexander.

When jQuery's data is used with two arguements, a key and a value, it stores the value under the given key in an internal object that jQuery keeps track of.
When doing this, jQuery returns the collection, so it can be chained again
var me = $('#element'); // a DOM element
var me2 = me.data('key1', 'value'); // returns same DOM element
me2.data('key2', 'value');
is the same as
var me = $('#element'); // a DOM element
me.data('key1', 'value').data('key2', 'value');
because the collection is returned, and can be chained.
As for the data stored in data, that's something used internally by the plugin, and could be anything, even an object, as long as there's a key to get the data back again, remember this isn't data attributes in HTML, it's an internal store that accepts any data type, even an instance of a function.
As for the key, it just increments to be unique
key = 'unslider' + (len > 1 ? '-' + ++index : ''); // the string "unslider-1" etc
Then the first call to data stores the current instance of the slider
me.data(key, instance).data('key', key);
while the second one stores the key, as it's easier to just do
me.data('key');
to get the key back, if you don't know what the last number in the key is, so it's actually a little clever as it lets you do
var key = me.data('key');
var instance = me.data(key);
and get the correct intance back regardless of the index, increments etc.

Related

I'm making a level maker with a preview from the code generated by the level maker, how could I do this?

I have made a Level Generator. Basically there is a 3 by 20 grid of squares, and you can select either one and depending on what you select when you click the button to generate it generate some code for you into a variable (string). It works perfectly but how am I going about to then get that generated code and turn it into a preview.
So far I found out using the keyword eval() but this only does the last line? Any ideas?
Here is a picture of what the layout is:
The Website So Far
The code that I originally had to detect the code was:
if (container.childNodes[index].innerText == 'pos3') {
if (container.childNodes[index].id == '1 second') {
text = text + '\n' + 'cube1 = new theCubeCreator(pos3, 0, 2, 1000),'
//amtselected = amtselected + 1
}....
Something like that then I would bundle it all up with this
var pos1 = 125 //middle
var pos2 = 70 //left
var pos3 = 180 //right
text = text + '\n' + 'cube1 = new theCubeCreator(pos2, 0, 2, 1000)' // Must add this to make it a end
var evaluation = eval(text)
console.log(evaluation);
Sorry if this is hard to read or if you want me to send examples.
What you are doing is bad practice. You should make an object that holds the functions and a generator function that converts and object into a function.
// object for the function / class you want to run
var data = {
name: "console.log",
isClass: false,
params: ["pos2", 0, 2, 1000],
};
var domParse = {
name: "DOMParser",
isClass: true,
params: ["<div>Hello World</div>", "text/html"],
};
var funcs = {
DOMParser: (args) => {
const dom = new DOMParser();
return dom.parseFromString(...args);
},
"console.log": (args) => console.log(...args),
};
// function to generate a function from the object.
function generate({ name, isClass, params }) {
return funcs[name](params);
}
generate(data); // console.log's pos2 0 2 1000
generate(domParse); // creates a DOM object
I took another way than doing eval() (well i still used eval). What I was doing was, to have a variable let text = '' then adding onto that variable doing something like this text = text + \n + '...'
Already this is bad so i took a different approach. all i changed was instead of having a string variable i would have a Array to store my code. Declearing it like this let text = [] then using push() to add the code to it, like so text.push(eval(...)).
Thats what i did to complete to fix my problem if you have any other way or eisier to follow (and yes i know this is messy) then comment (:

How can I reformat this simple JSON so it doesn't catch "Circular structure to JSON" exception?

Introduction
I'm learning JavaScript on my own and JSON its something along the path. I'm working on a JavaScript WebScraper and I want, for now, load my results in JSON format.
I know I can use data base, server-client stuff, etc to work with data. But I want to take this approach as learning JSON and how to parse/create/format it's my main goal for today.
Explaining variables
As you may have guessed the data stored in the fore mentioned variables comes from an html file. So an example of the content in:
users[] -> "Egypt"
GDP[] -> "<td> $2,971</td>"
Regions[] -> "<td> Egypt </td>"
Align[] -> "<td> Eastern Bloc </td>"
Code
let countries = [];
for(let i = 0; i < users.length; i++)
{
countries.push( {
'country' : [{
'name' : users[i],
'GDP' : GDP[i],
'Region' : regions[i],
'Align' : align[i]
}]})
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
Code explanation
I have previously loaded into arrays (users, GDP, regionsm align) those store the data (String format) I had extracted from a website.
My idea was to then "dump" it into an object with which the stringify() function format would format it into JSON.
I have tested it without the loop (static data just for testing) and it works.
Type of error
let obj_data = JSON.stringify(countries, null, 2);
^
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Node'
| property 'children' -> object with constructor 'Array'
| index 0 -> object with constructor 'Node'
--- property 'parent' closes the circle
What I want from this question
I want to know what makes this JSON format "Circular" and how to make this code work for my goals.
Notes
I am working with Node.js and Visual Studio Code
EDIT
This is further explanation for those who were interested and thought it was not a good question.
Test code that works
let countries;
console.log(users.length)
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : 'CountryTest'
}
]
}
};
let obj_data = JSON.stringify(countries, null, 2);
fs.writeFileSync('countryballs.json', obj_data);
});
Notice in comparison to the previous code, right now I am inputing "manually" the name of the country object.
This way absolutely works as you can see below:
Now, if I change 'CountryTest' to into a users[i] where I store country names (Forget about why countries are tagged users, it is out of the scope of this question)
It shows me the previous circular error.
A "Partial Solution" for this was to add +"" which, as I said, partially solved the problem as now there is not "Circular Error"
Example:
for(let i = 0; i < users.length; i++)
{
countries = {
country : [
{
"name" : users[i]+''
}
]
}
};
Resulting in:
Another bug, which I do not know why is that only shows 1 country when there are 32 in the array users[]
This makes me think that the answers provided are not correct so far.
Desired JSON format
{
"countries": {
"country": [
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
},
{
"name": "",
"GDP" : "",
"Region" : "",
"Align" : ""
}
]}
}
Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a) or indirectly (a -> b -> a).
To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference. For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
The second parameter to stringify is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.
You can test the above code with the following:
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
})
The answer is from StackOverflow question,
Stringify (convert to JSON) a JavaScript object with circular reference
From your output, it looks as though users is a list of DOM nodes. Rather than referring to these directly (where there are all sort of possible cyclical structures), if you just want their text, instead of using users directly, try something like
country : [
{
"name" : users[i].textContent // maybe also followed by `.trim()
}
]
Or you could do this up front to your whole list:
const usersText = [...users].map(node => node.textContent)
and then use usersText in place of users as you build your object.
If GDP, regions and align are also references to your HTML, then you might have to do the same with them.
EUREKA!
As some of you have mentioned above, let me tell you it is not a problem of circularity, at first..., in the JSON design. It is an error of the data itself.
When I scraped the data it came in html format i.e <td>whatever</td>, I did not care about that as I could simply take it away later. I was way too focused in having the JSON well formatted and learning.
As #VLAZ and #Scott Sauyezt mentioned above, it could be that some of the data, if it is not well formatted into string, it might be referring to itself somehow as so I started to work on that.
Lets have a look at this assumption...
To extract the data I used the cheerio.js which gives you a kind of jquery thing to parse html.
To extract the name of the country I used:
nullTest = ($('table').eq(2).find('tr').eq(i).find('td').find('a').last());
//"Partial solution" for the OutOfIndex nulls
if (nullTest != null)
{
users.push(nullTest);
}
(nullTest helps me avoid nulls, I will implement some RegEx when everything works to polish the code a bit)
This "query" would output me something like:
whatEverIsInHereIfThereIsAny
or else.
to get rid off this html thing just add .html() at the end of the "jquery" such as:
($('table').eq(2).find('tr').eq(i).find('td').find('a').last().html());
That way you are now working with String and avoiding any error and thus solves this question.

Search array for string - returning -1

I've been reading lots of StackOverflow answers which tell me that, in Javascript, the best way to search an array for a particular string is use indexOf(). I have been trying to make this work for a while now, and I need some help with it.
I am making a shop in a text-adventure game. These are the values I am using:
The array shopCosts:
shopCosts = [20, 25];
The array shopItems:
shopItems = [["Sword", "Shield"]];
I dynamically create radiobuttons by looping through shopItems:
for(var i = 0; i < array.length; i++)
{
// Create the list item:
var item = document.createElement('li');
// Set its contents:
item.appendChild(document.createTextNode(array[i] + " - " + shopCosts[i] + " Gold"));
// Add it to the list:
list.appendChild(item);
var label = document.createElement("label");
var radio = document.createElement("input");
var text = document.createTextNode(array[i]);
radio.type = "radio";
radio.name = "shop";
radio.value = array[i];
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
label.appendChild(radio);
label.appendChild(text);
document.body.appendChild(label);
}
This is the part in question:
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
My logic was basically to assign values to each dynamically created radiobutton, and if one was pressed, get the value (so, the name of the item you wanted to buy) and then search shopItems for that particular string for the index value. Once I had that, I would look in the same "parallel" list shopCosts to find the price.
I used console.log() to see what variables were in play. When I clicked on the radio button, this function is called:
function addValue(nameOfItem, shopCosts, shopItems)
{
var positionOfShopItem = shopItems.indexOf(nameOfItem);
console.log(positionOfShopItem);
console..log(nameOfItem);
console.log(shopItems);
}
Surely, the console.log() would return the position of the named item? To prove to myself I'm not going crazy, here's what the Dev Tools say:
-1
Sword
[Array[2]]
0: "Sword"
1: "Shield"
Sword is clearly in the array, in position 0, so why is indexOf() returning -1?
Any help appreciated!
As I alluded to in my comment, its because shopItems does not contain an array of strings, it contains a single element, where that one element is an array of strings. I suspect your code would work just fine if you removed the extra square braces
var shopItems = ["Sword", "Shield"];
I realize you've already fixed the bug, but I urge you to consider a different approach to the problem. These two principles will not only solve the problem in a cleaner way, but they also give you a new way to think about similar problems in the future:
Never use parallel arrays. Use a single array of objects instead.
In your main loop that appends the items, put the main body of the loop in a function.
If you follow these two ideas you gain several benefits. The code becomes much more straightforward, easier to maintain, and you don't have to do any array lookups at all!
Each shop item is packaged up as a single object in the array, like this:
var shopItems = [
{ name: 'Sword', cost: 20 },
{ name: 'Shield', cost: 25 }
];
So if you have a reference to the shop item as a whole, say in a variable called shopItem, then you automatically have all of its properties available: shopItem.name and shopItem.cost. This lets you also easily add more bits of data to a shop item, e.g.
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
and now shopItem.dangerous will give you the appropriate value. All without any array lookups.
Making the main loop body into a function adds a further benefit: Inside that function, its parameters and local variables are preserved each time you call the function (this is called a closure). So now you don't even have to fetch the list item value and look it up - you already have the appropriate shopItem available in the code.
Putting this together, the code might look like this:
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
var list = document.getElementById( 'list' );
for( var i = 0; i < shopItems.length; ++i ) {
appendShopItem( shopItems[i] );
}
// Alternatively, you could use .forEach() instead of the for loop.
// This will work in all browsers except very old versions of IE:
// shopItems.forEach( appendShopItem );
function appendShopItem( shopItem ) {
// Create the list item:
var item = document.createElement( 'li' );
// Set its contents:
item.appendChild( document.createTextNode(
shopItem.name + ' - ' + shopItem.cost + ' Gold'
) );
// Add it to the list:
list.appendChild( item );
var label = document.createElement( 'label' );
var radio = document.createElement( 'input' );
var text = document.createTextNode( shopItem.name );
radio.type = 'radio';
radio.name = 'shop';
radio.value = shopItem.name;
radio.onclick = function () {
addValue( shopItem );
};
label.appendChild( radio );
label.appendChild( text );
document.body.appendChild( label );
}
function addValue( shopItem ) {
console.log( shopItem );
alert(
shopItem.name +
' costs ' + shopItem.cost + ' and is ' +
( shopItem.dangerous ? 'dangerous' : 'not dangerous' )
);
}
New fiddle (with a tip of the hat to Jamiec for the original fiddle)
As you can see, this makes the code much easier to understand. If you have a shopItem, you automatically have its name, cost, and any other property you want to add. And most importantly, you never have to keep track of putting your values in the same order in two, three, or even more different arrays.
shopItems is an Array of Arrays. The 0 index of shopItems contains another array which contains:
["Sword", "Shield"]
So when you are trying to find the "Sword" item or "Shield" Item inside of shopItems it is returning -1 because it cannot find either inside of the array.
Change
shopItems = [["Sword", "Shield"]];
To
shopItems = ["Sword", "Shield"];
And that will fix your issue.
I've fixed it!
Removing the double square brackets resulted in this mess. So, as a workaround, I simply added [0] to var positionOfShopItem = shopItems.indexOf(nameOfItem); to get var positionOfShopItem = shopItems[0].indexOf(nameOfItem);
Thanks for everyone's help.

Couchdb reverses start and end key when descending is true

I have a CouchDB that contains items with something called save_data (actual data I need), rel (as related account - account linked to that document) and created_at (date of creation).
When I first created my view which I called recent-items I thought that items in that view are sorted in order they were created in, but it didn't take long for me to discover just how wrong I was. I wanted to get all documents related to one user (rel, save_profile in my js which calls the db.view funcion) and then sort them based on created_at so I created map funcion:
function(doc) {
if (doc.rel) {
var p = doc.save_data || {};
var r = doc.rel || {};
var q = doc.created_at || {};
emit([doc.rel], {save_data: doc.save_data, rel: doc.rel});
}
};
and then I called it with these parameters:
db.view(design + "/recent-items", {
descending : "true",
limit : 10,
update_seq : true,
key : [save_profile],
success : function(data) {
...somecode...
}
});
and then I noticed that they didn't appear in the order I wanted, but sorted by their ID which makes sense now, but that's not what I needed. So I did this: I reworked map function so that it shows user and date in key (as fields to be sorted by)
function(doc) {
if (doc.rel) {
var p = doc.save_data || {};
var r = doc.rel || {};
var q = doc.created_at || {};
emit([doc.rel, doc.created_at], {save_data: doc.save_data, rel: doc.rel});
}
};
and then I used startkey instead of key in db.view like this:
db.view(design + "/recent-items", {
descending : "true",
limit : 10,
update_seq : true,
startkey : [save_profile, null],
success : function(data) {
...somecode...
}
});
so that I get all documents related to save_profile but sorted by date also. I did get them, but I also got documents from other users with it so that function is completely unreliable. What I did then is implement endkey also, like this:
db.view(design + "/recent-items", {
descending : "true",
limit : 10,
update_seq : true,
startkey : [save_profile, null],
endkey : [save_profile, {}],
success : function(data) {
...somecode...
}
});
but then I get empty view as result.
Dates I use are in this format:
"2013-05-13T11:59:22.281Z"
and profiles are something like this:
{"rand":"0.26928815129213035","nickname":"Nickname","email":"Label for Gravatar","url":"URL","gravatar_url":"http://www.gravatar.com/avatar/35838c85593335493a1fa916863fee0c.jpg?s=40&d=identicon","name":"testacc"}
I also tried replacing [] and {} in start/endkeys with "0000-00-00T00:00:00.000Z" and "9999-99-99T99:99:99.999Z", but it changed nothing. So... Any ideas? As far as I've seen in other similar problems people just used {} as end key and left startkey without second parameter but that doesn't work here either.
Edit: Solved!
Alright folks, believe it or not I've done it in this way:
I changed my map function to display created at and profile in this way:
function(doc) {
if (doc.rel) {
var p = doc.save_data || {};
var r = doc.rel || {};
var q = doc.created_at || {};
emit([doc.rel, doc.created_at], {save_data: doc.save_data, rel: doc.rel});
}
};
and it appears that if you set descending to true before setting start and end keys you have to reverse the search interval so that endkey contains starting value and startkey containst ending value, like this:
db.view(design + "/recent-items", {
descending : "true",
update_seq : "true",
startkey : [save_profile.name, save_profile.rand, {}],
endkey : [save_profile.name, save_profile.rand, null],
inclusive_end : "true",
success : function(data) {
...somecode...
}
});
That did the trick and it works flawlessly (but also with a complete absence of logic).
I should have caught this before. So when you do the following, it works the way you'd like:
db.view('_design/test_views/_view/view1', startkey: ["account2"])
=> {"total_rows"db.view('_design/test_views/_view/view1')
=> {"total_rows"=>4, "offset"=>0, "rows"=>[{"id"=>"test1", "key"=>["account1", "2009-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account1"}}, {"id"=>"test2", "key"=>["account2", "2012-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account2"}}, {"id"=>"test3", "key"=>["account3", "2011-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account3"}}, {"id"=>"test4", "key"=>["account4", "2010-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account4"}}]}`
db.view('_design/test_views/_view/view1',startkey: ["account2"])
=> {"total_rows"=>4, "offset"=>1, "rows"=>[{"id"=>"test2", "key"=>["account2", "2012-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account2"}}, {"id"=>"test3", "key"=>["account3", "2011-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account3"}}, {"id"=>"test4", "key"=>["account4", "2010-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account4"}}]}`
db.view('_design/test_views/_view/view1',
startkey: ["account2"],
endkey: ["account3",{}])
=> {"total_rows"=>4, "offset"=>1, "rows"=>[{"id"=>"test2", "key"=>["account2", "2012-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account2"}}, {"id"=>"test3", "key"=>["account3", "2011-05-13T11:59:22.281Z"], "value"=>{"rel"=>"account3"}}]}`.
But when you set descending=true, you reverse the order first. Previously you were setting your start and end keys the way that you should when descending=false, but you need to reverse them when you change descending. The CouchDB Definitive Guide is great and talks about these reversed results, worth the read.
I totally missed that you were setting descending, sorry for the confusion.
I think the startkey [save_profile, null] is what is messing you up (although it works via curl). Whatever library you're using (db.view is some javascript lib or ruby CouchRest maybe?) may be recoding null as something else. You can always verify this compared to curl by breaking out the packet sniffer (i.e. Wireshark), although you'll get an idea how inefficient a library can be with all the extra requests it makes. Can make the troubleshooting more difficult.
What results do you get with curl? I mocked up your database, and here's what I get:
$ curl -X GET 'http://localhost:5984/test2/_design/test_views/_view/view1'
{"total_rows":4,"offset":0,"rows":[
{"id":"test1","key":["account1","2009-05-13T11:59:22.281Z"],"value":{"rel":"account1"}},
{"id":"test2","key":["account2","2012-05-13T11:59:22.281Z"],"value":{"rel":"account2"}},
{"id":"test3","key":["account3","2011-05-13T11:59:22.281Z"],"value":{"rel":"account3"}},
{"id":"test4","key":["account4","2010-05-13T11:59:22.281Z"],"value":{"rel":"account4"}}
]}
$ curl -X GET 'http://localhost:5984/test2/_design/test_views/_view/view1?startkey=\["account2"\]&endkey=\["account3",\{\}\]'
{"total_rows":4,"offset":1,"rows":[
{"id":"test2","key":["account2","2012-05-13T11:59:22.281Z"],"value":{"rel":"account2"}},
{"id":"test3","key":["account3","2011-05-13T11:59:22.281Z"],"value":{"rel":"account3"}}
]}
Notice that I am not using null, I'm just leaving that element of the key out. Also notice in curl (and possibly you're library), you have to be really careful what you put in start/end keys. I have to escape all bash stuff that even single quotes don't escape (i.e. [ { etc), and curl escapes spaces as %20, which is then used for the keys. A good approach is to run couchdb not forked out, or just watch its logs, and see what the incoming requests look like. Has been a source of issues for me.
You're using the wildcards in the keys, which is a cool feature. You may have seen this, I've re-read this snippet a few times to try to understand them.
I've beat my head on this similar problem too, until I really understood what views do. But what you're doing should be possible. Any more complicated searches, and I'd really consider Elasticsearch or something similar. The river install for it is really easy, and the queries are pretty similar. But you don't have to work around the limitations of views and orders.
Hope that helps.
Alright folks, believe it or not I've done it in this way:
I changed my map function to display created at and profile in this way:
function(doc) {
if (doc.rel) {
var p = doc.save_data || {};
var r = doc.rel || {};
var q = doc.created_at || {};
emit([doc.rel, doc.created_at], {save_data: doc.save_data, rel: doc.rel});
}
};
and it appears that if you set descending to true before setting start and end keys you have to reverse the search interval so that endkey contains starting value and startkey containst ending value, like this:
db.view(design + "/recent-items", {
descending : "true",
update_seq : "true",
startkey : [save_profile.name, save_profile.rand, {}],
endkey : [save_profile.name, save_profile.rand, null],
inclusive_end : "true",
success : function(data) {
...somecode...
}
});
That did the trick and it works flawlessly (but also with a complete absence of logic).

JavaScript Reformatting JSON arrays

I am relatively new to the JSON notation, and have run into an issue when attempting to reformat. The current format contained in the database needs to be modified to a new format for importation into a project timeline graph.
Here is the current JSON format:
[
{
"name":"5-HP-N/A-N/A-F8",
"node":{
"name":"5",
"id":14
},
"timeline":{
"epc":null,
"m1":null,
"m2":null,
"m3":1554087600000,
"m4":1593572400000,
"m5":1625108400000,
"m6":1641006000000,
"m7":1656644400000
},
"fab":{
"name":"F8",
"id":1
}
},
However, in order to display in the graph, I need the following format:
{
'start': new Date(value from epc, or first non-null milestone),
'end': new Date(value from m1 or first non-null milestone), // end is optional
'content': 'label from start Date milestone'
'group' : ' value from name field above 5-HP'
'classname' : ' value from start Date milestone'
});
I am trying to write a function in order to accomplish this. Only epc, m1, or m2 may have the value of null, but the condition must be checked for to determine if an event range should be created and where it should end. What would be the best way to reformat this json data (preferrably from an external json sheet)?
Edit: Thanks for all the help I see how this is working now! I believe I didn't explain very well the first time though, I actually need multiple class items per "group".
The end result is that these will display inline on a timeline graph 'group' line, and so I am trying to figure out how to create multiple new objects per array element shown above.
So technically, the first one will have start date = m3, and end date = m4. Then, the next object would have the same group as the first (5-HP...), the start date = m4, end date = m5...etc. This would continue until m7 (always an end date but never a start date) is reached.
This is why the loop is not so simple, as many conditions to check.
see a working fiddle here: http://jsfiddle.net/K37Fa/
your input-data seems to be an array, so i build a loop around that. if not just see this fiddle where the input data is a simple object: http://jsfiddle.net/K37Fa/1/
var i
, result = [],
, current
, propCounter
, content = [ { "name":"5-HP-N/A-N/A-F8", "node":{ "name":"5", "id":14 }, "timeline":{ "epc":null, "m1":null, "m2":null, "m3":1554087600000, "m4":1593572400000, "m5":1625108400000, "m6":1641006000000, "m7":1656644400000 }, "fab":{ "name":"F8", "id":1 } }],
// get the milestone in a function
getMileStone = function(obj) {
propCounter = 1;
for(propCounter = 1; propCounter <= 7; propCounter++) {
// if m1, m2 and so on exists, return that value
if(obj.timeline["m" + propCounter]) {
return {key: "m" + propCounter, value: obj.timeline["m" + propCounter]};
}
}
};
// loop over content array (seems like you have an array of objects)
for(i=0;i< content.length;i++) {
current = content[i];
firstMileStone = getMileStone(current);
result.push({
'start': new Date(current.epc || firstMileStone.value),
'end': new Date(current.m1 || firstMileStone.value),
'content': firstMileStone.key,
'group' : current.name,
'classname' : firstMileStone.value
});
}
EDIT:
getMileStone is just a helper-function, so you could just call it with whatever you want. e.g. current[i+1]:
secondMileStone = getMileStone(current[i + 1])
you should just check, if you are not already at the last element of your array. if so current[i+1] is undefined, and the helperfunction should return undefined.
you could then use as fallback the firstMileStone:
secondMileStone = getMileStone(current[i + 1]) || firstMileStone;
see the updated fiddle (including check in the getMileStone-Helperfunction): http://jsfiddle.net/K37Fa/6/

Categories

Resources