AngularJS using ng-repeat to display Hierarchical Data - javascript

So I've been trying to build a nice way to represent hierarchical data in my application. I've created a slide effect for some bootstrap badges I am using to display some sub-categories using AngularJS.
I've created (with some help from you stackoverflow-ers!) the following example which works for data of the type parent and child. ie. You can't be a parent and child at the same time, which is needed for my real world example.
<ul>
<li ng-repeat="category in categories"
ng-init="isChild = category.category_type == 'child'"
ng-show="category.category_show"
class="badge-slider">
<span class="badge {{ isChild ? 'badge-c' : 'badge-p' }}"
ng-click="isChild || updateResults(category)"
ng-bind="category.category_name">
</span>
</li>
</ul>
I am struggling to understand what is the best way to change the code so it is able to work for the additional 'parent and child' category_type. This 'parent and child' category_type is needed for creating a way to browse a directory structure.
In the example above, it relies on the boolean value 'isChild' and the ternary operator, which doesn't work when we introduce the 'parent and child' category_type.
Anyone got any ideas?
Here is a link to a PLNKR which demonstrates the sliding functionality working for simple the parent-child relationship: http://plnkr.co/edit/9CiXW1YAoPj80x6PtBW3
EDIT 1:
I've created another PLNKR to handle the 3-tier nature of the hierarchical relationship. It works fine, except it doesn't display 'parent and child' elements with the corresponding badge.... http://plnkr.co/edit/YoRI578GHE91t6torCUt

Here is how I solved this:
Modified categories data structure
Created inline angular template in html file
Create new CSS class for "parent and child" elements
You can view the working Plunker
Here is a Snapshot of the result:

Your data structure is not currently hierarchical. I would suggest a structure such as this for your categories list (probably a better name name), where each element in an array has an array "children" as a property.
$scope.categories = [
{category_name:"apples", children: [
{category_name:"bramble", children: [
{category_name:"red"},
{category_name:"green"}
]},
{category_name:"granny smiths"},
{category_name:"pink lady"}
]},
{category_name:"oranges", children: [
{category_name:"satsuma"},
{category_name:"nectarine"},
{category_name:"mandarin"}
]}
];
Here is a plunkr of an inefficient way to represent this (templates and directive would be a more effective way to work on the recursive aspect versus doing it manually).

Related

Is it possible to mix two GraphQL queries into one query?

I am using Gatsby as a frontend to a WordPress backend. I have successfully fetched the menu items but I now need to link them to the pages I have created. I have added the Menu Links in my Gatsbyconfig.js but I have no idea on how I can go about mapping it to the menu items at the same time as the menu itself. It ends up contradicting each other. Is this possible to do? I am quite new at graphQL. Never touched it till this project. Below is the GraphQl Query
{
allWpMenuItem(filter: {menu: {node: {name: {eq: "Navigation Menu"}}}}) {
edges {
node {
label
}
}
}
site {
siteMetadata {
title
menuLinks {
name
link
}
}
}
}
The label holds the name for each menu and the link holds the link to the pages I have created. I am trying to fix this into this bit of code
<div>
{props.allWpMenuItem.edges.map(edge =>(
<a href="#" key={edge.node.label}>
{edge.node.label}
</a>
))}
</div>
I am trying to query the menu links change the anchor tag to the link item and then point it to the menu link.
The short answer is that you can't, natively each query is a separate entity. However, you can combine queries using createResolvers, for further details check: https://github.com/gatsbyjs/gatsby/discussions/28275 (thanks LekoArts for the feedback).
However, you have a few approaches to bypass this limitation. Given that each query is transformed into a standalone JavaScript object, you can always manipulate them using native JavaScript filtering or doing whatever you need. The idea is to create an empty object and populate it with links and labels, in a single loop or using two different, then, in your component, iterate through this object instead of through the props like you are doing now.
I can't create a minimal example without knowing the internal structure or without knowing what's inside menuLinks.name.
By the way, if you are using internal navigation I would hardly suggest using <Link> component, among other things, using the #reach/router (extended from React's router) will only render the necessary parts of each component, creating smoother navigation than using native anchor tag, what will refresh all the page.

Class binding based on status of objects nested in v-for loops

i have an issue correctly displaying the status of my nested objects.
The Structure is as follows.
A -> B -> C
A contains a List of B's and B contains a List of C's.
So there are usually 2+ Bs with 2+ Cs each.
The entire structure is basically a tree.
This is a very simplified version of what i am trying to do:
<div v-for="a in As">
<i v-if="a?.showWarning" class="fa-exclamation-triangle text-danger"/>
<div v-for="b in a.Bs">
<i v-if="b?.showWarning" class="fa-exclamation-triangle text-danger"/>
<div v-for="c in b.Cs">
<i v-if="c?.showWarning" class="fa-exclamation-triangle text-danger"/>
</div>
</div>
</div>
A, B and C each have a .showWarning that is either an true or false.
I want to display a warning symbol on each Component that has an error.
Sa there could be an error onToplevel (A), or further down the structure (B,C).
I tried using v-if="c?.showWarning" on my -tags showing the symbol.
This works initially, but a change to c.status will NOT re-evaluate the v-if tags so the warning symbol will not vanish once the user corrects the error.
I tried using a computed method as suggested but the problem is that i need a parameter else i wont know where in the structure i am so i cannot really find out using the data() ...
I can just create a method with a parameter and use it in the v-bind:class="evalueateError(object)" but that will also not update on change of the corresponding property.
I can add :key="object?.showWarning" but that will re-render the entire component when the property changes ....
I could just use vue.js to set costum ids on the html objects and do it myself in javascript but i rather use vue.js for this.
But i ran out of options here what is the correct way to do this???
I want to color-code and display error symbols in my hierarchy depending on the state of the corresponding object in my hierarchy.
Any hints are greatly appreciated.
Kind Regards
Oliver

