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

Robert Christian
fonte
ui-sref Veja esta resposta: stackoverflow.com/a/21105057/2539811
Vincil Bishop

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>
Josh David Miller
fonte
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>
sean
fonte
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.

Bennett McElwee
fonte
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

Jens Alenius
fonte
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.

ArifMustafa
fonte
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)

Albert Hendriks
fonte
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.

Sohail xIN3N
fonte
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');

}

})
LucasMugi
fonte