245

Suppose you are using routes:

// bootstrap
myApp.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {

    $routeProvider.when('/home', {
        templateUrl: 'partials/home.html',
        controller: 'HomeCtrl'
    });
    $routeProvider.when('/about', {
        templateUrl: 'partials/about.html',
        controller: 'AboutCtrl'
    });
...

And in your html, you want to navigate to the about page when a button is clicked. One way would be

<a href="#/about">

... but it seems ng-click would be useful here too.

  1. Is that assumption correct? That ng-click be used instead of anchor?
  2. If so, how would that work? IE:

<div ng-click="/about">

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Robert Christian
  • 18,218
  • 20
  • 74
  • 89
  • possible duplicate of [How do I switch views in AngularJS from a controller function?](http://stackoverflow.com/questions/11003916/how-do-i-switch-views-in-angularjs-from-a-controller-function) – Blazemonger Aug 22 '14 at 13:53
  • ui-sref See this answer: http://stackoverflow.com/a/21105057/2539811 – Vincil Bishop Apr 05 '16 at 15:53

8 Answers8

431

Routes monitor the $location service and respond to changes in URL (typically through the hash). To "activate" a route, you simply change the URL. The easiest way to do that is with anchor tags.

<a href="#/home">Go Home</a>
<a href="#/about">Go to About</a>

Nothing more complicated is needed. If, however, you must do this from code, the proper way is by using the $location service:

$scope.go = function ( path ) {
  $location.path( path );
};

Which, for example, a button could trigger:

<button ng-click="go('/home')"></button>
tronman
  • 9,862
  • 10
  • 46
  • 61
Josh David Miller
  • 120,525
  • 16
  • 127
  • 95
  • 6
    This one didn't work for me, but by replacing $location.hash(hash); with $location.path(hash); it works. This is suggested by @sean in another reply, which has much fewer votes for some reason. – Per Quested Aronsson Jul 30 '13 at 11:22
  • 2
    @PerQuestedAronsson `path` and `hash` serve two different purposes but depending on circumstance can have the same effect. For most cases, for strict routing (especially with `html5mode` enabled), `path` will be the canonical choice. I updated the answer to reflect this. – Josh David Miller Jul 31 '13 at 02:29
  • does activating the route with just the anchor tag work with html5mode? When I have `Next` the browser reloads the page, it is not intercepted by the router. Do I have to do this with code then? – David Woods Aug 16 '13 at 02:22
  • 2
    @DavidWoods It should work, but only if the base path matches `/`. If you're serving the app from `/app/index.html`, then this will not work because the absolute URL is `/app/next.html`. Obviously also, the server must be set to return your `index.html` file when hit at `/next.html`. Feel free to post a Plunker/Fiddle if you want me to take a look. – Josh David Miller Aug 16 '13 at 07:29
  • 2
    This is a very generic and useful thing to do. Is there a way to centralise it, or do we really have to add a `go` method to every controller? (Or create a root controller with a `go` method?) – Bennett McElwee Sep 25 '13 at 00:03
  • 3
    @BennettMcElwee I think by far the best approach is to just use anchor tags; the button tag provides no value in this case and is what is creating the issue. That said, you could easily create a directive to do this for you, e.g.: ``. The link function would only be this: `element.on("click", function () { $location.path(attrs.clickGo); });` – Josh David Miller Sep 25 '13 at 00:21
  • Thanks Josh. In my case I want to tap on a div to navigate, so anchor tags are no good. It seems to me that a directive would be the cleanest approach. But since I am already using the `ngTap` directive I have to create an `ng-tap-go` directive :\ – Bennett McElwee Sep 25 '13 at 00:36
  • Is there any performance, accessibility, or standards differences that we should be aware of with either approach? – Will Strohl Oct 03 '15 at 04:32
  • @WillStrohl Good question. I'm not aware of any performance or accessibility problems with these, assuming both are handled appropriately. – Josh David Miller Oct 03 '15 at 23:31
  • Side note: remember that the `url` is case sensitive and one single letter may give you a good headache _as it gave me ;)_ –  Mar 28 '16 at 13:08
  • Moreover, the hash prefix needs to match whatever's in your route provider config. For example, with the following, `$locationProvider.hashPrefix('!');` it is necessary to update routes to `#!/wherever`. – ThisClark Jul 12 '17 at 06:03
82

Here's a great tip that nobody mentioned. In the controller that the function is within, you need to include the location provider:

app.controller('SlideController', ['$scope', '$location',function($scope, $location){ 
$scope.goNext = function (hash) { 
$location.path(hash);
 }

;]);

 <!--the code to call it from within the partial:---> <div ng-click='goNext("/page2")'>next page</div>
sean
  • 1,220
  • 9
  • 8
  • 2
    cool thanks! this answer worked better for me, because the hash method append the values on the url (encoded) and the path method let me replace the full url, that was what i needed. thanks! – jfplataroti Jul 15 '13 at 15:40
  • 8
    This is the only suggested solution on this page that actually worked. Don't know why another answer has a lot more votes than this one..? – Per Quested Aronsson Jul 30 '13 at 11:24
  • I was trying this, but it isnt working. Do i have to add location to the module as well before attaching it to the controller ? – Fallenreaper Oct 01 '16 at 18:56
  • This worked for me once I set ng-click on a div rather than an . – Steve Dec 02 '19 at 23:06
33

Using a custom attribute (implemented with a directive) is perhaps the cleanest way. Here's my version, based on @Josh and @sean's suggestions.

angular.module('mymodule', [])

// Click to navigate
// similar to <a href="#/partial"> but hash is not required, 
// e.g. <div click-link="/partial">
.directive('clickLink', ['$location', function($location) {
    return {
        link: function(scope, element, attrs) {
            element.on('click', function() {
                scope.$apply(function() {
                    $location.path(attrs.clickLink);
                });
            });
        }
    }
}]);

It has some useful features, but I'm new to Angular so there's probably room for improvement.

Bennett McElwee
  • 24,740
  • 6
  • 54
  • 63
  • Won't this create a click event on the element every time the clickLink attribute changes? – toxaq Nov 20 '13 at 05:45
  • @toxaq It's definitely not perfect. I suspect that when the `clickLink` attribute changes, the directive will add the new click handler but leave the old one in place. The result could be a bit chaotic. I originally wrote this to use in a situation where the `clickLink`attribute would never change, so I never tied up this loose end. I think fixing this bug would actually lead to simpler code - I might try to do it when I have time (ha!) – Bennett McElwee Nov 20 '13 at 10:09
  • Cool. Yeah, if you take out the attrs.$observe it'll work as intended. I'd paste my version here but it won't format in the comments and is practically identical bar the observe part. – toxaq Nov 20 '13 at 12:00
  • @toxaq I've edited the code now. I think I had adapted the code from some other directive, that's why the inappropriate `attrs.$observe` was there. Thanks for your suggestions. – Bennett McElwee Nov 20 '13 at 20:14
  • Was about to suggest this when reading through the suggested answers. Clean and reusable. +1 – Dormouse Dec 11 '14 at 13:23
  • This is the perfect solution IMO and it does NOT add new click handler wihen the attribute changes.. I tried this with Angular 1.6.3 – Mustafa Apr 03 '17 at 14:32
4

Remember that if you use ng-click for routing you will not be able to right-click the element and choose 'open in new tab' or ctrl clicking the link. I try to use ng-href when in comes to navigation. ng-click is better to use on buttons for operations or visual effects like collapse. But About I would not recommend. If you change the route you might need to change in a lot of placed in the application. Have a method returning the link. ex: About. This method you place in a utility

Jens Alenius
  • 1,931
  • 2
  • 16
  • 20
1

I used ng-click directive to call a function, while requesting route templateUrl, to decide which <div> has to be show or hide inside route templateUrl page or for different scenarios.

AngularJS 1.6.9

Lets see an example, when in routing page, I need either the add <div> or the edit <div>, which I control using the parent controller models $scope.addProduct and $scope.editProduct boolean.

RoutingTesting.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Testing</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-route.min.js"></script>
    <script>
        var app = angular.module("MyApp", ["ngRoute"]);

        app.config(function($routeProvider){
            $routeProvider
                .when("/TestingPage", {
                    templateUrl: "TestingPage.html"
                });
        });

        app.controller("HomeController", function($scope, $location){

            $scope.init = function(){
                $scope.addProduct = false;
                $scope.editProduct = false;
            }

            $scope.productOperation = function(operationType, productId){
                $scope.addProduct = false;
                $scope.editProduct = false;

                if(operationType === "add"){
                    $scope.addProduct = true;
                    console.log("Add productOperation requested...");
                }else if(operationType === "edit"){
                    $scope.editProduct = true;
                    console.log("Edit productOperation requested : " + productId);
                }

                //*************** VERY IMPORTANT NOTE ***************
                //comment this $location.path("..."); line, when using <a> anchor tags,
                //only useful when <a> below given are commented, and using <input> controls
                $location.path("TestingPage");
            };

        });
    </script>
</head>
<body ng-app="MyApp" ng-controller="HomeController">

    <div ng-init="init()">

        <!-- Either use <a>anchor tag or input type=button -->

        <!--<a href="#!TestingPage" ng-click="productOperation('add', -1)">Add Product</a>-->
        <!--<br><br>-->
        <!--<a href="#!TestingPage" ng-click="productOperation('edit', 10)">Edit Product</a>-->

        <input type="button" ng-click="productOperation('add', -1)" value="Add Product"/>
        <br><br>
        <input type="button" ng-click="productOperation('edit', 10)" value="Edit Product"/>
        <pre>addProduct : {{addProduct}}</pre>
        <pre>editProduct : {{editProduct}}</pre>
        <ng-view></ng-view>

    </div>

</body>
</html>

TestingPage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .productOperation{
            position:fixed;
            top: 50%;
            left: 50%;
            width:30em;
            height:18em;
            margin-left: -15em; /*set to a negative number 1/2 of your width*/
            margin-top: -9em; /*set to a negative number 1/2 of your height*/
            border: 1px solid #ccc;
            background: yellow;
        }
    </style>
</head>
<body>

<div class="productOperation" >

    <div ng-show="addProduct">
        <h2 >Add Product enabled</h2>
    </div>

    <div ng-show="editProduct">
        <h2>Edit Product enabled</h2>
    </div>

</div>

</body>
</html>

both pages - RoutingTesting.html(parent), TestingPage.html(routing page) are in the same directory,

Hope this will help someone.

ArifMustafa
  • 4,617
  • 5
  • 40
  • 48
1

Another solution but without using ng-click which still works even for other tags than <a>:

<tr [routerLink]="['/about']">

This way you can also pass parameters to your route: https://stackoverflow.com/a/40045556/838494

(This is my first day with angular. Gentle feedback is welcome)

Albert Hendriks
  • 1,979
  • 3
  • 25
  • 45
0

You can use:

<a ng-href="#/about">About</a>

If you want some dynamic variable inside href you can do like this way:

<a ng-href="{{link + 123}}">Link to 123</a>

Where link is Angular scope variable.

Sohail xIN3N
  • 2,951
  • 2
  • 30
  • 29
0

just do it as follows in your html write:

<button ng-click="going()">goto</button>

And in your controller, add $state as follows:

.controller('homeCTRL', function($scope, **$state**) {

$scope.going = function(){

$state.go('your route');

}

})
Neeraj Kumar
  • 771
  • 2
  • 16
  • 37
LucasMugi
  • 26
  • 1