Як запобігтиDefault у якорних тегах?


342

Скажімо, у мене є якорний тег типу

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

Як я можу запобігти переходу браузера до # в AngularJS ?


14
Як Кріс каже нижче, просто залиште href.
Джессі

13
Це не те, що говорить Кріс, Джессі, href=''щоб використовувати поведінку вказівника миші.
ома

1
Ви просто видаліть знак # з href, це нормально.
HENG Vongkol

4
Або просто використовуйте href = "javascript: void (0);" щоб утримати покажчик, але не робити жодних дій (поки ви не додасте ще один обробник кліків)
Robba

1
Чи можете ви, будь ласка, змінити прийняту відповідь на найкращу та найбільш голосувану Крисом - stackoverflow.com/a/11672909 ?
Пьотр Доброгост

Відповіді:


259

ОНОВЛЕННЯ : З того часу я передумав це рішення. Після більшого розвитку та витраченого часу на роботу, я вважаю, що кращим рішенням цієї проблеми є наступне:

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

А потім оновіть своє, cssщоб мати додаткове правило:

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

Його набагато простіше і забезпечує точно такий же функціонал і набагато ефективніше. Сподіваємось, що це може бути корисним для всіх, хто шукає це рішення в майбутньому.


Далі йде моє попереднє рішення, яке я залишаю тут лише для застарілих цілей:

Якщо у вас є ця проблема багато, проста директива, яка б вирішила цю проблему, полягає в наступному:

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

Він перевіряє всі теги прив’язки ( <a></a>), щоб побачити, чи є їх hrefатрибут порожнім рядком ( "") або хеш ( '#'), чи є ng-clickпризначення. Якщо він виявить будь-яке з цих умов, він вловлює подію і запобігає поведінці за замовчуванням.

Єдина нижня сторона - це те, що вона виконує цю директиву для всіх прив’язних тегів. Отже, якщо у вас багато тегів прив’язки на сторінці, і ви хочете лише запобігти поведінці за замовчуванням для невеликої кількості з них, то ця директива не дуже ефективна. Однак я майже завжди хочу цього робити preventDefault, тому я використовую цю директиву у всіх своїх програмах AngularJS.


2
Дякую @matejkramny, дуже конструктивна критика. Будь-які пропозиції зробити його менш "безладним"?
тенісист

1
Як зазначено в інших відповідях, наявність пустого hrefатрибута має різну поведінку в різних браузерах. Хоча я погоджуюся, що це на сьогоднішній день найчистіше та найефективніше рішення, але у нього є проблеми з перехресними браузерами. Використання директивного підходу дозволяє браузеру обробляти <a>теги так, як зазвичай, але все ж отримувати ОП відповідь, яку вони шукали.
тенісист

2
Це працює і все, окрім серйозної надмірності, для дуже простої проблеми. Angular надає вам доступ до об’єкта події за допомогою $ event, тому ви можете робити саме те, що ви робили в звичайних js або jquery подіях клацання. Дивіться цю відповідь stackoverflow.com/a/19240232/1826354 і мій коментар до неї
Чарлі Мартін

1
Так. Ти можеш. У цій публікації є ще два відповіді, які вже роблять те, що ви описуєте. І я згоден, це надмірно. Тому я зробив оновлення, яке я зробив.
тенісист

6
Це добре, якщо вам не байдуже доступність вашого сайту. Залишаючи href, не можна використовувати клавіатуру для вкладки на цей елемент. Якщо ви не додали табіндекс. Зважаючи на це, чому б не просто використовувати prevenDefault ...? Ось для чого його там.
duhseekoh

319

Згідно з документами для ngHref, ви повинні мати можливість залишити href або виконувати 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
Це єдина справді хороша відповідь. Все, що потребує дотику до DOM або рідних подій, викликає сумніви
vincent

4
Це правильна відповідь. Якщо ви
скинете

25
Єдиним недоліком відсутності атрибута href є те, що ви втрачаєте звичайний курсор "вказівника" під час наведення курсору на посилання. Ви можете виправити це, додавши правило до таблиці стилів: a: hover {cursor: pointer; }
karlgold

35
Майте на увазі, що це також робить тег неможливим для вкладки, що не дуже зручно для доступності.
Річард Шалай

