Ankraj etiketlerinde varsayılanlar nasıl önlenir?


342

Diyelim ki böyle bir çapa etiketim var

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

AngularJS'de tarayıcının # numarasına gitmesini nasıl önleyebilirim ?


14
Chris'in dediği gibi, dışarıda bırakın href.
Jesse

13
Chris'in söylediği bu değil, Jesse, href=''fare işaretçisi davranışını korumak için kullanın .
oma

1
Sadece # işaretini href'den kaldırırsınız, sorun değil.
HENG Vongkol

4
Veya sadece href = "javascript: void (0);" işaretçiyi saklamak ama hiçbir işlem
yapmamak

1
Chris - stackoverflow.com/a/11672909 tarafından kabul edilen cevabı en iyi ve en çok oy alan cevapla değiştirebilir misiniz ?
Piotr Dobrogost

Yanıtlar:


259

GÜNCELLEME : O zamandan beri bu çözüm hakkındaki fikrimi değiştirdim. Bu konuda daha fazla gelişme ve zaman geçirdikten sonra, bu soruna daha iyi bir çözümün aşağıdakileri yapmak olduğuna inanıyorum:

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

Ve sonra cssekstra bir kurala sahip olmak için güncelleyin :

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

Çok daha basit ve aynı işlevselliği sağlar ve çok daha verimlidir. Umarım gelecekte bu çözümü arayan herkese yardımcı olabilir.


Aşağıda, sadece eski amaçlar için burada bıraktığım önceki çözümüm:

Bu sorunu çok yaşıyorsanız, bu sorunu giderecek basit bir yönerge şudur:

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

Özniteliklerinin boş bir dize ( ) veya karma ( ) olup olmadığını veya bir atama <a></a>olup olmadığını görmek için tüm bağlantı etiketlerini ( ) kontrol eder . Bu koşullardan herhangi birini bulursa, olayı yakalar ve varsayılan davranışı önler.href""'#'ng-click

Tek aşağı tarafı, tüm bağlayıcı etiketler için bu yönergeyi çalıştırmasıdır. Dolayısıyla, sayfada çok fazla bağlayıcı etiketiniz varsa ve yalnızca az sayıda varsayılan davranışı önlemek istiyorsanız, bu yönerge çok verimli değildir. Ancak, neredeyse her zaman istiyorum preventDefault, bu yüzden bu direktifi AngularJS uygulamalarımda her yerde kullanıyorum.


2
Teşekkürler matejkramny, çok yapıcı eleştiri. Daha az "dağınık" yapmak için herhangi bir öneriniz var mı?
Tennisgent

1
Diğer yanıtlarda belirtildiği gibi, boş bir hrefözniteliğe sahip olmak farklı tarayıcılarda farklı davranışlara sahiptir. Şimdiye kadar en temiz ve en verimli çözüm olduğunu kabul etsem de, bazı tarayıcılar arası sorunları var. Yönerge yaklaşımını kullanmak, tarayıcının <a>etiketi normalde olduğu gibi işlemesine izin verir , ancak yine de OP'ye aradıkları yanıtı alır.
tennisgent

2
Bu işe yarıyor ve çok basit bir problem için ciddi bir şekilde abartılıyor. Açısal, $ event ile olay nesnesine erişmenizi sağlar, böylece düz js veya jquery click olaylarında tam olarak ne yapacağınızı yapabilirsiniz. Bu cevaba bakın stackoverflow.com/a/19240232/1826354 ve bu konu hakkındaki yorumum
Charlie Martin

1
Evet. Yapabilirsin. Bu yayında, açıkladığınızı zaten yapan iki yanıt daha var. Ve katılıyorum, aşırı dolu. Bu yüzden yaptığım güncellemeyi yaptım.
tennisgent

6
Sitenizdeki erişilebilirliği umursamıyorsanız bu sorun olmaz . Href'i bırakarak, o öğeye sekmek için klavyenizi kullanmanız mümkün değildir. Tabindex eklemediğiniz sürece. Tüm bunları göz önünde bulundurarak, niçin sadece preventDefault kullanmıyorsunuz? Orada bunun için var.
duhseekoh

