angular ng-repeat toggle menu element - angularjs

I have menu filled with $http method
<ul class="nav">
<li ng-repeat="(itemIndex, item) in menuItems.menu_items">
<a ng-click="showSubmenu(itemIndex)" ng-href="{{item.link}}">{{item.title}}</a>
<ul class="sub-nav" ng-show="isShowing(itemIndex)">
<li ng-repeat="subItem in item.submenu">
<a ng-href="{{subItem.link}}">{{subItem.title}}</a>
<span>{{subItem.desc}}</span>
</li>
</ul>
</li>
</ul>
And in controller
$scope.activeMenuIndex;
$scope.showSubmenu = function(item) {
$scope.activeParentIndex = item;
}
$scope.isShowing = function(index) {
return $scope.activeParentIndex === index;
};
Basically it works - click on menu element hides other elements and expands clicked one. The problem is when I click on opened menu element - it won't hide.
Maybe you know a better idea of ​​the solution, than my (incomplete) way?
Greetings!

You need to add condition like this:
$scope.showSubmenu = function(item) {
if($scope.activeParentIndex === item){
$scope.activeParentIndex = "";
}else{
$scope.activeParentIndex = item;
}
}

As #fliborn said, you can just put that logic in the showMenu. Or, for clarity, consider renaming showMenu(id) to toggleMenu(id) -- so it's more clear that it handles the closing case if you call it with an id that is active.
But, in either case, you'd do as #fliborn said and set the activeParentIndex to null if you toggle the id that is currently active.
From an Angular perspective, that's certainly a reasonable way to go (i.e. that's a good technical way to implement that behavior, if that's the behavior you want).
The other thing to consider is whether your approach is ideal from a UI perspective. Is it clear to your end users that they can click on the open one in order to close? If unclear, consider putting a "+" icon to the left side of all the inactive headers, and have a "-" show next to the active one (use ng-class if using glyphicons, or ng-show and ng-hide if you are just going to use text or graphics).
That way, when a user clicks to open a section, the "+" turns into a "-" as it opens up, and the user realizes that they can click on the header again to close it.

Related

Making bootstrap nav-tabs active using AngularJS Filtering

so I have a webpage with a table that gets updated according to filters on some nav-tabs I have.
I cannot make these tabs active, ie. you don't know which tab you're on and what you have filtered on. I assume this is because the only thing my tab does is filter angular;
<li role="presentation"><a data-ng-click="areaFilter = 'Odder'">Odder</a></li>
And nothing more. How do I work around this ? I have found solutions when there is a webpage redirect, but I dont do that here, I only update a table.
For anyone who might have this problem sometime in the future, I simply made this Jquery script to handle the nav-tabs or pills;
$(".nav-tabs li").on("click", function() {$(".nav-tabs li").removeClass("active");$(this).addClass("active");});

ng-click not working inside ng-switch

