Bagaimana cara mencegah Kerusakan pada tag jangkar?


342

Katakanlah saya memiliki anchor tag seperti

<a href="#" ng-click="do()">Click</a>

Bagaimana saya bisa mencegah browser dari menavigasi ke # di AngularJS ?


14
Seperti kata Chris di bawah, tinggalkan saja href.
Jesse

13
Bukan itu yang dikatakan Chris, Jesse, gunakan href=''untuk menjaga perilaku penunjuk tetikus.
oma

1
Anda cukup menghapus tanda # dari href, itu OK.
HENG Vongkol

4
Atau cukup gunakan href = "javascript: void (0);" untuk mempertahankan penunjuk tetapi tidak memiliki tindakan (hingga Anda menambahkan penangan klik lain)
Robba

1
Bisakah Anda mengubah jawaban yang diterima menjadi yang terbaik dan yang paling banyak dipilih oleh Chris - stackoverflow.com/a/11672909 ?
Piotr Dobrogost

Jawaban:


259

PEMBARUAN : Sejak itu saya berubah pikiran tentang solusi ini. Setelah lebih banyak pengembangan dan waktu yang dihabiskan untuk mengerjakan ini, saya percaya solusi yang lebih baik untuk masalah ini adalah dengan melakukan hal berikut:

<a ng-click="myFunction()">Click Here</a>

Dan kemudian perbarui Anda cssuntuk memiliki aturan tambahan:

a[ng-click]{
    cursor: pointer;
}

Jauh lebih sederhana dan menyediakan fungsionalitas yang sama persis dan jauh lebih efisien. Harapan yang mungkin bisa membantu orang lain mencari solusi ini di masa depan.


Berikut ini adalah solusi saya sebelumnya, yang saya tinggalkan di sini hanya untuk tujuan warisan:

Jika Anda sering mengalami masalah ini, arahan sederhana yang akan memperbaiki masalah ini adalah sebagai berikut:

app.directive('a', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            if(attrs.ngClick || attrs.href === '' || attrs.href === '#'){
                elem.on('click', function(e){
                    e.preventDefault();
                });
            }
        }
   };
});

Itu memeriksa semua tag anchor ( <a></a>) untuk melihat apakah hrefatribut mereka adalah string kosong ( "") atau hash ( '#') atau ada ng-clicktugas. Jika menemukan salah satu dari kondisi ini, ia menangkap peristiwa dan mencegah perilaku default.

Satu-satunya sisi adalah menjalankan arahan ini untuk semua tag anchor. Jadi jika Anda memiliki banyak tag anchor pada halaman dan Anda hanya ingin mencegah perilaku default untuk sejumlah kecil, maka arahan ini tidak terlalu efisien. Namun, saya hampir selalu ingin preventDefault, jadi saya menggunakan arahan ini di seluruh aplikasi AngularJS saya.


2
Terima kasih @matejkramny, kritik yang sangat membangun. Adakah saran untuk membuatnya kurang "berantakan"?
tennisgent

1
Seperti yang dinyatakan dalam jawaban lain, memiliki hrefatribut kosong memiliki perilaku yang berbeda di berbagai browser. Meskipun saya setuju itu sejauh ini merupakan solusi terbersih dan paling efisien, ia memang memiliki beberapa masalah lintas browser. Menggunakan pendekatan direktif memungkinkan browser untuk menangani <a>tag seperti biasanya, tetapi masih mendapatkan OP jawaban yang mereka cari.
tennisgent

2
Ini bekerja dan semua kecuali sangat serius untuk masalah yang sangat sederhana. Angular memberi Anda akses ke objek acara dengan $ event, sehingga Anda dapat melakukan apa yang akan Anda lakukan di acara js atau jquery klik biasa. Lihat jawaban ini stackoverflow.com/a/19240232/1826354 dan komentar saya tentang hal itu
Charlie Martin

1
Ya. Kamu bisa. Ada dua jawaban lain di pos ini yang sudah melakukan apa yang Anda gambarkan. Dan saya setuju, itu berlebihan. Itu sebabnya saya membuat pembaruan yang saya lakukan.
tennisgent

6
Ini bagus jika Anda tidak peduli dengan aksesibilitas di situs Anda. Dengan mengabaikan href, tidak mungkin menggunakan keyboard Anda untuk menabrak item itu. Kecuali Anda menambahkan tabindex. Dengan semua itu dalam pikiran, mengapa tidak menggunakan preventDefault ...? Itulah gunanya.
duhseekoh

319

Menurut dokumen untuk ngHref Anda harus dapat meninggalkan href atau melakukan href = "".

