Using ng-class to enable pagination - javascript

I'd like to create a pagination control that shows the user what page they are on. I'm having trouble using ng-class to style the page links properly.
After I get the count of the data, I setup $scope.pages to be [0,1,2..n] where n is the count / itemsPerPage. The html looks like this...
<ul class="pagination">
<li ng-click="prevPage()"><a>«</a></li>
<li ng-repeat="page in pages"
ng-class="(page==$index)? 'active' : ''"
ng-click="selectedPage(page)"><a>{{page+1}}</a></li>
<li ng-click="nextPage()"><a>»</a></li>
</ul>
But this markup results in all <li> getting the active class. I can see with debugging that $index is advancing within the li's, and I can see that page is the expected value (I can also see the style looks right when I hard-code it), so why doesn't the conditional styling work as I have it above?
Thanks in advance.

You should not be evaluating the expression against $index. If you desk check the repeat loop for every iteration, this is what you're evaluating:
page $index
0 == 0 // true
1 == 1 // true
2 == 2 // true
Instead, what you should do, is add a separate variable to the scope that tracks the current page, if you don't have one already. For illustrative purposes, let's call it currentPage. Then you can change your expression to:
ng-class="(page === currentPage) ? 'active': ''"
Additionally, in your selectedPage() function you would update currentPage to the page the user selected (i.e. $scope.currentPage = page).

Related

Only show unique date values in ng-repeat list

