How/when to use ng-click to call a route?
Asked Answered
S

8

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">

Selfopinionated answered 7/1, 2013 at 18:23 Comment(2)
possible duplicate of How do I switch views in AngularJS from a controller function?Technocracy
ui-sref See this answer: https://mcmap.net/q/119023/-angularjs-ui-router-state-go-does-not-work-inside-ng-clickDoody
W
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>
Willmert answered 7/1, 2013 at 19:14 Comment(11)
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.Gaylor
@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.Willmert
does activating the route with just the anchor tag work with html5mode? When I have <a href="/next.html">Next</a> the browser reloads the page, it is not intercepted by the router. Do I have to do this with code then?Fineman
@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.Willmert
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?)Leavetaking
@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.: <button click-go="/home">Click</button>. The link function would only be this: element.on("click", function () { $location.path(attrs.clickGo); });Willmert
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 :\Leavetaking
Is there any performance, accessibility, or standards differences that we should be aware of with either approach?Geostatics
@WillStrohl Good question. I'm not aware of any performance or accessibility problems with these, assuming both are handled appropriately.Willmert
Side note: remember that the url is case sensitive and one single letter may give you a good headache as it gave me ;)Dorwin
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.Haunting
A
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>
Arbitrament answered 27/6, 2013 at 16:12 Comment(4)
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!Gregorio
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..?Gaylor
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 ?Indention
This worked for me once I set ng-click on a div rather than an <a>.Cobbler
L
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.

Leavetaking answered 25/9, 2013 at 2:0 Comment(6)
Won't this create a click event on the element every time the clickLink attribute changes?Decanal
@Decanal 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 clickLinkattribute 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!)Leavetaking
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.Decanal
@Decanal 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.Leavetaking
Was about to suggest this when reading through the suggested answers. Clean and reusable. +1Nil
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.3Haddix
T
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

Tetrameter answered 16/11, 2015 at 12:36 Comment(0)
F
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.

Fivespot answered 8/4, 2018 at 12:50 Comment(0)
P
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://mcmap.net/q/119024/-angular-2-pass-parameters-to-route

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

Peachy answered 12/4, 2018 at 13:42 Comment(1)
this shouldn't be marked as a correct answer as it refers to angular 2+ not what the question asks - angular 1Chalybeate
V
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.

Vortical answered 19/9, 2015 at 11:33 Comment(1)
This does not answer the OP question, which is about using ng-click to change location.Flamboyant
P
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');

}

})
Patras answered 12/7, 2018 at 20:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.