<input ng-model="value" /><br />
<a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
<a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
<a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
<a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />

6
Itu satu-satunya jawaban bagus yang sebenarnya. Apa pun yang memerlukan sentuhan DOM atau acara asli dipertanyakan
vincent

4
Ini jawaban yang benar. Jika Anda menghapus href dari atribut <a> atribut yang akan dipanggil AngularJS mencegah default:
pkozlowski.opensource

25
Satu-satunya downside meninggalkan atribut href adalah bahwa Anda kehilangan kursor 'pointer' normal ketika melayang di atas tautan. Anda bisa memperbaikinya dengan menambahkan aturan ke stylesheet Anda: a: hover {cursor: pointer; }
karlgold

35
Perlu diingat bahwa ini juga membuat tag tidak dapat ditabuh, yang tidak terlalu ramah aksesibilitas.
Richard Szalay

3
Bagi saya browser masih menampilkan aksi klik: /
Matej

238

Anda dapat mengirimkan objek $ event ke metode Anda, dan memanggilnya $event.preventDefault(), sehingga pemrosesan default tidak akan terjadi:

<a href="#" ng-click="do($event)">Click</a>

// then in your controller.do($event) method
$event.preventDefault()

13
ya, dan Anda juga dapat menghubungi $ event.stopPropagation () agar acara tidak muncul (pada dasarnya, Anda memiliki akses ke objek Acara seperti yang didefinisikan oleh W3C: w3.org/TR/DOM-Level-2- Events / events.html # Acara-Acara )
mna

1
Harap dicatat bahwa pada saat ini ditulis, membiarkan href kosong (atau tidak ada) tidak berfungsi pada IE8 / 9 dan Opera. Ini adalah setahun yang lalu, dan saya belum memiliki kesempatan untuk mencobanya lagi (saya membuka masalah saat itu di Github, tapi saya pikir mereka mengatur ulang masalah beberapa waktu lalu). Jika ini diperbaiki (atau Anda tidak peduli dengan browser ini), maka tentu saja, gunakan jawaban Chris! Jika seseorang dapat mencobanya dan mengomentari / mengedit jawaban, bahkan lebih baik.
mna

1
@PuerkitoBio - Saya dapat mengkonfirmasi bahwa IE8 dan di bawah ini masih memerlukan $event.preventDefault()... pajak IE.
Scotty.NET

4
meneruskan $ event ke controller berarti mereferensikan DOM di controller Anda, yang berarti Anda telah menggabungkan pandangan Anda dan controller Anda. Anda dapat memanggil metode $ event secara langsung dalam ekspresi yang dievaluasi: ng-click="do(); $event.preventDefault()misalnya ... meskipun, itu tidak perlu karena jawaban @ Chris di bawah adalah yang benar. Ini mungkin membantu orang-orang dalam situasi di mana mereka telah membuat ngClicks dan mereka ingin menelepon $event.stopPropagation().
Ben Lesh

2
Akhirnya solusi SEO friendly. Anda mungkin ingin juga memperbarui URL browser tanpa memuat ulang tampilan-ng - joelsaupe.com/programming/... Dengan begitu Anda memiliki tautan yang tidak memuat ulang tampilan Anda, tetapi dapat dibuka di tab baru dan mesin pencari dapat mengikutinya. YAY!
Tom

111

Saya lebih suka menggunakan arahan untuk hal semacam ini. Ini sebuah contoh

<a href="#" ng-click="do()" eat-click>Click Me</a>

Dan kode arahan untuk eat-click:

module.directive('eatClick', function() {
    return function(scope, element, attrs) {
        $(element).click(function(event) {
            event.preventDefault();
        });
    }
})

Sekarang Anda dapat menambahkan eat-clickatribut ke elemen apa pun dan itu akan menjadi preventDefault()otomatis.

Manfaat:

  1. Anda tidak harus memasukkan $eventobjek jelek ke dalam do()fungsi Anda .
  2. Pengontrol Anda lebih mudah diuji unit karena tidak perlu mematikan $eventobjek

1
@ Kato Angular hadir dengan jQuery, untuk memudahkan hidup kita.
Neil

3
Manfaat tambahan - ini juga berfungsi di IE8 dan di bawah, jika itu penting bagi Anda.
Scotty.NET

1
Saya mendapatkan Error: $ is not defined. Apa yang saya lewatkan?
Bilal Mirza

7
Saya mencoba angular.element(element).bind('click', function(event){...});. Itu berhasil. Ref: jQLite
Bilal Mirza

3
Memperkenalkan arahan untuk sesuatu yang sederhana seperti itu tampaknya sedikit membengkak jika Anda bertanya kepada saya ... Lihat Chris jawabannya di bawah ini
Wilt

54

Meski Renaud memberi solusi hebat

<a href="#" ng-click="do(); $event.preventDefault()">Click</a> 

Saya pribadi menemukan Anda juga memerlukan $ event.stopPropagation () dalam beberapa kasus untuk menghindari beberapa efek samping

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">
    Click</a>

akan menjadi solusi saya


34
ng-click="$event.preventDefault()"

13
Ini solusi terbaik. Tentu saja, Anda bisa melewatkan objek $ event ke fungsi lingkup Anda juga. Seperti ng-klik = "myFunction ($ event, otherParams) dan kemudian $ event.preventDefault () di myFunction. Menggulirkan arahan Anda sendiri untuk ini terlalu banyak
Charlie Martin

34

Solusi termudah yang saya temukan adalah yang ini:

<a href="#" ng-click="do(); $event.preventDefault()">Click</a>

Ini bukan hanya yang termudah, tetapi juga tidak memasangkan acara dengan pengontrol seperti yang disarankan dalam solusi lain. Menggabungkan acara ke pengontrol adalah sesuatu yang harus Anda hindari bagaimanapun caranya karena membuat pengujian jauh lebih sulit.
jornare

11

Jadi membaca jawaban ini, @ Chris masih memiliki jawaban yang paling "benar", saya kira, tetapi memiliki satu masalah, itu tidak menunjukkan "pointer" ....

Jadi, inilah dua cara untuk mengatasi masalah ini tanpa perlu menambahkan kursor: gaya pointer:

  1. Gunakan javascript:void(0)alih-alih #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
  2. Gunakan $event.preventDefault()dalam ng-clickarahan (sehingga Anda tidak membuang controller Anda dengan referensi terkait DOM):

    <a href="#dontGoHere" ng-click="doSomething(); $event.preventDefault()">Do Something</a>

Secara pribadi saya lebih suka yang pertama daripada yang terakhir. javascript:void(0)memiliki manfaat lain yang dibahas di sini . Ada juga diskusi tentang "JavaScript tidak mencolok" di tautan yang baru-baru ini menakutkan, dan tidak serta-merta langsung berlaku untuk aplikasi bersudut.


2
Mengapa ini diturunkan? Saya juga memperhatikan bahwa pointer tidak muncul dengan jawaban dari Chris.
Wim Deblauwe

2
javascript: void (0) jauh lebih baik daripada # yang dapat bertindak pada rute jika Anda salah mengonfigurasinya. +1
Shay Elkayam

2
Saya baru saja akan menulis jawaban untuk ini. Anda juga dapat melakukannyajavascript:;
Adrian

10

Anda bisa melakukannya sebagai berikut

1.Hapus hrefatribut dari atag anchor ( )

2. Atur kursor kursor dalam elemen klik css ke ng

 [ng-click],
 [data-ng-click],
 [x-ng-click] {
     cursor: pointer;
 }

9

HTML

di sini pure angularjs: dekat dengan fungsi ng-klik Anda dapat menulis fungsi preventDefault () dengan memisahkan tanda titik koma

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">Click me</a>

JS

$scope.do = function() {
    alert("do here anything..");
}

(atau)

Anda dapat melanjutkan dengan cara ini, ini sudah dibahas di sini.

HTML

<a href="#" ng-click="do()">Click me</a>

JS

$scope.do = function(event) {
    event.preventDefault();
    event.stopPropagation()
}

7

Coba opsi ini yang bisa saya lihat belum terdaftar di atas:

<a href="" ng-click="do()">Click</a>

6

Karena Anda membuat aplikasi web, mengapa Anda perlu tautan?

Tukar jangkar Anda ke tombol!

<button ng-click="do()"></button>

2
Karena kita tidak bisa apl web memiliki jangkar?
Robin van Baalen

1
Saya merujuk pada poin bahwa sebagian besar aplikasi web tidak memerlukan tautan relatif seperti situs web, mereka juga sering hanya menggunakan tautan jangkar sebagai pemicu javascript dan tidak menautkan ke halaman; oleh karena itu sebuah tombol dengan pengaturan ulang gaya standar juga semantik benar jika tidak lebih dari itu.
sidonaldson

3
@sidonaldson Sebenarnya, banyak aplikasi web saat ini sangat bergantung pada tautan. Lihatlah perutean angularjs.
Robert

1
@ Robert ya, tetapi jika Anda menggunakan perutean bawaan Anda tidak perlu mengelola mencegah default, itu dilakukan untuk Anda. Saya berasumsi karena poster ingin membatalkan tautan jangkar yang dia bicarakan tentang tautan non-rute. Misalnya meluncurkan modal dll
sidonaldson

2
Jawaban ini seharusnya memiliki lebih banyak upvotes. Dalam banyak kasus, jika Anda ingin mencegah perilaku jangkar default, Anda menggunakan jangkar sebagai tombol dan bukan tautan.
ItsCosmo

6

jika masih relevan:

<a ng-click="unselect($event)" />

...

scope.unselect = function( event ) {
 event.preventDefault();
 event.stopPropagation();
}

...

6

Cara teraman untuk menghindari peristiwa pada href adalah mendefinisikannya sebagai

<a href="javascript:void(0)" ....>

5

Saya akan pergi dengan:

<a ng-click="do()">Click</a>
  • karena menurut dokumen Anda harus dapat meninggalkan href dan kemudian Angular akan menangani pencegahan default untuk Anda!

Seluruh ini mencegah hal standar telah membingungkan saya, jadi saya telah membuat JSFiddle menggambarkan kapan dan di mana Angular mencegah default .

JSFiddle menggunakan arahan Angular - jadi harus sama persis. Anda dapat melihat kode sumber di sini: kode sumber tag

Saya harap ini akan membantu klarifikasi untuk beberapa orang.

Saya ingin memposting dokumen ke ngHref tetapi saya tidak bisa karena reputasi saya.


5

Inilah yang selalu saya lakukan. Bekerja seperti pesona!

<a href ng-click="do()">Click</a>

4

Atau jika Anda perlu inline maka Anda dapat melakukan ini:

<a href="#" ng-click="show = !show; $event.preventDefault()">Click to show</a>

4

Banyak jawaban tampaknya berlebihan. BAGI SAYA, ini berhasil

 <a ng-href="#" ng-click="$event.preventDefault();vm.questionContainer($index)">{{question.Verbiage}}</a>

2

Saya memerlukan kehadiran nilai atribut href untuk degradasi (ketika js dimatikan), jadi saya tidak dapat menggunakan atribut href kosong (atau "#"), tetapi kode di atas tidak bekerja untuk saya, karena saya memerlukan sebuah acara ( e) variabel. Saya membuat arahan saya sendiri:

angular.module('MyApp').directive('clickPrevent', function() {
  return function(scope, element, attrs) {
    return element.on('click', function(e) {
      return e.preventDefault();
    });
  };
});

Dalam HTML:

<a data-click-prevent="true" href="/users/sign_up" ng-click="openSignUpModal()">Sign up</a>

2

Meminjam dari jawaban tennisgent. Saya suka Anda tidak harus membuat arahan khusus untuk menambahkan semua tautan. Namun, saya tidak bisa membuatnya bekerja di IE8. Inilah yang akhirnya bekerja untuk saya (menggunakan sudut 1.0.6).

Perhatikan bahwa 'bind' memungkinkan Anda untuk menggunakan jqLite yang disediakan oleh angular sehingga tidak perlu membungkus dengan jQuery penuh. Juga diperlukan metode stopPropogation.

.directive('a', [
    function() {
        return {
            restrict: 'E',
            link: function(scope, elem, attrs) {

                elem.bind('click', function(e){
                    if (attrs.ngClick || attrs.href === '' || attrs.href == '#'){
                        e.preventDefault();
                        e.stopPropagation();
                    }
                })
            }
        };
    }
])

3
Ini membunuh banyak hal. Misalnya, ketika saya menggunakan Bootstrap Twitter dropdown, saya ingin propagasi tetapi bukan perilaku default. Cuplikan ini TIDAK disarankan.
Robin van Baalen

2

Saya mengalami masalah yang sama ketika menggunakan jangkar untuk drop down bootstrap sudut. Satu-satunya solusi yang saya temukan yang menghindari efek samping yang tidak diinginkan (mis. Drop down tidak menutup karena menggunakan preventDefault ()) adalah menggunakan yang berikut ini:

 <a href="javascript:;" ng-click="do()">Click</a>

2

jika Anda tidak pernah ingin pergi ke href ... Anda harus mengubah markup Anda dan menggunakan tombol bukan jangkar karena secara semantik itu bukan jangkar atau tautan. Sebaliknya jika Anda memiliki tombol yang melakukan beberapa pemeriksaan dan kemudian mengarahkan kembali itu harus menjadi tautan / tag jangkar dan bukan tombol ... untuk keperluan SEO juga pengujian [masukkan test suite di sini].

untuk tautan yang Anda hanya ingin mengarahkan kembali secara kondisional seperti meminta untuk menyimpan perubahan, atau mengakui kondisi kotor ... Anda harus menggunakan ng-klik = "someFunction ($ event)" dan di someFunction pada validasi AndaError preventDefault dan atau stopPropagation.

juga hanya karena Anda tidak dapat berarti Anda harus melakukannya . javascript: void (0) bekerja dengan baik pada hari itu ... tetapi karena peretas jahat / peramban menandai aplikasi / situs yang menggunakan javascript dalam sebuah href ... lihat tidak ada alasan untuk ducktype di atas ..

ini tahun 2016 sejak 2010 seharusnya tidak ada alasan di mana pun untuk menggunakan tautan yang bertindak seperti tombol ... jika Anda masih harus mendukung IE8 dan di bawah ini Anda perlu mengevaluasi kembali tempat bisnis Anda.


1
/* NG CLICK PREVENT DEFAULT */

app.directive('ngClick', function () {
    return {
        link: function (scope, element, attributes) {
            element.click(function (event) {
                event.preventDefault();
                event.stopPropagation();
            });
        }
    };
});

1

Yang harus Anda lakukan, adalah menghilangkan hrefatribut sepenuhnya.

Jika Anda melihat kode sumber untuk aarahan elemen (yang merupakan bagian dari inti Angular), kode itu menyatakan di baris 29 - 31:

if (!element.attr(href)) {
    event.preventDefault();
}

Yang berarti Angular sudah menyelesaikan masalah tautan tanpa href. Satu-satunya masalah yang masih Anda miliki adalah masalah css. Anda masih dapat menerapkan gaya pointer ke jangkar yang memiliki klik-ng, misalnya:

a[ng-click] {
    /* Styles for anchors without href but WITH ng-click */
    cursor: pointer;
}

Jadi, Anda bahkan dapat membuat situs Anda lebih mudah diakses dengan menandai tautan nyata dengan gaya yang berbeda, lalu tautan yang menjalankan fungsi.

Selamat coding!


1

Anda dapat menonaktifkan pengalihan url di dalam Html5Mode $ location untuk mencapai tujuan. Anda dapat mendefinisikannya di dalam kontroler spesifik yang digunakan untuk halaman tersebut. Sesuatu seperti ini:

app.config(['$locationProvider', function ($locationProvider) {
    $locationProvider.html5Mode({
        enabled: true,
        rewriteLinks: false,
        requireBase: false
    });
}]);


1

Jika Anda menggunakan Angular 8 atau lebih, Anda dapat membuat arahan:

import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[preventDefault]'
})
export class PreventDefaultDirective {

