StevieP
StevieP

Reputation: 401

Angular.js routing: Previous and Next pager

I'm new to Angular.js, so I'm sure there is a very simple solution to this, and I'm surprised there isn't a bunch of tutorials that cover this question.

(There are plenty that cover pagination of a long list of results - but my problem seems quite different.)

I have successfully implemented routes for a number of pages within my "single page application" / website. These pages have a natural order, so I am trying to implement Previous and Next buttons (or links) in the header, so that the Next button cycles through Home > Page 1 > Page 2 > Page 3 > Home, and the previous button goes backwards from Home > Page 3 > Page 2 > Page 1 > Home.

Having read some relevant-ish articles, tutorials, examples, and StackOverflow Q&As I've tried a few methods that I thought might work, but the Prev / Next buttons do not dynamically update as intended when the route / ng-view changes.

i.e. in my simplified code below (with Home, About and Contact pages), the targets of the Previous / Next buttons and their respective functions nextPage() and prevPage() always relate to the "Home" page's previous and next pages, even when another page has been navigated to.

index.html (the important bits)

<html ng-app="app">

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.js"></script>
  <script src="script.js"></script>
</head>

<!-- define angular controller -->
<body ng-controller="mainController">

  <nav class="navbar navbar-default">
    <div class="container">

      <button class="btn" ng-click="prevPage()">Previous</button>

      <button class="btn" ng-click="nextPage()">Next</button>

    </div>
  </nav>

  <div id="main">
    <div ng-view></div> 
  </div>

</body>

</html>

script.js

var app = angular.module('app', ['ngRoute']);

app.config(function($routeProvider) {
    $routeProvider

        // Page routes
        .when('/', { templateUrl : 'pages/home.html', controller  : 'mainController' })
        .when('/about', { templateUrl : 'pages/about.html', controller  : 'aboutController' })
        .when('/contact', { templateUrl : 'pages/contact.html', controller  : 'contactController' })
        .otherwise( {redirectTo:'/'} );
});

// create the controller and inject Angular's $scope
app.controller('mainController', function($scope, $location) {
    $scope.nextPage = function() { $location.path('/about'); };
    $scope.prevPage = function() { $location.path('/contact'); };
});

app.controller('aboutController', function($scope, $location) {
    $scope.nextPage = function() { $location.path('/contact'); };
    $scope.prevPage = function() { $location.path('/'); };
});

app.controller('contactController', function($scope, $location) {
    $scope.nextPage = function() { $location.path('/contact'); };
    $scope.prevPage = function() { $location.path('/'); };
});

Here's a Plunker (it's based based on this one).

What is the best way of achieving this?!

Upvotes: 2

Views: 2289

Answers (3)

Emir Marques
Emir Marques

Reputation: 2687

Try this:

This example work with one controller for router

var app = angular.module('app', ['ngRoute']);

app.config(function($routeProvider) {
    $routeProvider
    .when('/home', { templateUrl : 'pages/home.html', controller  : 'mainController' })
    .when('/about', { templateUrl : 'pages/about.html', controller  : 'mainController' })
    .when('/contact', { templateUrl : 'pages/contact.html', controller  : 'mainController' })
    .otherwise( {redirectTo:'/home'} );
});

// create the controller and inject Angular's $scope
app.controller('mainController', function($scope, $rootScope, $location) {
     $scope.nextPage = function() { 
         if(!$rootScope.currentPage || $rootScope.currentPage == 0){
            $rootScope.currentPage = 1;
            $location.path('/about'); 
         }else if($rootScope.currentPage == 1){
            $rootScope.currentPage = 2;
            $location.path('/contact'); 
         }
         else if($rootScope.currentPage == 2){
            $rootScope.currentPage = 0;
            $location.path('/home'); 
         }
     }

     $scope.prevPage = function() { 
         if(!$rootScope.currentPage || $rootScope.currentPage == 0){
            $rootScope.currentPage = 2;
            $location.path('/contact'); 
         }else if($rootScope.currentPage == 1){
            $rootScope.currentPage = 0;
            $location.path('/home'); 
         }else{
            $rootScope.currentPage = 1;
            $location.path('/about'); 
         }
      };
});

Upvotes: 1

Shimon Brandsdorfer
Shimon Brandsdorfer

Reputation: 1723

The reason why it behaves like this, is because the scope object you define in your controllers, is only inside the ng-view, and outside of it, the scope is bound to the main controller (since you passed it in in the ng-controller).

you can see it here http://plnkr.co/edit/sh5JcJs82c7uIiVg6Skg?p=preview where the hello variable, is different when it's outside the ng-view.

My sulotion is you should use the $rootScope, here's a working plunker: http://plnkr.co/edit/krs7mzcIVktXxFPvG44R?p=preview

(btw, another issue, you did in the contact controller wrong, and I fixed it).

Upvotes: 1

Hari Pachuveetil
Hari Pachuveetil

Reputation: 10374

The problem is the buttons are bound to functions on the mainController, which are not the ones being changed when the /about and /contact routes are being shown.

You could add another homeController for the / route and have all the three route controllers change the mainController's nextPage and prevPage functions appropriately.

Like:

var app = angular.module('app', ['ngRoute']);

app.config(function($routeProvider) {
    $routeProvider

        // Page routes
        .when('/', { templateUrl : 'pages/home.html', controller  : 'homeController' })
        .when('/about', { templateUrl : 'pages/about.html', controller  : 'aboutController' })
        .when('/contact', { templateUrl : 'pages/contact.html', controller  : 'contactController' })
        .otherwise( {redirectTo:'/'} );
});

// create the controller and inject Angular's $scope
app.controller('mainController', function($scope, $location) {
  $scope.nextPage = function() { $location.path('/about'); };
  $scope.prevPage = function() { $location.path('/contact'); };
});

app.controller('homeController', function($scope, $location) {
  $scope.$parent.nextPage = function() { $location.path('/about'); };
  $scope.$parent.prevPage = function() { $location.path('/contact'); };
});

app.controller('aboutController', function($scope, $location) {
  $scope.$parent.nextPage = function() { $location.path('/contact'); };
  $scope.$parent.prevPage = function() { $location.path('/'); };
});

app.controller('contactController', function($scope, $location) {
  $scope.$parent.nextPage = function() { $location.path('/'); };
  $scope.$parent.prevPage = function() { $location.path('/about'); };
});

Working Plunker: http://plnkr.co/edit/8Q2IIn?p=preview

Upvotes: 1

Related Questions