I'm beginner with AngularJs, and i have a lot of questions :/
Here's one of them :
I have links that i use to filter data. So when i click on link one, the value for the filter myFilter is one, etc.
Just to show you that my filters work, i putted two times the links (see here http://plnkr.co/edit/2G6mahkmyIixMJ1mEVKp?p=preview)
In the above links, i use ng-swich, cause i want, when i click on a link, to remove the link and only keep the text
In the bottom links, there are no ng-swich, so myFilter works perfectly
Is it possible, to make the ng-click inside the ng-swich work ?
The way you are approaching the issue involves far too much code duplication.
Also it is a bad practice to replace objects directly in the html. If you use a function bound to the scope it is cleaner and you won't run into child scope issues as much
Rather than creating four <ul> you could simply use ng-if within each <li> and use only one <ul>. This would also be a good case to create a very simple directive
HTML
<li>
<span ng-if="myFilter.trimestre==1">Avril - juin</span>
<a ng-if="myFilter.trimestre!=1" ng-click="updateFilter('trimestre',1)" href="#">Avril - juin</a>
</li>
JS
$scope.myFilter={};
$scope.updateFilter = function(key, val){
$scope.myFilter[key]=val;
}
DEMO

Making behavior of hyperlinks conditional in AngularJS

In an Angular app, I have a list of hyperlinks that need to have the following behavior:
if a certain condition is present (e.g. if a certain cookie has value x), a click on the hyperlink should open a modal window;
if this condition is not met (e.g. if the cookie has value y), the hyperlink should act in its usual manner and open the link in a new tab.
The hyperlinks are formatted as follows:
<a ng-href="{{article.url}}" target="_blank" ng-click="myFunction()">
{{article.title}}
</a>
I am puzzled by how to implement such a behavior. If I leave both ng-href and ngclick directives, then ng-href will insert the url and every click will open a page in a new tab. If I remove the ng-href directive, then the only way to open a link in another tab will be through javascript, but this is prevented by most browsers. I couldn't think of a way to make ng-href conditional (for example, writing <a ng-href="myCondition === true ? {{article.url}} : '#'"> doesn't work).
Could you please suggest a way of how to implement such a functionality in Angular?
This worked for me
<a ng-href='{{(element.url.indexOf("#")>-1) ? element.url : element.url + "client_id="}}{{credible.current_client_info.client_id}}'>{{element.title}}</a>
Here is a bit different approach that worked for me, didn't use ng-href at all:
HTML:
<a ng-click="myFunc()">{{article.title}}</a>
Controller:
$scope.myFunc = function() {
if (myCondition){
window.open($scope.article.url,'_self',false);
}
window.open("/#/",'_self',false);
};
Here is what I came up with. It looks kind of ugly, so if you have better suggestions, they are very welcome:
I wrote two separate anchor tags with different behaviors and made Angular choose between them depending on whether or not the necessary condition is met:
<a href="#" ng-if="checkCookies() === 'show popup'" ng-click="openArticle(article)">
{{$parent.article.title}}
</a>
<a ng-href="{{$parent.article.url}}" target="_blank" ng-if="checkCookies() === 'no popup'">
{{$parent.article.title}}
</a>
And in the javascript file, I wrote the checkCookies() function that looks up the value of the particular cookie.

AngularJS navigation with key events

I am trying to create navigation via key events between entries. Left and right keys to move towards either end. It works similarly to this JsFiddle i modified from someone although in the actual one each entry would have its own links to the previous and next one.
angular.element($document).bind("keyup", function(event) {
if (event.which === 37) {
$scope.$apply(function() {
$location.path("/Book/Moby");
});
} else if (event.which === 39) {
$scope.$apply(function() {
$location.path("/Book/Gatsby");
});
}
});
It seems to work fine in the JsFiddle but if you look at the console and see the amount of events fired from left and right keyups it will seriously slow down navigation. Each one of those events will run $location.path.
Any advice on how to listen to an event only once or flush old events would be great
You can unbind it before binding it.
angular.element($document).unbind('keyup');
First of all you have to check whether it is hide from bottom side or upper side.
Let's suppose element is li,which used to be most common dom .
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<ul>
then every li height is relative postion of ul .If there are 1000 elements then if you want find out the position of 900th element then you can find out with offset() but when you apply animate and make them visible you will got stuck that scroll is not moving element which is hidden it should be more .
use some Mathematics Height*nth:child will always give you a right position
providing fiddle expamle so that basic concept will get clear
http://jsfiddle.net/MGwVM/108/

What's a good way to control an angular-ui accordion programmatically?

I am using the accordion directive from http://angular-ui.github.com/bootstrap/ and I need to have more control over when the accordions open and close.
To be more precise I need a button inside the accordion-group that will close its parent accordion and open the next one (so basically mimic what clicking the next header would do if close-others was set to true).
I also need to do some validation before I can allow an accordion to be closed and the next one to be opened, and I also need to wire this up to click events on the accordion headers.
I am pretty new to angular and we're currently rewriting an application from Backbone+JQuery to Angular. In the Backbone-version we were using Twitter Bootstrap accordions and we were opening and closing them using JQuery. While we can still keep doing this I would rather get rid of JQuery DOM manipulation completely so I am looking for a pure angular solution to this.
What I've tried to do in terms of validation is
<accordion-group ng-click="close($event)">
and in my controller
event.preventDefault();
event.stopPropagation();
This obviously did not work as the DOM element is replaced by the directive and the click-handler is never added. I've been going over the source code (and found a few very nice undocumented features) but I'm at a loss over where to even begin solving this specific challenge. I was considering forking angular-ui and try to add this functionality to the accordion directive but if I can achieve this without modifying the directive that would be a lot nicer.
There is the is-open attribute on the accordion-group which points to a bindable expression. By using this expression you can control accordion items programatically, ex.:
<div ng-controller="AccordionDemoCtrl">
<accordion>
<accordion-group ng-repeat="group in groups" heading="{{group.title}}" is-open="group.open">
{{group.content}}
</accordion-group>
</accordion>
<button class="btn" ng-click="groups[0].open = !groups[0].open">Toggle first open</button>
<button class="btn" ng-click="groups[1].open = !groups[1].open">Toggle second open</button>
</div>
and the working plunk here: http://plnkr.co/edit/DepnVH?p=preview
For whoever the solution by #pkozlowski.opensource is not working (me for example) you could just force the component to accept the CSS that will close it (without transition that is).
The Theory: The angular directive gets expanded into standard HTML, div elements mainly, where the CSS styles give it the appearance of the accordion. The div with class .panel-collapse is the body of the accordion-group element. You can swap its second class from .in to .collapse along with a few other changes as seen below.
The Code:
$scope.toggleOpen = function(project) {
var id = '<The ID of the accordion-group you want to close>';
var elements = angular.element($document[0].querySelector('#'+id));
var children = elements.children();
for(var i = 0; i < children.length; i++) {
var child = angular.element(children[i]);
if(child.hasClass('panel-collapse')) {
if(child.hasClass('in')) { // it is open
child.removeClass('in');
child.addClass('collapse');
child.css('height', '0px');
} else { // it is closed
child.addClass('in');
child.removeClass('collapse');
child.css('height', 'auto');
}
}
}
};
As we are talking about Angular, it is very possible that you are generating the accordion through an ng-repeat tag. In this case you can also generate the id's for the elements like:
<accordion-group ng-repeat="user in users"
is-disabled="user.projects.length == 0"
id="USER{{user._id}}">
Given a Mongoose model User, notice that the id I am giving is not user._id but has 'USER' appended in front. This is because Mongoose might generate id's that start numerically and querySelector does not like that ;-) go figure!

Resources