  @HostListener("click", ["$event"])
  public onClick(event: any): void
  {
    console.log('click');
    debugger;
      event.preventDefault();
  }

}

Pada tag jangkar Anda pada komponen Anda dapat mengirimkannya seperti ini:

  <a ngbDropdownToggle preventDefault class="nav-link dropdown-toggle" href="#" aria-expanded="false" aria-haspopup="true" id="nav-dropdown-2">Pages</a>

Modul Aplikasi harus memiliki deklarasi:

import { PreventDefaultDirective } from './shared/directives/preventdefault.directive';


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective

-1

Alternatifnya mungkin:

<span ng-click="do()">Click</span>

1
Merupakan praktik mengerikan untuk menyalahgunakan spanuntuk tujuan mengklik. Pergi saja untuk jawaban @ tennisgent - jangkar tanpa hrefditentukan.
Robin van Baalen


1
Jika Anda melakukan <span> Halo </span> sejak kapan itu bisa diklik? Apa yang spek katakan mungkin adalah bahwa <span> dapat digunakan di dalam elemen yang dapat diklik seperti <a> atau <button>. Tetapi sekali lagi, semua elemen blok inline (img, span, dll) dapat dibuat dapat diklik dengan cara itu. Rentang itu sendiri tidak dapat diklik.
Robin van Baalen

1
@RobinvanBaalen Silakan lihat tautan di atas. Atribut onclick untuk elemen span telah ditentukan sejak setidaknya HTML 4.01.
Terence Bandoian

1
Saya tidak pernah mengatakan bahwa menambahkan event handler tidak akan berhasil selama rentang waktu. Saya mengatakan itu adalah praktik yang buruk untuk membuat elemen yang tidak dapat diklik seperti span, div, section, ul, li, dll. Dapat diklik dengan menggunakan event handler javascript. Ini semua tentang semantik. Semantik dalam HTML adalah praktik memberi konten pada makna dan struktur halaman dengan menggunakan elemen yang tepat.
Robin van Baalen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.