AngularJS - Conditionally display key and value if they exist - json

This may be a little confusing to describe.
Basically, I am parsing multiple external JSON feeds that display in different views depending on the 'active tab' displayed. They both share the same partial template, so they both look exactly the same, just different content.
The problem that I am facing now is, that in some feeds, some keys are placed in an array and others are not.
For example, the feeds parses this kind of data:
JSON Feed 1 - One 'attributes' inside of 'link'
"link":{
"attributes":{
"href":"www.link1.com"
}
}
JSON Feed 2 - Two 'attributes' inside of 'link'
"link":[
{
"attributes":{
"href":"www.link1.com"
}
},
{
"attributes":{
"href":"www.link2.com"
}
}
]
The only way I am able to get the value "www.link1.com" is via:
For Feed 1:
link1
And for Feed 2:
link1
I am trying to figure out what would be the best way to do:
1) If link[0] exists - display it, else if [link] exists, display that instead.
2) Or if targeting the activeTab would be safer? For instance, if activeTab = view2 or view4, use [link][0], else if activeTab = view1 or view3 use [link], else if I do not want it to be displayed, do not display anything.
Also a relatable question, if I am on view2 can I only display [link][0] on that view?
Any feedback would be appreciated. Thanks!

In your model controller, you can reconstruct the JSON objects to make them similar. The value of link in both feeds should be an array.
Then in your template you can simply use ngRepeat to get the items from inside the array.

Okay - so I found a solution to one of the questions above: "How to only display [link][0] in a specific view"
Pro: It's a simple code that depends on the activeTab / view that is being displayed.
Con(?): Since I am really a newbie to AngularJS - not sure if this is the best solution.
Basically:
Depending on the ng-view that is currently displayed, than a specific JSON object will be displayed, such as:
<a ng-show="activeTab == 'view1' || activeTab == 'view3'" ng-href="{{item['link'][0]['attributes']['href']}}">
<h6>Link1 from Feed2</h6>
</a>
Although the primary question is still unresolved: How to swap/switch JSON objects (key,values) if one exists, and not the other. I am still definitely trying to find a solution, although any help is still appreciated.
Please let me know what you think, or how I can improve the solution to the problem!
Thanks!
Roc.

Related

How to Retrieve Values from a Class Within a Class Using JavaScript

I am not experienced with HTML and 'JavaScript', and is having a roadblock when attempting to check the values from a class.
Below is the source as seen from F12
I would like to retrieve all createdby text -muted values (as they may contain more than one row) to check if any of them matches SYSTEM, may I know how can it be done?
I understand that an image is not the best way to portrait my question, I will try to type the source in my question.
My apologies, and thank you.
You can get NodeList which contains createdby text-muted classes using document.querySelectorAll as follows.
const elems = document.querySelectorAll(".createdby .text-muted");
elems.forEach((item) => {
console.log(item.innerHTML); // This will contain the text value of the selected selector
});

How to check TabNavigator Page efficiently

I am using flex TabNavigator to display few datagrids. Each datagrid have same structure but populated with different dataProvider. Currently I am using following method to check which datagrid or an element from a tab was clicked.
if(TabNavigator.selectedIndex == 0){
}else if(TabNavigator.selectedIndex == 1){
}
...
else if(TabNavigator.selectedIndex == 4){
}
My question is is there an efficient way to check this? Is there anyway I can organize similar structure in to one property?
Thank you.
Add all your data providers into an array in the same sequence as the items in the tab navigator. Then simply do:
dataGrid.dataProvider = dataProviderArray[tabNavigator.selectedIndex];
Here 'dataProviderArray' is the array of all the data providers for the data grid.
Also, since you mentioned that the data grid has the same structure for all the tabs, I am assuming you are using one Data Grid and not multiple. If not, I would recommend you keep one data grid only and change its data provider when the tabs change.
Hope this solves your question.

d3.js Zoomable Sunburst visualization from self-referencing CSV input