3
Для мене браузер все ще кидає дію натискання: /
Matej

238

Ви можете передати об’єкт $ події своєму методу та зателефонувати $event.preventDefault()за ним, щоб обробка за замовчуванням не відбулася:

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

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

13
так, і ви також можете зателефонувати в $ event.stopPropagation (), щоб подія не спливала (в основному, у вас є доступ до об'єкта події, визначений W3C: w3.org/TR/DOM-Level-2- події / events.html # щодо події Event )
МНА

1
Зауважте, що на той час, коли це було написано, залишити href порожнім (або відсутнім) не працював на IE8 / 9 та Opera. Це було рік тому, і я не мав можливості спробувати його ще раз (я відкрив випуск тоді на Github, але, думаю, вони скинули проблеми деякий час тому). Якщо це виправлено (або ви не переймаєтесь цими веб-переглядачами), то, будь-ласка, використовуйте відповідь Кріса! Якщо хтось може спробувати це і прокоментувати / відредагувати відповідь, ще краще.
mna

1
@PuerkitoBio - Я можу підтвердити, що IE8 і нижче вимагає $event.preventDefault()... IE податку.
Scotty.NET

4
передача події $ контролеру означає посилання на DOM у вашому контролері, а це означає, що ви з'єднали свій погляд і контролер. Ви можете зателефонувати методам $ event безпосередньо у вашому оціненому виразі: ng-click="do(); $event.preventDefault()наприклад ... хоча, це не обов'язково, оскільки відповідь @ Кріса нижче - правильна. Це може допомогти людям у ситуаціях, коли вони вклали ngClicks і хочуть зателефонувати $event.stopPropagation().
Бен Леш

2
Нарешті, SEO-дружнє рішення. Ви можете також оновити URL-адресу браузера, не завантажуючи ng-view - joelsaupe.com/programming/… Таким чином, у вас є посилання, які не перезавантажують ваш погляд, але можуть бути відкриті на новій вкладці, і пошукові системи можуть слідувати за ними. ТАК!
Том

111

Я вважаю за краще використовувати директиви для подібних речей. Ось приклад

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

І код директиви для eat-click:

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

Тепер ви можете додати eat-clickатрибут до будь-якого елемента, і він отримає preventDefault()автоматичне редагування.

Переваги:

  1. Вам не доведеться передавати потворний $eventоб’єкт у свою do()функцію.
  2. Ваш контролер більш перевірений, оскільки йому не потрібно заглушувати $eventоб'єкт

1
@ Kato Angular оснащений власним набором jQuery, щоб полегшити наше життя.
Ніл

3
Додаткова вигода - це також працює в IE8 і нижче, якщо це має значення для вас.
Scotty.NET

1
Я отримую Error: $ is not defined. Що я пропускаю?
Білал Мірза

7
Я спробував angular.element(element).bind('click', function(event){...});. Це спрацювало. Посилання: jQLite
Білал Мірза

3
Введення директиви щодо чогось такого простого, здається, трохи роздуто, якщо ви запитаєте мене ... Перевірте Кріса його відповідь нижче
Wilt

54

Хоча Рено дав чудове рішення

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

Я особисто знайшов, що вам також потрібно $ event.stopPropagation (), щоб уникнути деяких побічних ефектів

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

буде моїм рішенням


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

13
Це найкраще рішення. Звичайно, ви можете передавати об’єкт $ події і вашій функції масштабу. Як і ng-click = "myFunction ($ подія, іншіParams), а потім $ event.preventDefault () у myFunction. Прокат власної директиви для цього є надмірним
Чарлі Мартін

34

Найпростіше рішення, яке я знайшов, це:

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

Це не тільки найпростіше, але також не поєднує події з контролером, як це пропонується в інших рішеннях. З'єднання подій з контролером - це те, чого слід уникати будь-якою ціною, оскільки це робить тестування набагато складніше.
jornare

11

Отже, читаючи ці відповіді, @Chris все ще має найбільш "правильну" відповідь, я думаю, але у нього є одна проблема, вона не показує "покажчик" ....

Тож ось два способи вирішити цю проблему без необхідності додавати курсор: pointer style:

  1. Використовуйте javascript:void(0)замість #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
  2. Використовуйте $event.preventDefault()в ng-clickдирективі (щоб ви не барахтували ваш контролер з посиланнями на DOM):

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

Особисто я віддаю перевагу першому, ніж останньому. javascript:void(0)є й інші переваги, про які йдеться тут . Також є обговорення "ненав'язливого JavaScript" у тому посиланні, яке лякає нещодавно, і не обов'язково безпосередньо стосується кутового додатка.


2
Чому це заборонено? Я також помітив, що покажчик не відображається з відповіддю від Кріса.
Вім Деблауве

2
javascript: void (0) набагато краще, ніж #, який може діяти на маршруті, якщо ви неправильно налаштували його. +1
Шай Елькаям

2
Я ось-ось збирався написати відповідь на це. Ви також можете зробитиjavascript:;
Адріан

10

Можна зробити наступним чином

1.Вилучіть hrefатрибут з aтега anchor ( )

2.Встановити курсор вказівника в css для ng елементів клацання

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

9

HTML

тут чистий angularjs: поруч із функцією ng-click можна записати функцію prevenDefault (), відокремлюючи крапку з комою

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

JS

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

(або)

Ви можете продовжувати цей шлях, про це вже йде мова.

HTML

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

JS

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

7

Спробуйте цей варіант, який я бачу, ще не вказаний вище:

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

6

Оскільки ви створюєте веб-додаток, навіщо вам потрібні посилання?

Поміняйте якіри на кнопки!

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

2
Оскільки Вень не може у веб-сайтів мати якір?
Робін ван Бален

1
Я мав на увазі те, що більшості веб-додатків не потрібні відносні посилання, як веб-сайти; вони також часто використовують прив’язні посилання як тригери javascript і не посилаються на сторінку; тому кнопка зі скиданням стилю за замовчуванням настільки ж семантично правильна, якщо не більше.
sidonaldson

3
@sidonaldson Насправді багато веб-додатків сьогодні сильно залежать від посилань. Подивіться на маршрутизацію angularjs.
Роберт

1
@Robert так, але якщо ви використовуєте вбудовану маршрутизацію, вам не потрібно керувати попередженням за замовчуванням, це робиться для вас. Я припускаю, що оскільки плакат хоче скасувати прив’язний зв'язок, він говорить про позашляхові посилання. Наприклад, запуск
модалі

2
Ця відповідь повинна мати набагато більше результатів. У багатьох випадках, якщо ви хочете запобігти поведінці якоря за замовчуванням, ви використовуєте якір як кнопку, а не посилання.
ItsCosmo

6

якщо все ще актуально:

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

...

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

...

6

Найбезпечнішим способом уникнути подій на href було б визначити його як

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

5

Я б пішов з:

<a ng-click="do()">Click</a>
  • тому що згідно з документами ви повинні мати можливість залишити href, і тоді Angular буде обробляти попередження за замовчуванням для вас!

Ціле це запобігання за замовчуванням мене бентежить, тому я створив там JSFiddle, що ілюструє, коли і де Angular заважає дефолту .

JSFiddle використовує директиву Angular - тому воно повинно бути ТОЧНО таким же. Ви можете побачити вихідний код тут: вихідний код тегу

Я сподіваюся, що це допоможе роз'ясненню для деяких.

Я хотів би опублікувати документа на ngHref, але не можу через свою репутацію.


5

Це те, що я завжди роблю. Працює як шарм!

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

4

Або якщо вам потрібен вбудований текст, ви можете зробити це:

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

4

Дуже багато відповідей здається непосильним. ДЛЯ МНЕ це працює

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

2

Мені потрібна наявність атрибута href для деградації (коли js вимкнено), тому я не можу використовувати порожній атрибут href (або "#"), але наведений вище код не працював для мене, тому що мені потрібна подія ( д) змінна. Я створив власну директиву:

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

В HTML:

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

2

Запозичення у відповіді тенісгента. Мені подобається, що вам не потрібно створювати власну директиву, щоб додавати всі посилання. Однак я не зміг заставити його працювати в IE8. Ось що, нарешті, працювало для мене (використовуючи кутовий 1.0.6).

Зверніть увагу, що "bind" дозволяє використовувати jqLite, наданий кутовим, тому не потрібно завершувати повний jQuery. Також потрібен метод 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
Це багато чого вбиває. Наприклад, коли я використовую Twitter Bootstrap dropdown, я хочу розповсюдження, але не поведінку за замовчуванням. Цей фрагмент НЕ рекомендується.
Робін ван Бален

2

Я зіткнувся з цим самим питанням, коли використовував анкери для кутового завантажувального падіння вниз. Єдине рішення, яке я знайшов, щоб уникнути небажаних побічних ефектів (тобто падіння, яке не закривалося через використання prevenDefault ()), було використання наступного:

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

2

якщо ви ніколи не хочете переходити до href ... слід змінити розмітку і використовувати кнопку не тег прив’язки, оскільки семантично це не якір чи посилання. І навпаки, якщо у вас є кнопка, яка робить деякі перевірки, а потім переспрямовує, це має бути тег посилання / прив’язки, а не кнопка ... для цілей SEO, а також тестування [сюди вставити тестовий набір].

для посилань, які ви хочете лише переадресувати лише умовно, як, наприклад, запит на збереження змін або підтвердження брудного стану ... ви повинні використовувати ng-click = "someFunction ($ подія)", а в деякихFunction на вашій валідаціїError prevenDefault та або stopPropagation.

також тільки тому, що ви не можете означати, що слід . javascript: void (0) добре спрацював у той час ... але через жахливі хакери / зломщики браузерів прапор програм / сайтів, які використовують javascript в рамках href ... не бачити причин для того, щоб ducktype був вище.

це 2016 рік з 2010 року. Ніде не майте причин використовувати посилання, які діють як кнопки ... якщо вам все-таки потрібно підтримувати IE8 і нижче, вам потрібно переоцінити своє місце роботи.


1
/* NG CLICK PREVENT DEFAULT */

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

1

Що ви повинні зробити, це hrefповністю опустити атрибут.

Якщо ви подивитеся на вихідний кодa директиви щодо елемента (який є частиною кутового ядра), у рядку 29 - 31 зазначено:

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

Що означає, що Angular вже вирішує питання про посилання без href. Єдине питання, який у вас все ще є, це проблема css. Ви все ще можете застосувати стиль вказівника до якорів, які мають ng-клацання, наприклад:

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

Таким чином, ви навіть можете зробити свій сайт більш доступним, позначивши реальні посилання тонкими, різними стилями, а потім посиланнями, що виконують функції.

Щасливого кодування!


1

Ви можете відключити переадресацію URL-адреси всередині Html5Mode $ location для досягнення мети. Ви можете визначити його всередині певного контролера, який використовується для сторінки. Щось на зразок цього:

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


1

Якщо ви використовуєте Angular 8 або більше, ви можете створити директиву:

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

}

