I have the following HTML markup:-
<ul class="dropdown-menu">
<li ng-repeat="track in songTracks track by $index" ng-class="{active: $index===selectedIndex}">
<a ng-click="setSongTrack(track)">
{{track.name}}
</a>
</li>
</ul>
In Angular, I use this:-
$scope.setSongTrack = setSongTrack;
$scope.selectedIndex = 0;
$scope.index= function(i) {
$scope.selectedIndex=i;
};
Which passes to DASHJS like so:-
function setSongTrack(track) {
musicPlayer.setSongTrack(track);
$scope.selectedIndex = track;
}
musicPlayer being the instance of DASHJS, which parses my audio tracks. This all works - I get a bunch of list elements with the track names, I can click them and independently load each track as expected. However, I need to add some visual way of informing the user which track is currently selected, which is probably best done by way of adding a CSS 'active' class.
Currently this just sets an 'active' class to the first list element, regardless if I click another and it changes the track. If I click another list item, the 'active' class is removed from the first list item. I need the 'active' class to only be on the currently selected track, i.e. the selected list item.
Now I'm stumped. I've read over a lot of similar SO questions and haven't located something which I can get to work.
Can anyone enlighten me? Fairly new to Angular and so, I'm still a bit of a noob with it.
Instead of using the index of the track to mark it as selected, use the track itself. Write a function like trackSelected() which takes a track, and use that to apply a class with ngClass. Eg...
HTML
<ul class="dropdown-menu">
<li ng-repeat="track in songTracks track by $index" ng-class="{ 'active': isSelected(track)} ">
<a ng-click="setSongTrack(track)" ng-bind="track.name">
</a>
</li>
</ul>
JS
$scope.selectedTrack = null;
$scope.setSongTrack = function(track) {
musicPlayer.setSongTrack(track);
$scope.selectedTrack = track;
}
$scope.isSelected = function(track) {
return $scope.selectedTrack === track;
}
This is because you may add or remove tracks from the list in your view at some point, and then the selected index will be invalid.
just go like this:
<ul class="dropdown-menu">
<li ng-repeat="track in songTracks track by $index" ng-class="{active: track===selectedTrack}">
<a ng-click="setSongTrack(track)">
{{track.name}}
</a>
</li>
</ul>
and in your js
$scope.selectedTrack = undefined;
$scope.setSongTrack = function (track) {
musicPlayer.setSongTrack(track);
$scope.selectedTrack = track;
}
This way you can also do stuff like presenting the selected track in your player like below just with one click, no need to fiddle with indexes and such.
<h1>{{selectedTrack.name}}</h1>
<p>
<span>{{selectedTrack.totalTime}}</span>
</p>
Here is a simple fiddle
Alternate Solution
Going the $index way should be like this(Just explaining to help you see what you did wrong)
<ul class="dropdown-menu">
<li ng-repeat="track in songTracks track by $index" ng-class="{active: $index===selectedIndex}">
<a ng-click="setSongTrackIndex($index)">
{{track.name}}
</a>
</li>
</ul>
Notice that i chanced setSongTrack(track) to setSongTrackIndex($index). Then you would of course change your js accordingly, like so:
function setSongTrackIndex(trackIndex) {
musicPlayer.setSongTrack(songTracks[trackIndex]);
$scope.selectedIndex = trackIndex;
}
$scope.setSongTrack = setSongTrack;
$scope.selectedIndex = 0;
If you need further explanation please comment.
Related
This is html:
<div class="main" ng-controller="companies">
<ul style="list-style: none;">
<li ng-repeat="company in companies | orderBy:'name' | filter:companies_filter">
<a href="#!/companies/{{company.id}}" ng-click="companySelected(company)">
{{company.name}}
</a>
</li>
</ul>
</div>
This is router.js:
...
.when('/companies', {
templateUrl: '../html/companies.html',
controller: 'companies'
})
.when('/companies/:companyId', {
templateUrl: '../html/companies.html'
});
....
This is working:
$scope.companySelected = function(company) {
console.log(company);
}
The list is pretty huge. If I scroll down to bottom and click on a company, the list gets back to the top. Same happens when I enter company name to filter and click, again, it gets back to its initial view. How can I fix it so that it stays where it is?
you are looking for $anchorScroll.
Here is the documentation: anchorScroll
When you return from company page to the list, you might need to add hash Id of the element that you clicked earlier. To that, you first need to add ID to li element like below.
<li id={{company.id}} ng-repeat="company in companies | orderBy:'name' | filter:companies_filter">
<a href="#!/companies/{{company.id}}" ng-click="companySelected(company)">
{{company.name}}
</a>
</li>
while coming back to list page, call $anchorScroll(); You can send hash as a parameter in the anchorscroll or update the location hash like below before calling $anchorScroll();
$location.hash('id_value');
I have Menu list which contains Sub-Menu as shown in the code below.
<li class="current">
<span class="icon4"></span>Subscriptions
<ul class="sub-menu">
<li>View Subscriptions
</li>
<li class="#((ViewBag.PageName == " Subscription ") ? "active " : " ")">Manage Subscription Plans
</li>
</ul>
</li>
<li class="current">
<span class="icon5"></span>Administration
<ul class="sub-menu">
<li class="#((ViewBag.PageName == " AssetPage ") ? "active " : " ")">Assets
</li>
<li>Configure Text
</li>
<li>Error Log
</li>
<li>Product Settings
</li>
</ul>
</li>
<li class="current">
<span class="icon6"></span>Promo Codes
<ul class="sub-menu">
<li>Manage Promo Code
</li>
<li>Used Promo Code
</li>
</ul>
</li>
Here Subscription,Administration,Promo Codes are Menu Lists which contains Sub-Menu Lists under them.
The thing is I want to apply class=current dynamically when a user clicks on Subscription,Administration,Promo Codes`.
And I am doing this in LayoutPage of MVC.
Any help will be appreciated.
Here you have a working solution: https://jsfiddle.net/c4h3sup9/
You have to use a little bit of Javascript for that.
You have to give the listitems a other class name like in my example "operator"
document.body.addEventListener("click", function(e){
if(e.target && e.target.className == "operator"){
var actives = document.getElementsByClassName("active");
actives[0].setAttribute("class", "operator");
e.target.setAttribute("class", "active");
}
});
for this example you need to assing one element as active from the beginning.
Note:
LI elements are never parents of UL.
The order is:
Unordered List (Plural) -> List item (Singular, Child).
You might want to correct that as it is not standard conform.
To add the class name to the parent <li> element, give the main links a class name. Assuming you also want to remove it from any <li> elements that already have it, also give them a class name
<li class="container">
<span class="icon4"></span>Subscriptions
and the script will be
$('.mainmenu').click(function() {
$('.container').removeClass('current'); // remove any previous
$(this).closest('.container').addClass('current');
});
In addition, if when you navigate to one of the views with this layout, and what to add the class name to the appropriate element, then you can give the <li> elements an id attribute
<li id="subscriptions" class="container">
....
</li>
<li id="administration" class="container">
....
and in the GET method, pass the value of the id to the view (e.g. using ViewBag
public ActionResult ConfigureText()
{
ViewBag.Menu = "administration";
....
return View(...);
}
and add a script that runs when the page first loads
var menu = '#ViewBag.Menu";
$('#' + menu).addClass('current');
In my Meteor app I need to add class to navigation item when page is active.
How can I do that?
Template.header.helpers({
getActiveClass: function(routeName) {
var active = Router.current() && Router.current().route.getName() === routeName;
return active && 'active';
}
});
<li class="{{getActiveClass 'home'}}">
Home
</li>
Note if you want to make the element active for more than one route you have to modify the getActiveClass helper a little bit.
Add Package zimme:iron-router-active
Use as follows:
class="{{isActiveRoute regex='<route>'}}"
For example
<li class="{{isActiveRoute regex='dashboard'}}">
<a href="{{pathFor route='dashboard'}}"><i class="fa fa-th-large"></i> <span
class="nav-label">Dashboard</span> </a>
</li>
So whenever the Route is active, Link will be Active.
I'm working on a project where I'm about to use the jQuery plugin mmenu (http://mmenu.frebsite.nl/).
I already had to do some customisations to fit my needs but I don't know what to do with my current issue. In mmenu, when i click on an list entry I will be navigated to the given href and the clicked item becomes active by mmenus css class ".mm-selected". So far so good.
Now I want to additionally mark the parent list item (and thats parent, and so on until menu root) as selected. This should be so when the user goes one level up in the menu he should be able to see in which category he currently is.
Below is an example of the menus html structure after mmenu was applied. This shows the code for a menu with 4 main pages (index, page1, page2 and page3) and 3 subpages (2.1, 2.2, 2.3).
<nav id="nav" class="mm-menu mm-horizontal mm-offcanvas mm-hasheader mm-current mm-opened">
<ul class="mm-list mm-panel mm-opened mm-current" id="mm-0">
<li class="mm-selected">
Index
</li>
<li>
Page 1
</li>
<li>
<a class="mm-subopen mm-fullsubopen" href="#mm-1"></a>
<span>Page 2</span>
</li>
<li>
Page 3
</li>
</ul>
<ul class="mm-list mm-panel mm-highest" id="mm-1">
<li class="mm-subtitle">
<a class="mm-subclose" href="#mm-0">Page 2</a>
</li>
<li>
Page 2.1
</li>
<li>
Page 2.2
</li>
<li>
Page 2-3
</li>
</ul>
</nav>
It would be great if you had some idea where and how I could achive such functionality.
So, for the moment I did some jQuery hacking. This seems to work for my case mentioned above. It should also work for deeper menus as it's using recursion. If there's a better way to achieve this, please let me know.
var nav = $("#nav");
nav.find("li > a:not(.mm-subopen)").click(function () {
nav.find("li.active").removeClass("active");
selectParentEntry($(this));
});
var selectParentEntry = function (a) {
var li = a.parent(),
ul = li.parent(),
back = ul.find("li > a.mm-subclose").first(),
cID = "#" + ul.attr("id"),
pID = back.length ? back.attr("href") : null;
li.addClass("active");
if (pID != null) {
var subOpen = nav.find("ul" + pID + " > li > a.mm-subopen").filter(function () {
var self = $(this);
if (self.attr("href") === cID) return self;
}).first();
if (subOpen) selectParentEntry(subOpen);
}
};
I have a list which I am populating through ng-repeat and in that list I have a nested list with a button on each . Now upon clicking that ul i want to load list from server which can be dynamic. Currently it is overiding the field. Here is my code.
<ul class="qtree">
<li ng-repeat="Childgroup in childGroups">
<span class="glyphicon glyphicon-remove del-btn-tree" data-ng-click="deleteChildGroup(Childgroup.id)" ></span>
<label for="test1">{{Childgroup.name}}</label>
<input type="checkbox" id="{{Childgroup.id}}" data-ng-click="getEntities(Childgroup.id)" />
<ul>
<li ng-repeat="entity in entites">
{{entity.name}}
</li>
</ul>
</li>
</ul>
JavaScript:
$scope.getEntities = function(groupID) {
$scope.entites = [];
var entitiesGroup = ManageGroupsFactory.getEntitiesForGroup(groupID);
entitiesGroup.success(function(entitiesGroup) {
if(entitiesGroup != "") {
for(var i=0; i<entitiesGroup.length;i++) {
$scope.entites.push(entitiesGroup[0]);
}
}
});
entitiesGroup.error(function(data,status){
// TODO for errors
});
The first list populates fine through ng-repeat. Now what I want is upon clicking the checkbox it load's it's specific entities from server and populates in it and every checkbox will have different entites inside it.
Any ideas ?
One technique that has a good chance of working is to generate unique id's for each of the elements in the sub lists. You should be able to combine the parent list name + some value of the inner loop to generate a unique id, eg:
<li ng-repeat="entity in entites track by $id(Childgroup.id + entity.name)">
{{entity.name}}
</li>
Let me know how that works for you.