AngularJs multi level data drilling - javascript

I'm kind of a newbie in AngularJs and I have a complex JSON that i need to get data from to a auto complete.
I need to create an auto complete for ONLY the child elements in the the stucture without showing the parent categories.
Getting to the parents is easy, data[2].JobCategories and binding that to the ng-repeat and binding "jobParentCategoryModel.JobCategoryName" to the model does the trick.
But drilling to get only the children confuses me in the angular way. The way i see it, what I need to so is to to get only the children from the factory in new array of categories children and work with that. But for some reason in my mind it seem wrong to drill in the factory... Don't know why, just doesn't seem the angular way to do things.
PS. When looking at examples i saw lots of nested ng-repeat examples but i don't want to create the extra parent DOM elements for each child, so using nested repeats seams over head. But again I don't want to destroy the data structure (It is not two way binding so I don't know if it matter if i change the model at all).
What is the best practice to do this kind of deep drill down in angular?

I assume that you want to use only the child elements for instance in an ng-repeat but you do not want to create a separate data structure, that holds only these elements, in your scope. In this case I would write a function that extracts the elements and refer to this function in the ng-repeat:
<li ng-repeat="eachElement in getChildElements()">...</li>
This way you avoid redundancy and inconsistencies since your list automatically adapts to changes in the data structure.

Related

How to save the open/closed state of an object

I've made a component that visualizes an object where array's and nested objects are collapsible.
It works by looping through all the keys/indexes and using the appropriate render function. Right now the collapse and extend actions are purely CSS class-based.
The issue I have right now is that I need to make it so the collapsed/extended state persists. So basically I need a way to store the collapsed state info. and read it later on. I'm not really sure how to even start.
The state should persist even when the object is modified. So when an new item gets pushed in the middle of the array it should still open the same thing. What data structure should I use for this and how would I read it?
The reason I'm not posting any code is that I don't think it's necessary, I'm purely interested in how the data should be structured for the collapsed/extended state of an array/object so it persists when updates are made to the object/array.
I've tried making some type of "breadcrumbs" that follow the structure of the object but then I realized that it won't persist when changes are made.
Any ideas? Is this even possible without some hardcoded unique ids?
Edit 1: point 4 it's not optimal and can be done better - after you finish rendering the main object to the DOM, loop through the state object and for each path, find the DOM node and expand it.
Edit 2: instead of 'index1.nestedIndex2[1].nestedIndex3' you can do 'index1.nestedIndex2.1.nestedIndex3', makes your code simpler
Edit 3: no need to use lodash (edited point 1)
I hope I understood your scenario correctly.
In order to persist the expanded (or collapsed) state, you have to:
create an object that stores the paths to the indexs that you want expanded, like this {'index1.nestedIndex2[1].nestedIndex3': true}. You can do this when clicking to expand. Of course, this means you should know the current index and it's parents when you click - one way to do this is by having a DOM attribute holding the index, on each element. So when you click a node to go up recursively until you reach the top element, and build that string path
Convert the state object to a string using JSON.stringify and store it in localStorage (https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). localStorage.set('expandedState', JSON.stringify(stateObject)). If you need to store the state for multiple data objects, you have to use some specific key instead of 'expandedState'
In the code, before rendering the main object, convert the string state from localStorage back to an object using JSON.parse
While rendering your main object, you have to build the path for the currently rendered node and check if it can be found in the state object. If yes, expand it by adding your css class on it. To build back the path, it's more optimal to build it as you render each node rather than using the same method used in point 1, but that would also work (but slower, so for really big objects will be a problem, I think)

React DIV dynamic layout algorithm to create a box-in-box view

I am trying to represent the following onto a web page. - that is a data model representation illustrating objects, attributes and child objects in a parent child hierarchy.
I was thinking to create a generic React component that would be able to store a single data object, but then also have that same object accept child instances in a sort of dynamic mechanism.
The result would be a nested-box type view, which would show all elements and nested children.
the child div, would need to have some sort of layout feature (much like the grid-layout features of popular UI frameworks (material-ui, Scemantic-ui, Zurb foundation)
at the end, The "model" would look something like this.
I dont even know where to start to build something like this. I am looking for some ideas to build a UI like this... the intention at a later stage would be to enable something like React-draggable to allow dragging of elements.
For infinite tree structure rendering purposes, you might need to look at recursion usage in React. I found some resources for you:
https://dev.to/baso53/recursive-rendering-in-react-building-a-universal-json-renderer-f59
https://medium.com/#suraj.rajan/recursion-using-reactjs-components-3c871f99fb2f
Basically, you need to create a function in the class which returns an instance of your class.

How to speed up AngularJS rendering with big scopes?

I'm developping an angular app right now for my company, but I reached a point where the app became extremely slow so I tried tunning it by using onetimebind everywhere I can, track by ...but it's faster to load at first but still laggy, it is composed of a pretty much huge nested objects, I've counted the total number of objects, it starts at 680 and can go up to +6000 for normal use of the app, oh yeah I should precise that the app is generating a form and pretty much +90% of the objects in the scope belongs to an input and are updated each time the client click(radio) keyup/change(text).
It also have like 5/6 arrays composed of objects and the array gets bigger/smaller accodring to the clients choice, and that's where it gets laggy, each time I add an object to the array, it takes like a second to render it, so I tried using nested controllers thinking that if the child of an object is updated Angular will render only this child and not all the others, but somehow the app got even slower and laggier :s (it's a bit faster when I use ng-show instead of ng-if but the memory used jumps from ~50Mb to ~150Mb)
I should also precise that the form is in a wizard style, and not all the inputs are displayed at once, the number of inputs that are displayed are between 10%-20% of the total inputs
Has anyone encountred this problem before? does anyone know how to deal with big scopes?
Sad to say, but that's intrinsic of the view rendering in angular.
An update in the model triggers a potential redraw of the entire view. No matter if you have elements hidden or not. The two way data binding can really kill performances. You can consider evaluate if you need to render the view only once, in that case there are optimizations, but I'm assuming that your form change dynamically, therefore a 2 way data binding is necessary.
You can try to work around this limitation but encapsulate sub part of the entire MVC. In this way a contained controllers only update the specific view associated to that scope.
You may want to consider using react (that has as first goal to address exactly your use case)
Have a look at this blog post for a comparison of the rendering pipeline between angular and react Js.
http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/

ng-model works with ng-repeat but not with collection-repeat [duplicate]

i got a little bit confusion about ng-repeat and collection-repeat
ng-repeat
<ion-item ng-repeat="item in items" >
...
</ion-item>
collection-repeat
<ion-item collection-repeat="item in items">
...
</ion-item>
the above both lines are doing well and same.
Please let me know if any difference there. also i have 1000 items, so which one is better for this scenario? and how's the rendering speed and what about the performance status ?
collection-repeat is not part of angularjs. As far as I can see it's coming from Ionic Framework. As documentation says collection-repeat was created to be used instead of ng-repeat as it might work better with large number of items.
collection-repeat allows an app to show huge lists of items much
more performantly than ng-repeat
Collection repeat is Ionic's buttery-smooth solution for scrolling huge lists. collection-repeat can be used for large list of items and it has high performance when process huge data set.It renders into the DOM only as many items as are currently visible.This means that on a phone screen that can fit eight items, only the eight items matching the current scroll position will be rendered.
ngRepeat part of the angular Core module. The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
Based on the use case you can use any of the options. However, if you use ionic framework for mobile then I would suggest to go for Collection repeat.
Further, If you need to use ng-repeat, it is recommend to process data in the server side and request part by part. This way you can expect high performance and less processing in the client side. Another option is store the large data set in the client browser and then process data using that data set.
In case of 1000 elements I would strongly recommend the collection-repeat. It's more flexible, and it renders as many items from collection as many can fit the screen. the rest is loaded dynamically, you can even use 200k collection and it will go smooth as well. ng-repeat renders the collection items until it's done, so it will give you much worse performance.
So collection-repeat it is my friend.
Good luck with your development!
Note: collection-repeat is not a part of angular core, look here for more : http://ionicframework.com/docs/api/directive/collectionRepeat/
From what I'm understand is ng-repeat is suitable to use for small numbers of item and collection-repeat is very suitable to use for huge numbers of item. Its actually about the performance when it comes to view/render in a device. For more understanding you can see this video, it really help me to understand both of it.
In Simple Word -
Ionic has a collection-repeat directive that you can use, instead of ng-repeat, when you need to display very large lists.
How it works?(Deep)
The module is divided into two components, $repeatFactory (a service where helper functions are defined) and collectRepeat (a directive where most of the logic lives).
The most important takeaway from the factory is the repeatManager method. It is the contructor that is instantiated at the beginning of the link function of the directive and is responsible for maintaining the state of the scrolling view.
On creating a new instance of repeatManager, it's also necessary to generate a new object (or map) to provide as reference for all the items that have already been transcluded, rendered, and whose scope has been updated. The enclosing parent element must also be registered so that we can later change it's height to the height of all the items in the collection.
Next, a watch is set on the collection with an anonymous function set to be invoked whenever the collection changes. This is where the bulk of the logic resides. It's split into three steps.
Transclude and render the first element of the collection so that the height and other properties of each individual item may be registered, the height of the parent div adjusted, and the size of the viewport calculated
With the size of the viewport determined, loop over and render the n number of items that will fit inside the viewport (plus a few extra for smoothness).
Set a 'scroll' event listener on .scroll-content to return the scrollHeight of the first element of the collection and render only the necessary elements.
There are a few additional tidbits (also known as comments) available in the code below. It should help alleviate some confusion if you have trouble following the above synopsis. The module is also available on github.
GitHub
Differences - Working Example
Code Here

With d3.js, how do you modify corresponding nodes when you have multiple selections for the same data?

I use the same data to create few different parts of my visualization. I want to create a mouseover event on one node of a selection that modifies the corresponding node in another selection. What is the idiomatic d3 way to do that?
(I know I can use the id, or nest the selections, or store info in a map within scope of both selections...but these all seem messy strategies to me)
As a side note, if there is a good "d3 idioms" reference that could be very helpful when doing common tasks.
Selections are generally transient; you don't need to keep them around if you can just as easily reselect them from the document. So, selecting by id is a reasonable option.
If you don't want to give your elements unique ids (which is sometimes a pain when creating visualizations generically), then another option is to store a reference to the associated elements via the bound data. For example:
selection.each(function(d) { d.element = this; })
Now, assuming that the same data d is bound to another element, you can d3.select(d.element) to select the original element. You might choose a more specific name than "element" to make it clear which of the two (original, and decorative) elements you are referring to.
On the other hand, if you have different data on different elements, then you'll need a different way to link them together. If you don't want to use an id or another suitable selector, then a map of references is reasonable too.

Categories

Resources