У своєму тезі прив’язки до компонента ви можете його провести так:

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

Модуль додатка повинен мати свою декларацію:

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


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective

-1

Альтернативою може бути:

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

1
Жахлива практика зловживати spanцілями для клацання. Просто перейдіть до відповіді @ тенісгента - якоря без hrefвизначеного.
Робін ван Бален

1
@RobinvanBaalen Елемент span визначено як натискання, оскільки принаймні HTML 4.0.1: w3.org/TR/html401/struct/global.html#edef-SPAN w3.org/TR/html5/dom.html#global-attributes html.spec.whatwg.org/multipage/dom.html#global-attributes
Теренс Бандоян

1
Якщо ви робите <span> привіт </span> з тих пір, коли це натискання? Те, що, напевно, говорить про те, що <span> можна використовувати всередині елемента, який можна натиснути, наприклад <a> чи <but>. Але знову ж таки, всі елементи вбудованого блоку (img, span тощо) можна зробити так, щоб їх можна було натискати таким чином. Сам проміжок не можна натискати.
Робін ван Баален

1
@RobinvanBaalen Перегляньте посилання вище. Атрибут onclick для елементів span визначено щонайменше за HTML 4.01.
Теренс Бандоян

1
Я ніколи не говорив, що додавання обробника подій не буде працювати протягом певного періоду. Я сказав, що це погана практика робити елемент, який не можна натискати, наприклад, проміжок, розділ, розділ, ul, li тощо. Вся справа в семантиці. Семантика в HTML - це практика надання вмісту на сторінці значення та структури за допомогою відповідного елемента.
Робін ван Баален
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.