319

NgHref belgelerine göre href'i bırakabilmeniz veya href = "" yapabilmeniz gerekir.

<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
Tek gerçek iyi cevap bu. DOM veya yerel etkinliklere dokunmayı gerektiren her şey
şüphelidir

4
Bu doğru cevap. <a> özniteliğinden href bırakırsanız, AngularJS önleme varsayılanını çağırır:
pkozlowski.opensource

25
Href niteliğini bırakmanın tek dezavantajı, bir bağlantının üzerine geldiğinizde normal 'işaretçi' imlecini kaybetmenizdir. Stil sayfanıza bir kural ekleyerek bunu düzeltebilirsiniz: a: hover {cursor: pointer; }
karlgold

35
Bunun, etiketi erişilebilirlik dostu olmayan, etiketin kaldırılamaz hale getirdiğini de unutmayın.
Richard Szalay

3
Benim için tarayıcı hala tıklama eylemi kabarcıklar: /
Matej

238

$ Event nesnesini yönteminize iletebilir ve $event.preventDefault()varsayılan işlemenin gerçekleşmemesi için çağırabilirsiniz :

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

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

13
evet, ayrıca olayın patlamaması için $ event.stopPropagation () öğesini çağırabilirsiniz (temel olarak, W3C tarafından tanımlanan Etkinlik nesnesine erişebilirsiniz: w3.org/TR/DOM-Level-2- Olaylar / events.html # Olaylar-Event )
mna

1
Zamanda bu boş (veya yok) href bırakarak yazılı olduğu not yaptım lütfen değil IE8 / 9 ve Opera üzerinde çalışır. Bu bir yıl önceydi ve tekrar deneme şansım olmadı (Github'da bir sorun açtım, ancak bir süre önce sorunları sıfırladıklarını düşünüyorum). Bu düzeltildiyse (veya bu tarayıcıları umursamıyorsanız), elbette Chris'in cevabını kullanın! Birisi deneyebilir ve yanıtı yorumlayabilir / düzenleyebilirse, daha da iyisi.
mna

1
@PuerkitoBio - IE8 ve aşağılarının hala $event.preventDefault()IE vergisi gerektirdiğini onaylayabilirim .
Scotty.NET

4
$ etkinliğinin denetleyiciye iletilmesi, denetleyicinizdeki DOM'a başvurmak anlamına gelir; bu, görünümünüzü ve denetleyicinizi birleştirdiğiniz anlamına gelir. $ Event yöntemlerini doğrudan değerlendirilen ifadenizde çağırabilirsiniz: ng-click="do(); $event.preventDefault()örneğin ... gerekli değildir, çünkü @ Chris'in aşağıdaki cevabı doğru cevaptır. Bu, ngClicks'i iç içe yerleştirdikleri ve aramak istedikleri durumlarda insanlara yardımcı olabilir $event.stopPropagation().
Ben Lesh

2
Sonunda SEO dostu bir çözüm. Ayrıca ng- view'i yeniden yüklemeden tarayıcı URL'sini de güncellemek isteyebilirsiniz - joelsaupe.com/programming/… Bu şekilde, görünümünüzü yeniden yüklemeyen ancak yeni bir sekmede açılabilir bağlantılara sahip olursunuz ve arama motorları bunları takip edebilir. YAŞASIN!
Tom

111

Bu tür şeyler için direktifleri kullanmayı tercih ederim . İşte bir örnek

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

Ve yönerge kodu eat-click:

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

Artık eat-clicközelliği herhangi bir öğeye ekleyebilirsiniz;preventDefault() düzenlenecektir.

Yararları:

  1. Çirkin $eventnesneyido() işlevinize .
  2. Denetleyiciniz daha fazla birim test edilebilir, çünkü $eventnesneyi saplamak zorunda değil

1
@Kato Angular, hayatımızı kolaylaştırmak için kendi jQuery alt kümesiyle birlikte gelir.
Neil

3
Ek fayda - bu sizin için önemliyse , IE8 ve aşağısında da çalışır .
Scotty.NET

1
Ben alıyorum Error: $ is not defined. Neyi kaçırıyorum?
Bilal Mirza

7
Denedim angular.element(element).bind('click', function(event){...});. İşe yaradı. Referans: jQLite
Bilal Mirza

3
Bana sorarsanız böyle basit bir şey için bir direktifle tanışmak biraz şişmiş gibi görünüyor ... Chris'e aşağıdaki cevabını kontrol et
Wilt

54

Renaud harika bir çözüm verse de

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

Şahsen ben de bazı yan etkileri önlemek için $ event.stopPropagation () gerekir bulundu

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

benim çözümüm olacak


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

13
Bu en iyi çözümdür. Elbette, $ event nesnesini kendi kapsam işlevinize de iletebilirsiniz. Ng-click = "myFunction ($ event, otherParams) ve sonra myFunction'daki $ event.preventDefault () gibi. Bunun için kendi direktifinizi yuvarlamak abartılı
Charlie Martin

34

Bulduğum en kolay çözüm şudur:

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

Bu sadece en kolay değil, aynı zamanda diğer çözümlerde önerildiği gibi olayları denetleyiciyle birleştirmez. Olayları bir denetleyiciye bağlamak, test etmeyi çok daha zorlaştırdığı için her ne pahasına olursa olsun kaçınmanız gereken bir şeydir.
jornare

11

Yani bu cevapları okurken, @Chris hala en "doğru" cevabı var, sanırım, ama bir sorunu var, "işaretçi" göstermez ....

İşte bir imleç eklemenize gerek kalmadan bu sorunu çözmenin iki yolu: işaretçi stili:

  1. Şunun javascript:void(0)yerine kullanın #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
  2. Kullanım $event.preventDefault()içinde ng-clickdirektifi (DOM ile ilgili referanslar ile denetleyici kadar çöpe kalmaz):

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

Şahsen ben ikincisini ikincisine tercih ederim. burada tartışılanjavascript:void(0) başka faydaları da vardır . Ayrıca bu bağlantıda korkutucu bir şekilde yeni olan ve doğrudan açısal bir uygulama için doğrudan geçerli olmayan "göze batmayan JavaScript" tartışması da vardır.


2
Bu neden reddedildi? Ayrıca işaretçinin Chris'in cevabı ile gösterilmediğini de fark ettim.
Wim Deblauwe

2
javascript: void (0), # 'dan çok daha iyidir, bu da yanlış yapılandırırsanız rota üzerinde etkili olabilir. +1
Shay Elkayam

2
Buna bir cevap yazmak üzereydim. Ayrıca şunları da yapabilirsinizjavascript:;
Adrian

10

Aşağıdaki gibi yapabilirsiniz

1. hrefözniteliği nitelikten kaldırın (a ) etiketinden

2. tıklama öğelerini css olarak işaretçi imlecini ayarla

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

9

HTML

here pure angularjs: ng-click fonksiyonunun yakınında noktalı virgül ayırarak preventDefault () fonksiyonu yazabilirsiniz

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

JS

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

(veya)

bu yoldan devam edebilirsiniz, bu zaten burada tartışılıyor.

HTML

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

JS

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

7

Yukarıda listelenen görebildiğim bu seçeneği deneyin:

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

6

Bir web uygulaması yaptığınız için neden bağlantılara ihtiyacınız var?

Ankrajlarınızı düğmelere değiştirin!

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

2
Wen webapps'lerin çapaları olmadığından mı?
Robin van Baalen

1
Çoğu web uygulamasının web siteleri gibi göreli bağlantılara ihtiyaç duymadığı noktasını kastediyordum, genellikle sadece javascript tetikleyicileri olarak bağlantı bağlantılarını kullanıyorlar ve bir sayfaya bağlantı vermiyorlar; bu nedenle, varsayılan stil sıfırlama özelliğine sahip bir düğme daha fazla değilse semantik olarak doğrudur.
sidonaldson

3
@sidonaldson Aslında, günümüzde birçok web uygulaması büyük ölçüde bağlantılara bağlıdır. Angularjs yönlendirmesine bakın.
Robert

1
@Robert evet ancak yerleşik yönlendirmeyi kullanırsanız, varsayılanları engellemeniz gerekmez, bu sizin için yapılır. Poster, rota dışı bağlantılar hakkında konuştuğu bir bağlantı bağlantısını iptal etmek istediğinden eminim. Örneğin, bir modal vb. Fırlatma
sidonaldson

2
Bu cevabın çok daha fazla oyu olmalı. Çoğu durumda, varsayılan bağlantı davranışını önlemek istiyorsanız, bağlantıyı bir bağlantı olarak değil bir düğme olarak kullanırsınız.
ItsCosmo

6

hala alakalı ise:

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

...

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

...

6

Bir href üzerindeki olaylardan kaçınmanın en güvenli yolu onu

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

5

Ben giderdim:

<a ng-click="do()">Click</a>
  • çünkü belgelere göre href'den çıkabilmelisiniz ve daha sonra Açısal sizin için varsayılanı ele alacaktır!

Bütün bu önleme varsayılan şey benim için kafa karıştırıcı oldu, bu yüzden orada ne zaman ve nerede Angular varsayılan engelliyor göstermek bir JSFiddle oluşturduk .

JSFiddle Angular'ın bir direktifini kullanıyor - bu yüzden TAM aynı olmalıdır. Kaynak kodu burada görebilirsiniz: bir etiket kaynak kodu

Umarım bu bazıları için açıklığa yardımcı olur.

Dokümanı ngHref'e göndermek isterdim ama itibarım yüzünden yapamam.


5

Hep böyle yapıyorum. Tıkır tıkır çalışıyor!

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

4

Ya da satır içi ihtiyacınız varsa bunu yapabilirsiniz:

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

4

Birçok cevap aşırıya kaçmış gibi görünüyor. BENİM İÇİN bu işe yarıyor

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

2

Ben boş href özniteliği (veya "#") kullanamam (bu yüzden boş bir href özniteliği (veya "#") kullanamazsınız, ancak bir olay (çünkü bir olay ( e) değişken. Kendi direktifimi yarattım:

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

HTML'de:

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

2

Tenisçinin cevabından borçlanma. Tüm bağlantıları eklemek için özel bir yönerge oluşturmanıza gerek yok. Ancak, onun IE8 çalışmak için alamadım. Sonunda benim için işe yarayan şey (açısal 1.0.6 kullanarak).

'Bind' komutunun açısal tarafından sağlanan jqLite kullanmanıza izin verdiğine dikkat edin, böylece tam jQuery ile sarmaya gerek yoktur. Ayrıca stopPropogation yöntemi gerekli.

.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
Bu çok şey öldürüyor. Örneğin, Twitter Bootstrap's kullandığımda dropdown, yayılımı istiyorum, ancak varsayılan davranışı istiyorum. Bu parçacık olduğunu DEĞİL önerilir.
Robin van Baalen

2

Açılı bir bootstrap açılır için çapa kullanırken bu aynı sorunla karşılaştım. İstenmeyen yan etkilerden kaçındığını bulduğum tek çözüm (yani, defada bırakma () nedeniyle kapanma kapanmıyor) aşağıdakileri kullanmaktı:

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

2

href'e hiç gitmek istemiyorsanız ... işaretlemenizi değiştirmeli ve bağlantı etiketi değil bir düğme kullanmalısınız çünkü anlamsal olarak bir bağlantı veya bağlantı değildir. Tersine, bazı kontroller yapan ve daha sonra yönlendiren bir düğme varsa, bir bağlantı / bağlantı etiketi değil, bir düğme olmalıdır ... SEO amacıyla da test [test paketi buraya ekleyin].

yalnızca değişiklikleri kaydetmeyi istemek veya kirli durumu kabul etmek gibi koşullu olarak yeniden yönlendirmek istediğiniz bağlantılar için ... ng-click = "someFunction ($ event)" kullanmanız ve validationError preventDefault ve / stopPropagation öğelerinde someFunction kullanmanız gerekir.

ayrıca sadece yapabileceğiniz için yapmanız gerektiği anlamına gelmez . javascript: void (0) gün içinde iyi çalıştı ... ama hain hackerlar / krakerler nedeniyle tarayıcılar bir href içinde javascript kullanan uygulamaları / siteleri bayrak ... yukarıdaki ducktype için bir neden görmüyorum ..

2010'dan beri, düğmeler gibi davranan bağlantıları kullanmak için hiçbir yerde 2016 olmamalı ... IE8'i desteklemeniz gerekiyorsa ve aşağıda iş yerinizi yeniden değerlendirmeniz gerekiyor.


1
/* NG CLICK PREVENT DEFAULT */

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

1

Yapmanız gereken, hrefniteliği tamamen atlamaktır.

Eğer bakarsak kaynak kodu için a(Açısal çekirdeğin bir parçası olan) eleman direktifi, bu satır 29 ülkesi - 31:

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

Yani Angular zaten bağlantı sorununu bir href olmadan çözüyor. Hala sahip olduğunuz tek sorun css problemidir. İşaretçi stilini yine de ng tıklaması olan bağlantılara uygulayabilirsiniz, örneğin:

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

Böylece, gerçek bağlantıları ince, farklı bir stil ve ardından işlevleri gerçekleştiren bağlantılar ile işaretleyerek sitenizi daha erişilebilir hale getirebilirsiniz.

Mutlu kodlama!


1

Hedefe ulaşmak için $ location'ın Html5Mode içindeki URL yönlendirmesini devre dışı bırakabilirsiniz. Bunu sayfa için kullanılan belirli bir denetleyicinin içinde tanımlayabilirsiniz. Bunun gibi bir şey:

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


1

Açısal 8 veya daha fazlasını kullanıyorsanız bir yönerge oluşturabilirsiniz:

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

}

Bileşen üzerindeki bağlantı etiketinizde şu şekilde bağlayabilirsiniz:

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

Uygulama Modülünün beyanı olmalıdır:

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


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective

-1

Bir alternatif şunlar olabilir:

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

1
Tıklama amacıyla kötüye kullanmak korkunç bir uygulamadır span. @ Tennisgent'ın cevabına gidin - hreftanımlanmadan çapalar .
Robin van Baalen


1
<span> Merhaba </span> yaparsanız ne zaman tıklanabilir? Spesifikasyonun muhtemelen söylediği şey, bir <span> 'ın <a> veya <düğmesi> gibi tıklanabilir bir öğenin içinde kullanılabileceğidir. Ama sonra tekrar, tüm satır içi blok elemanları (img, span, vb.) Bu şekilde tıklanabilir hale getirilebilir. Bir yayılma alanının kendisi tıklanabilir değildir.
Robin van Baalen

1
@RobinvanBaalen Lütfen yukarıdaki bağlantılara bakın. Span öğeleri için onclick özelliği, en az HTML 4.01'den beri tanımlanmıştır.
Terence Bandoian

1
Bir olay işleyicisi eklemenin açıklık için işe yaramayacağını hiç söylemedim. Bir javascript olay işleyicisi kullanarak bir yayılma alanı, div, bölüm, ul, li, vb. Gibi tıklanabilir olmayan bir öğeyi tıklatmanın kötü bir uygulama olduğunu söyledim. Her şey anlambilimle ilgilidir. HTML içindeki anlambilim, uygun öğeyi kullanarak sayfa anlamı ve yapısında içerik verme pratiğidir.
Robin van Baalen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.