Writing a directive to encapsulate multiple directives Angular

I'm using Angular 1.x and I have a section of code that I'm looking to repeat quite a bit, so I wanna throw it in a directive. The trouble is, it's somewhat complicated and I'm not sure how to begin writing it.
Essentially, it's a section of the page that displays various card directive and with infinite scrolling and perfect scrollbar.
<perfect-scrollbar refresh-on-change="myScope.data">
<div class="limit-columns">
<masonry masonry-options="{gutter: 30, isFitWidth: true}">
<user-card class="masonry-brick" ng-repeat="item in myScope.data"></user-card>
</masonry>
<div class="infinite-scroller" infinite-scroll="myScope.showMore()" infinite-scroll-tolerance="5"></div>
</div>
</perfect-scrollbar>
Perfect-scrollbar and masonry are both angular libraries on GitHub. Infinite-scroller is one I wrote myself, but works as you'd expect.
myScope contains a data attribute that is a list of objects containing a card's data. myScope.showMore is a function that adds items to that myScope.data list. Perfect-scrollbar also takes the refresh-on-change attribute which watches for changes on a particular object, in this case the list.
Ideally my directive would look something like this:
<card-scroller gutter="30" tolerance="5">
<some-card ng-repeat="achievements.data"></some-card>
</card-scroller>
But I'm not sure how feasible this is. Thanks!

Directive rendering an HTML output which contains rendered HTML in an attribute value

I'm trying to render an HTML like follows:
<div class="aClass" ng-controller="aCertainCtrl">
<span class="aSubclass" certain-attribute="<ul class='menu'><li class='selected'><a href='/'>Home</a></li><li><a href='/about'>About</a></li></ul>">
</span>
How is it possible to combine two directives (from my understanding it should be done using two), one for the element itself and the other to be compiled once the first has already been compiled, giving as an output an HTML markup embedded into the certain-atribute value?
Of course the aim of achieving this is allowing to render a certain HTML based on some model array, say the items of a menu, templating those items on how they will look like in terms of HTML, and embedding the ouput into the certain-attribute value.
I'm kind of newbie in AngularJS, so that still not controlling well the whole Directives process and its possibilities.
I know this is not the way to go, but I would like to see how to implement such a crappy thing in angular :D
Thanks in advance.
EDITING: Rewriting a bit for those ones who didn't understand well the issue
My goal is to have some HTML markup as a value inside an inline attribute of a certain element (even though is crap and nasty). Say <span data-some-markup="<p>Hello</p>"></span>.
I would like to use an attribute directive like this:
<div ng-controller="somecontroller"><my-custom-element></my-custom-element></div>
<my-custom-element> directive rendition will depend on someController $scope.data = [{name: Home, path: '/'}, { name: 'About', path: '/about' }];
The desired output will be something like:
<div class="aClass" ng-controller="aCertainCtrl">
<span class="aSubclass" certain-attribute="<ul class='menu'><li class='selected'><a href='/'>Home</a></li><li><a href='/about'>About</a></li></ul>">
</span>
</div>
Question is, how can you do this entirely with AngularJS?

How to observe multiple states in a handlebar template from an ember controller or component

I'm new to ember and am struggeling with the typical "how would one do that"-Problem. What I've got is fairly simple and I know how to do it, but my way is so complicated that I do not think it's correct.
The case:
<ul>
<li>{{link-to top-level}}</li>
<li>{{link-to another-top-level</li>
<ul class="submenu">
<li>{{link-to submenu</li>
</ul>
</ul>
What should happen is:
When a route is clicked, the corresponding list element should become active.
When a submenu is clicked the corresponding upper ul-element should get the class open
It's a fairly simple case with jQuery, but I understand that this is not scalable and abstracted and stuff.
Therefore I started with this approach:
Create a controller / template construct for the entire navigation to handle it's state (there are some other things I need to check as well, so it came in handy).
since ember adds the active class to the anchor tag I created a component to observe that:
Like:
export default Ember.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews').anyBy('active');
}.property('childViews.#each.active')
});
Replacing the li elements with {{linked-list}} does indeed work.
But what next? Do I need to add another component to watch the component to watch the build in behaviour of active links? Do I have to write dedicated MVC-Classes for all the DOM Elements?
There has to be a simpler way, I think. I already created a whole lotta files for such a simple behaviour that I'm thinking I'm totally on the wrong track.
My gut feeling is: That is view logic and the view should just observe a few states in the template and that's it.
What's the leanest approach to the problem?
I don't know if I understand your question right, but why you want to add the class open to the corresponding upper element? It automatically get active assigned. And with correct CSS it should work as expected.
I have created a small example demonstrating what I mean. Please have a look and let me know, if that's the solution for you or what's your problem with this solution.
http://emberjs.jsbin.com/wifusosadega/7/edit
EDIT
Here is a Bootstrap flavored version: http://emberjs.jsbin.com/wifusosadega/9/edit .

Categories

Resources