Como / quando usar o ng-click para chamar uma rota?


243

Suponha que você esteja usando rotas:

// 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'
    });
...

E no seu html, você deseja navegar para a página sobre quando um botão é clicado. Uma maneira seria

<a href="#/about">

... mas parece que o ng-click também seria útil aqui.

  1. Essa suposição está correta? Esse ng-click é usado em vez de âncora?
  2. Se sim, como isso funcionaria? IE:

<div ng-click="/about">



Respostas:


430

As rotas monitoram o $locationserviço e respondem a alterações no URL (geralmente por meio do hash). Para "ativar" uma rota, basta alterar o URL. A maneira mais fácil de fazer isso é com tags de âncora.

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

Nada mais complicado é necessário. Se, no entanto, você deve fazer isso a partir do código, a maneira correta é usar o $locationserviço:

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

Que, por exemplo, um botão pode acionar:

<button ng-click="go('/home')"></button>

6
Este não funcionou para mim, mas substituindo $ location.hash (hash); com $ location.path (hash); funciona. Isso é sugerido por @sean em outra resposta, que tem muito menos votos por algum motivo.
Por Queston Aronsson

2
@PerQuestedAronsson pathe hashserve a dois propósitos diferentes, mas, dependendo das circunstâncias, pode ter o mesmo efeito. Na maioria dos casos, para roteamento estrito (especialmente com html5modeativado), pathserá a escolha canônica. Eu atualizei a resposta para refletir isso.
Josh David Miller

2
@DavidWoods Deve funcionar, mas apenas se o caminho base corresponder /. Se você estiver veiculando o aplicativo /app/index.html, isso não funcionará porque o URL absoluto é /app/next.html. Obviamente, também, o servidor deve estar configurado para retornar seu index.htmlarquivo quando for atingido /next.html. Sinta-se livre para postar um Plunker / Fiddle se você quiser que eu dê uma olhada.
Josh David Miller

2
Isso é uma coisa muito genérica e útil a se fazer. Existe uma maneira de centralizá-lo ou realmente precisamos adicionar um gométodo a cada controlador? (Ou criar um controlador de raiz com um gométodo?)
Bennett McElwee

3
@BennettMcElwee Acho que, de longe, a melhor abordagem é usar apenas tags âncora; a tag button não fornece valor nesse caso e é o que está criando o problema. Dito isto, você pode facilmente criar uma directiva para fazer isso por você, por exemplo: <button click-go="/home">Click</button>. A função de link seria apenas esta:element.on("click", function () { $location.path(attrs.clickGo); });
Josh David Miller

83

Aqui está uma ótima dica que ninguém mencionou. No controlador em que a função está, você precisa incluir o provedor de localização:

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>

2
legal obrigado! essa resposta funcionou melhor para mim, porque o método hash acrescenta os valores no URL (codificado) e o método path permite que eu substitua o URL completo, era disso que eu precisava. obrigado!
jfplataroti

8
Esta é a única solução sugerida nesta página que realmente funcionou. Não sei por que outra resposta tem muito mais votos do que esta ..?
Por Aronsson consultado em 30/07/2013

Eu estava tentando isso, mas não está funcionando. Também tenho que adicionar um local ao módulo antes de conectá-lo ao controlador?
Fallenreaper

Isso funcionou para mim depois de definir o ng-clique em uma div, em vez de em um <a>.
Steve

33

Usar um atributo personalizado (implementado com uma diretiva) talvez seja a maneira mais limpa. Aqui está a minha versão, com base nas sugestões de @ Josh e @ sean.

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);
                });
            });
        }
    }
}]);

Ele tem alguns recursos úteis, mas eu sou novo no Angular, então provavelmente há espaço para melhorias.


Isso não criará um evento click no elemento toda vez que o atributo clickLink for alterado?
toxaq

@toxaq Definitivamente não é perfeito. Eu suspeito que, quando o clickLinkatributo for alterado, a diretiva adicionará o novo manipulador de cliques, mas deixará o antigo no lugar. O resultado pode ser um pouco caótico. Originalmente, escrevi isso para usar em uma situação em que o clickLinkatributo nunca mudaria, por isso nunca amarrei esse final. Eu acho que corrigir esse bug seria realmente levar a código mais simples - eu poderia tentar fazê-lo quando eu tiver tempo (ha!)
Bennett McElwee

Legal. Sim, se você remover os atributos, $ observe que funcionará como pretendido. Gostaria de colar minha versão aqui, mas ela não será formatada nos comentários e é praticamente idêntica à parte observada.
toxaq

@toxaq Eu editei o código agora. Eu acho que tinha adaptado o código de alguma outra diretiva, é por isso que o inadequado attrs.$observeestava lá. Obrigado por suas sugestões.
Bennett McElwee

Estava prestes a sugerir isso ao ler as respostas sugeridas. Limpo e reutilizável. +1
Dormouse

4

Lembre-se de que se você usar o ng-click no roteamento, não poderá clicar com o botão direito do mouse no elemento e escolher 'abrir em nova guia' ou clicar com a tecla Ctrl pressionada no link. Eu tento usar o ng-href quando se trata de navegação. É melhor usar o ng-click nos botões para operações ou efeitos visuais, como o recolhimento. Mas sobre eu não recomendaria. Se você alterar a rota, poderá ser necessário alterar muitas inserções no aplicativo. Tenha um método retornando o link. ex: Sobre. Esse método que você coloca em um utilitário


1

Eu usei a ng-clickdiretiva para chamar uma função, ao solicitar a rota templateUrl, para decidir qual <div>deve ser showou hidedentro da página templateUrl da rota ou para diferentes cenários.

AngularJS 1.6.9

Vamos ver um exemplo, quando na página de roteamento, preciso adicionar <div>ou editar <div>, que eu controle usando os modelos de controlador pai $scope.addProducte $scope.editProductbooleano.

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>

ambas as páginas - RoutingTesting.html(pai), TestingPage.html(página de roteamento) estão no mesmo diretório,

Espero que isso ajude alguém.


1

Outra solução, mas sem usar o ng-click, que ainda funciona mesmo para outras tags além de <a>:

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

Dessa forma, você também pode passar parâmetros para sua rota: https://stackoverflow.com/a/40045556/838494

(Este é o meu primeiro dia com angular. Feedback gentil é bem-vindo)


0

Você pode usar:

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

Se você quiser alguma variável dinâmica dentro do href, faça o seguinte:

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

Onde link é variável de escopo angular.


5
Isso não responde à pergunta do OP, que é sobre o uso ng-clickpara alterar o local.
jjmontes

0

basta fazer o seguinte em sua gravação em html:

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

E no seu controlador, adicione $ state da seguinte maneira:

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

$scope.going = function(){

$state.go('your route');

}

})
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.