I have a unordered list generated by an ng-repeat. In each list item I have a month header and a blog post.
I only want to show one instance of each month name but I can't work out a nice way of doing this without some really hacky jQuery.
Is there a way I can somehow detect this value in Angular and use an ng-hide to only show the first one of each type?
Maybe something like this could help, providing that your same-month posts are adjacent. If they are not, maybe it's okay to show the date altogether:
plnkr code example
Basically:
<li ng-repeat="post in model.blogPosts">
<span ng-show="model.blogPosts[$index - 1].date !== post.date">{{post.date}}</span>
<br>
<span>{{post.post}}</span>
</li>
Edit:
(Sorry for the default ul li styling, such uglyness)
You should probably modify your data to achieve this. Turn your post list into an object like
$scope.postsByMonth = {
October: [//...october posts],
November: [//...november posts],
//...
};
Then you can do something along these lines
<li ng-repeat-start="month, posts in postsByMonth">month<p>posts[0]</p></li>
<li ng-repeat-end ng-repeat="post in posts.slice(1)"><p>post</p>

Fill a DOM element depending on my current route with Angularjs

I'm doing a multipage website and using some features of AngularJS, but I'm pretty new to it so would like some help. It uses ngview to load subpages, depending on the link clicked on my index file.
But on this index file I have a header that I would like to change depending on the current view. Sample:
<h1>
{{currentheader}}
</h1>
<ul class="nav navbar-nav">
<li ng-class="{ active: isActive('/')}">
Home
</li>
<li ng-class="{ active: isActive('/rooms')}">
Rooms
</li>
</ul>
<ng-view></ng-view>
I use a 'isActive' class on the navigation to set the active list item depending on my location.path(). Rendering the ngviews is working fine.
But i can't find a way to modify that header based on my active link. I could do that with jquery but I believe Angular has an easier sollution?
Thanks
EDIT:
found a sollution based on this
Update parent scope variable
An option that lets you put all the logic to update this header in one place, instead of dividing the logic into the controllers of your child views, is to listen for a $locationChangeSuccess within the controller of your parent view.
function updateHeader($scope,val) {
$scope.currentheader = val; // Obviously you'd make this more intelligent.
}
$scope.currentheader = "Initial Value";
$scope.$on('$locationChangeSuccess', function (event, toUrl, fromUrl) {
updateHeader($scope,toUrl);
});

AngularJS change <li> element tags based on condition

I have a list in which each list element can have different styles. Simple HTML looks like this:
<li class="active">One</li>
<li>Two</li>
When the user clicks twothen I want the active element to move to that list item. I have tried the following solution.
// In my menu controller
// Determines which link that should be active
$scope.activeLinkID = 0;
// Associative array with link names and paths
$scope.linkArray = {};
// Index 0 = linkName, index 1 = linkPath
$scope.linkArray[0] = ["One", "#/link/one"]
$scope.linkArray[1] = ["Two", "#/link/two"]
[...]
I have tried to display this in my view like this:
<li ng-repeat="(linkIndex, link) in linkArray | orderBy:linkIndex">{{link[0]}}</li>
But I got stuck when trying to add elements into my <li> tag. The condition would be activeLinkID == linkIndex then add class="active".
I'm not sure which is the best way to achive this using AngularJS. What is the best way to do it?
In your controller
$scope.selectedIndex = -1;
$scope.links = [
["One", "#/link/one"],
["Two", "#/link/two"]
];
In your view
<li ng-repeat="link in link"
ng-class="{'active': $parent.selectedIndex == $index}">
<a ng-click="$parent.selectedIndex = $index">{{link[0]}}</a>
</li>
Here's a working demo http://jsbin.com/exafUmuq/2/edit?html,js,output
It seems like you're trying to accomplish something that ui-router was built to solve. You should take some time to learn about it, it will save you lots of headaches.
Great video on ui-router can be found here
https://egghead.io/lessons/angularjs-introduction-ui-router
Try adding a div the ng function inside your div like this
<div> <li ng-repeat="(linkIndex, link) in linkArray | orderBy:linkIndex">{{link[0]}}</li></div>
See if that works. Did for me

Navigation Works Once, But Then Does Nothing

I'm trying to code a navigation bar with four elements. If the element is currently selected it will have a "red" background image, if it is one of the other 3, it will have a "black" background image. my four tabs are 'timetable, homework, notifications and sport'
I tried making 8 functions like the 2 below
function setTimeRed()
{
document.getElementById("time").style.ClassName = 'timetable_r';
}
function setTimeBlack()
{
document.getElementById("time").style.ClassName = 'time_r';
}
And then four blocks like this:
function changeTimeButton()
{
var timePath = new String();
timePath = document.getElementById("timetable").style.backgroundImage;
if(timePath == "url(assets/img/tabs/time_black.png)" || timePath == "")
{
setTimeRed();
setHomeBlack();
setNotiBlack();
setSportBlack();
}
else {
}
}
finally, my html has this:
<div id="tabbar">
<ul id="tabs">
<a href"#" onclick="changeTimeButton()">
<li id="timetable" class="time_b">
<p>Timetable</p>
</li>
</a>
<a href"#" onclick="changeHomeButton()">
<li id="homework" class="home_b">
<p>Homework</p>
</li>
</a>
<a href"#" onclick="changeNotiButton()">
<li id="notifications" class="noti_b">
<p>Notifications</p>
</li>
</a>
<a href"#" onclick="changeSportButton()">
<li id="sport" class="sport_b">
<p>Sport</p>
</li>
</a>
</ul>
</div>
It works once then does nothing. Why?
I think error is in your script, just one example
document.getElementById("time").style.ClassName = 'timetable_r';
which should be (there are no elements with id "time" in your html, at least in the code you posted here)
document.getElementById("timetable").style.ClassName = 'timetable_r';
Another thing, if it works once, then seems it might save some issues with new session or existing session. I am not an expert on javascript. But if it helps, please inform.
When turning the background color off, you need to remove any existing classes like this:
document.getElementById("timetable").className =
document.getElementById("timetable").className.replace
( /(?:^|\s)time_b(?!\S)/ , '' )
Since you're using classes instead of modifying the styles in the javascript, you should stick to that. You seem to be trying to set the background image in the javascript.
Instead, you should apply that background image to the class' styles in the CSS.
Using a framework like jQuery would make this much easier since it has helper functions such as addClass(), toggleClass(), and removeClass(). You should also set the 'a' tags inside the 'li'. It makes for cleaner code in my opinion. The browser will still read the click and be able to apply the classes correctly.
Also, you shouldn't have to repeat yourself so often in your code. One solution is to create a generic function and pass the element's id in as a parameter. Then, you use an 'active' class instead of 'timetable_r'. The active class will be applied to the active link and you won't have to write the functions out so many times. Hope this helps.

onClick javascript: navigation with changing css background images / two types

i am doing a site with 2 navigations (navs) including links, each of them in another div.
When a link is clicked it should change its background image in the css (change class).
And only one link of its class can change the background.
In the second nav there is one link which is also included in nav 1.
Also are in the second nav two different background images to "toggle".
I already have accomplished the first nav, but I do not know how to include the second one.
In the second one is the problem that two links should not change their background at the same time.
The site: http://enlifer.de/test25/zp-kazachkova.html
The second nav is at the height of the logo.
If "Leistungen" is clicked in the second nav, the first one should also change its default background and vice versa.
Following code is relevant.
First nav
<navigation>
<ul id="nav">
<li class="link" onclick="mark(this)"> Kontakt </li>
<li class="link" onclick="mark(this)"> Anfahrt </li>
<li class="link" onclick="mark(this)"> Leistungen </li>
<li class="link" onclick="mark(this)"> Praxisteam </li>
</ul>
</navigation>
Second nav
<up>
<ul id="up">
<li class="uplink-l" onclick="l_mark(this)"> Leistungen </li>
<li class="uplink-i" onclick="i_mark(this)"> Impressum </li>
</ul>
</up>
JavaScript
<script type="text/javascript">
function mark(cell)
{
for(i=0; i <
document.getElementById("nav").getElementsByTagName("li").length; i++)
{
document.getElementById("nav").getElementsByTagName("li")[i].className="link";
}
cell.className="linkactive";
}
function l_mark(cell)
{
for(i=0; i <
document.getElementById("up").getElementsByTagName("li")[0].length; i++)
{
document.getElementById("up").getElementsByTagName("li")[0][i].className="uplink-l";
}
cell.className="uplink-l-active";
}
function i_mark(cell)
{
for(i=0; i <
document.getElementById("up").getElementsByTagName("li")[1].length; i++)
{
document.getElementById("up").getElementsByTagName("li")[1][i].className="uplink-i";
}
cell.className="uplink-i-active";
}
window.onload = setActive;
</script>
Thanks!
"Leistungen" has the class lmark, while "Impressum" has imark. Your Javascript function for lmark-classed elements resets the background for all other lmark-classed elements, but not for the imark-classed ones. Same for the function that concerns imark.
If you need to have only one non-default background for all lmark and imark elements, a correct (probably correct, though not tested) code is:
function li_mark(cell) {
var elts=document.getElementById("up").getElementsByTagName("li"); //store the elements we need in a local variable so we don't have to rewrite all that line (and the browser won't have to do the fetching job again), we don't care if they're L-type or I-type
for(var i in elts)
if(elts[i].className && elts[i].className.length>=8) //check if there is a className and it is at least as long as "uplink-X", otherwise we don't process the element and skip to the next
elts[i].className="uplink-"+elts[i].className.charAt(7); //we retrieve the letter for the type of class (L or I), and we append it to "upload-" to redefine the class of the current element
cell.className+="-active"; //after the loop, all elements have their default class, so we just need to append "-active" to the one we want to be active
}
Then, all your calls to l_mark(this) and i_mark(this) should simply be replaced by calls to li_mark(this).
P.S.: not related, but my current browser (Firefox) doesn't seem to like the window.onload=setActive;, saying that "setActive is not defined"...
Edit according to comments, having seen your JS file (scripttests.js):
You still need 2 functions, mark() and li_mark(), because for mark() your active class is of the form <className>active instead of <className>-X-active (not the same pattern in naming the classes, and no need to retrieve the character Lor I).
Another part of the problem is that you call cell.className+="-active" twice on the same cell in the one function you have.
The last part of the problem is that you forgot the instruction within the if of the second loop: as there are no block brackets, the instruction that is executed when this if is true is cell.className+="-active"... executed as many times as the loop runs and the if is true.
A (probably) working version would be:
function li_mark(cell) {
var elts=document.getElementById("up").getElementsByTagName("li"); //store the elements we need in a local variable so we don't have to rewrite all that line (and the browser won't have to do the fetching job again), we don't care if they're L-type or I-type
for(var i in elts)
if(elts[i].className && elts[i].className.length>=8) //check if there is a className and it is at least as long as "uplink-X", otherwise we don't process the element and skip to the next
elts[i].className="uplink-"+elts[i].className.charAt(7); //we retrieve the letter for the type of class (L or I), and we append it to "upload-" to redefine the class of the current element
if(cell && cell.className && cell.className.length>=8) { //if we passed an argument, then it must be a cell to activate, with a basic check on its className
cell.className+="-active"; //after the loop, all elements have their default class, so we just need to append "-active" to the one we want to be active
mark(); //we call mark() with no argument to reset all the items managed by mark(), we call it in this if-block to avoid infinite recursion
}
}
function mark(cell) {
var elts=document.getElementById("nav").getElementsByTagName("li"); //store the elements we need in a local variable so we don't have to rewrite all that line (and the browser won't have to do the fetching job again), we don't care if they're L-type or I-type
for(var i in elts)
if(elts[i].className) //check if there is a className, otherwise we don't process the element and skip to the next
elts[i].className="link"; //we set back to the default class
if(cell && cell.className) { //if we passed an argument, then it must be a cell to activate
cell.className+="active"; //after the loop, all elements have their default class, so we just need to append "active" to the one we want to be active
li_mark(); //we call li_mark() with no argument to reset all the items managed by li_mark(), we call it in this if-block to avoid infinite recursion
}
}

Categories

Resources