I'm a newbie at d3.js and need help to adapt Zoomable Sunburst to make it work with self-referencing CSV data.
Sample lines from the input CSV:
id,parentId,name,size
ROOT,NULL,Root,
RE,ROOT,General > Revenue Expenditure,
RE11,RE,Main supervision recovery etc.,
RE11A109K,RE11,Shivjayanti celebrations and lighting,170000
RE11H108,RE11,Electicity for import tax naka,2550000
RE11J,RE11,Maintaince for main building,
RE11J101A,RE11J,Electricity expenditure,11475000
RE11J101 C,RE11J,Power lift,2125000
As you can see, there are variable levels of depth. At some places the data is coming at 3rd level, at others we might have parent-child relationships going 9 levels deep, and so on. That's government budgets for you!
While there are columns in addition to these 4 that aren't critical to the visualization (so omitted here), I would be displaying their contents in a side pane on mouseover. So while non-critical, any additional columns do need to carry through and not get dropped.
I looked into many d3.nest() examples but those doesn't seem to work for parent-child self-referencing columns and data with variable levels of depth.
I'm presently using a workaround to convert this into hierarchical JSON in the flare.json format, using this DataStructures.Tree project . But looking for a more direct solution. Almost there, but not able to mix up code from different sources. Would be grateful to be shown a full top-to-bottom solution. Thanks in advance!
Got it. We include these scripts from the DataStructures.Tree project linked in the question : base.js, DataStructures.Tree.js. (you'll find them in /js/lib/ and /js/vendor/)
<script type="text/javascript" src="base.js"></script>
<script type="text/javascript" src="DataStructures.Tree.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
Then, we replace this line,
d3.json("flare.json", functon(error, root) {
..with these lines:
d3.csv("electrical5.csv", function(data){
var tree = DataStructures.Tree.createFromFlatTable(data),
root = tree.toSimpleObject(function(objectToDecorate, originalNode) {
objectToDecorate.size = originalNode.size;
if (objectToDecorate.children && objectToDecorate.children.length == 0) {
delete objectToDecorate.children;
}
return objectToDecorate;
});
//console.log(JSON.stringify(root));
leave everything else just as it is.
Uncomment the console.log line for debugging; it will put the json code in the browser console when you load the page. You can also make a textarea in the webpage and output the json code in that.
document.getElementById("SHOWME").value = JSON.stringify(root);
[at bottom of page]
<textarea id="SHOWME"></textarea>
it will be unformatted json code, so copy-paste it to http://codebeautify.org/jsonviewer and that ought to give you a well-formatted json.
To get more columns in apart from the regular [id,parentId,name,size] , we have to edit DataStructures.Tree.js
Locate these lines:
simpleChildRepresentation.push(decorateNode({
"name" : node.name,
"children" : children
}, node));
And insert the extra columns in the same format as the node.name line.
simpleChildRepresentation.push(decorateNode({
"name" : node.name,
//CUSTOM COLUMNS
"workcode" : node.id,
"parentcode" : node.parentId,
"department" : node.department,
"totalorextract" : node.totalorextract,
"total" : node.total,
"pages" : node.pages,
//CUSTOM COLUMNS DONE
"children" : children
}, node));
You can now directly visualize self-referencing csv data on any d3.js visualization that uses flare.json . Animations get a bit clunkier, though.

retrieving object properties from angularjs factory

I am completely stumped on this one. Everything's working fine (or fine enough for now) and all I need is to get the data back out of the factory in a non-json format. I've got a semi-working plunker with all the details.
Basically, the first page (under the Ctrl controller) is where a user can check a bunch of boxes. There's also an ng-switch between sets of options (the real things are much, much larger lists than these), so the checkboxFactory maintains the user's choices. When the user goes to the next page (or "next page" in the plunker because faking it), they can see what they chose. Those choices will then get wrapped up in a json post back to the server. I need to show the user-friendly name, but also have the id# of the choice, for the server.
If I put value="{{item.name}}" in the original checkbox ng-repeat, everything is fine. Except for the fact that then I have a factory of names, and not the server-required ids. Doing a second array in the factory (one for selected names, one for the corresponding selected ids) seems like overkill, when theoretically I could just add each selection as an object, and extract the properties as needed on the second page.
In reality, it's not working. Here's what I get if I echo the factory, after selections are made:
[ "{\"id\":1,\"name\":\"Firstplace\"}", "{\"id\":2,\"name\":\"Second place\"}" ]
...and I'm not sure, but those backslashes seem to be turning every selection into strings, because there are quotes just inside the square brackets. I've tried editing line 54 in the script, but I get errors. It doesn't like this:
if (checked && index == -1) {
if (setup) elem.prop('checked', false);
else scope.list.push({
id:"scope.value.id",
name:"scope.value.name"
});
On the html side, it doesn't like any of the variations I've tried in the ng-repeat, either. It seems like the source of all nightmares is that pushing is creating deformed json. I've tried all of these the second page/output:
{{item}}
{{item.name}}
{{item.item.name}}
The only one that works is {{item}} and unsurprisingly it's pretty ugly. Has anyone run into this before, and have any hints on how to fix this? Many thanks in advance.
using # will turn your object into a string, you should just use a reference to your item object instead and use =.
Change {{item}} to just item as a reference:
<input type="checkbox" name="group1" value="item" ng-model="isChecked" checkbox-list='checkedCity' />
In directive use =:
scope: {
list: '=checkboxList',
value: '='
},
see updated plunker

How to print a tree using Razor

I'm trying to print a simple HTML tree structure, consisting of ul and li elements. I want to be able to pass the view an IEnumerable<T> where T has some hiearchy information (e.g. parent). Now I want the view to output the Tree control much like ASP.NET's Tree used to work. Is there any way to do this in MVC3 using Razor?
I've so far ended up doing it like this:
#PrintCategoryTree(Model.Where(x => !x.ParentCategoryID.HasValue))
#functions{
public IHtmlString PrintCategoryTree(IEnumerable<Aurora.Models.Category> levelCategories) {
if (levelCategories.Count() == 0) { return new HtmlString(String.Empty); }
System.Text.StringBuilder sb = new System.Text.StringBuilder();
TagBuilder childBuilder = new TagBuilder("li");
foreach(var item in levelCategories.OrderBy(x => x.Name)) {
childBuilder.Attributes.Clear();
childBuilder.Attributes.Add("id", item.CategoryID.ToString("N"))
var sub = PrintCategoryTree(Model.Where(x => x.ParentCategoryID == item.CategoryID));
childBuilder.InnerHtml = item.Name + sub.ToString();
sb.AppendLine(childBuilder.ToString());
}
TagBuilder tagBuilder = new TagBuilder("ul")
{
InnerHtml = sb.ToString()
};
return Html.Raw(tagBuilder.ToString());
}
}
The reason being, this is still in the Razor View. And I can keep my presentation logic in my view. It's not exactly what I'd hoped, but I thought I'd share it with you guys here anyway.
Sure it's possible. :) You can acctually go about this in a few ways.
Use something like jsTree and only output the first level of the tree. When a user expands a node, jsTree issues an AJAX callback to get more, and that's just a matter of loading the nodes underneath whatever they opened. I know that's not exactly what you asked, but I wanted to mention it.
If you can either modify the query or do a bit of pre-processing on the data before passing it to razor, change each item in the IEnumberable so that it also includes it's "level" in the tree (1 for a root node, 2 for it's child, 3 for a child of a child, etc). Outputting it at that point is pretty easy. Create a variable in the view holding the current level. When you go to the next row, check if the new level is the same as the old one. If it's not, either open or close enough <ul> tags that you get to the right one for that element.
If you can't do that either, you'll need to keep track of the nodes as you see them in razor. The reason why is that when you find a child from a node that isn't the last one you saw, you'll need to get that node back to figure out how many </ul> tags you need to add to get to the right level. Off the top of my head you could do that by having the view create a Hashtable with the row's key and level for each row you hit. Then when you hit an element and don't know where to put it, look up its parent in the hashtable (since you'll have already seen the parent assuming these are ordered correctly).
Far as I'm aware there's no "display this blob of stuff as a tree" command, so you need to write some logic to get the number of tags to build the levels correct. But hopefully that will help you get started. :)