Как предотвратить дефолт по тегам привязки?

311

Скажем, у меня есть якорный тег, например

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

Как я могу запретить браузеру переходить на # в AngularJS?

  • 13
    Как говорит Крис ниже, просто оставьте без href .
  • 12
    Это не то, что говорит Крис, Джесси, используйте href='' чтобы сохранить поведение указателя мыши.
Показать ещё 3 комментария
Теги:
preventdefault

26 ответов

233
Лучший ответ

ОБНОВЛЕНИЕ. С тех пор я решил изменить это решение. После большего развития и времени, потраченного на это, я считаю, что лучшим решением этой проблемы является следующее:

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

  • 0
    Спасибо за идею. Пришлось изменить его, чтобы он работал в IE8. Смотрите мой ответ ниже.
  • 2
    Спасибо @matejkramny, очень конструктивная критика. Любые предложения, чтобы сделать его менее "грязным"?
Показать ещё 19 комментариев
296

В соответствии с docs для ngHref вы должны уйти с href или do 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 или родным событиям, сомнительно
  • 4
    Это правильный ответ. Если вы удалите href из атрибута <a>, AngularJS вызовет предотвращение по умолчанию:
Показать ещё 15 комментариев
211

Вы можете передать объект $event вашему методу и вызвать $event.preventDefault() на нем, чтобы обработка по умолчанию не выполнялась:

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

// then in your controller.do($event) method
$event.preventDefault()
  • 0
    Это должно работать с не # URL?
  • 13
    да, и вы также можете вызвать $ event.stopPropagation (), чтобы событие не всплыло (в основном, у вас есть доступ к объекту Event, как определено в W3C: w3.org/TR/DOM-Level-2- Events / events.html # Events-Event )
Показать ещё 7 комментариев
100

Я предпочитаю использовать директивы для такого рода вещей. Вот пример

<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() '.

Преимущества:

  • Вам не нужно передавать уродливый объект $event в вашу do() функцию.
  • Ваш контроллер более подвержен тестированию, потому что ему не нужно вырезать $event.object
  • 3
    Можно ли это сделать без использования jQuery?
  • 1
    @Kato Angular поставляется с собственным набором jQuery, чтобы сделать нашу жизнь проще.
Показать ещё 6 комментариев
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()"
  • 12
    Это лучшее решение. Конечно, вы могли бы также передать объект $ event вашей функции области видимости. Как ng-click = "myFunction ($ event, otherParams), а затем $ event.preventDefault () в myFunction. Откатить собственную директиву для этого - излишество
33

Самое легкое решение, которое я нашел, это:

<a href="#" ng-click="do(); $event.preventDefault()">Click</a>
  • 0
    Это не только самое простое, но и не связывает события с контроллером, как предлагалось в других решениях. Связывание событий с контроллером - это то, чего вам следует избегать любой ценой, поскольку это значительно усложняет тестирование.
  • 0
    Этот ответ также имеет хороший курсор мыши при использовании.
10

Поэтому, читая эти ответы, @Chris все еще имеет самый "правильный" ответ, я полагаю, но у него есть одна проблема, он не показывает "указатель"....

Итак, вот два способа решить эту проблему, не добавляя курсора: стиль указателя:

  • Используйте javascript:void(0) вместо #:

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
    
  • Используйте $event.preventDefault() в директиве ng-click (чтобы вы не загружали ваш контроллер ссылками, связанными с DOM):

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

Лично я предпочитаю первого над последним. javascript:void(0) имеет другие преимущества, которые обсуждаются здесь. Существует также обсуждение "ненавязчивого JavaScript" в этой ссылке, которая пугающе недавно, и не обязательно непосредственно относится к приложению angular.

  • 1
    Почему это понижено? Я также заметил, что указатель не отображается с ответом от Криса.
  • 1
    javascript: void (0) намного лучше, чем #, который может действовать на маршруте, если вы его неправильно настроите. +1
Показать ещё 1 комментарий
9

Вы можете сделать следующее:

1.Удалить атрибут href из тега anchor (a)

2. Установить курсор указателя в элементах css для ng click

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

HTML

здесь pure angularjs: рядом с функцией ng-click вы можете написать функцию preventDefault(), разделив точку с запятой

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

Попробуйте этот параметр, который я вижу, еще не указан выше:

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

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

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

...

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

...
5

Поскольку вы создаете веб-приложение, почему вам нужны ссылки?

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

<button ng-click="do()"></button>
  • 1
    Раз уж у веба не может быть якорей?
  • 0
    Я имел в виду, что большинству веб-приложений не нужны относительные ссылки, как это делают веб-сайты, они также часто используют якорные ссылки в качестве триггеров JavaScript и не ссылаются на страницу; поэтому кнопка со сбросом стиля по умолчанию так же семантически верна, если не больше.
Показать ещё 3 комментария
4

Это то, что я всегда делаю. Работает как шарм!

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

Я бы пошел с:

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

Все это предотвращает меня по умолчанию, поэтому я создал JSFiddle там, где и где Angular предотвращает по умолчанию.

JSFiddle использует директиву Angular, поэтому она должна быть ТОЧНО одинаковой. Вы можете увидеть исходный код здесь: исходный код тега

Надеюсь, это поможет прояснить некоторые.

Мне бы хотелось опубликовать документ до ngHref, но я не могу из-за своей репутации.

3

Или, если вам нужна встроенная строка, вы можете сделать это:

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

Самый безопасный способ избежать событий на href - определить его как

<a href="javascript:void(0)" ....>
  • 1
    или просто <a href="javascript:" ....> отлично работает для меня
1

Многие ответы кажутся излишними. Для меня это работает

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

если вы никогда не хотите идти в href... вы должны изменить свою разметку и использовать кнопку, а не тег привязки, потому что семантически это не привязка или ссылка. И наоборот, если у вас есть кнопка, которая выполняет некоторые проверки, а затем перенаправляет ее, это должен быть тег link/anchor, а не кнопка... для целей SEO, а также тестирование [вставить тестовый набор здесь].

для ссылок, которые вы только хотите перенаправить условно, как запрос на сохранение изменений или подтверждение грязного состояния... вы должны использовать ng-click = "someFunction ($ event)" и в someFunction на вашем validationError preventDefault и /stopPropagation.

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

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

1

Я столкнулся с этой проблемой при использовании якорей для бутстрапа angular. Единственное решение, которое я нашел, чтобы избежать нежелательных побочных эффектов (т.е. Падение вниз, не закрывающееся из-за использования preventDefault()), состояло в следующем:

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

Заимствование из ответа на теннис. Мне нравится, что вам не нужно создавать настраиваемую директиву для добавления во все ссылки. Однако я не мог заставить его работать в IE8. Вот что, наконец, сработало для меня (используя angular 1.0.6).

Обратите внимание, что 'bind' позволяет использовать jqLite, предоставляемый angular, поэтому нет необходимости обертывать полным 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();
                    }
                })
            }
        };
    }
])
  • 2
    Это убивает много. Например, когда я использую dropdown список Twitter Bootstrap, я хочу распространение, но не поведение по умолчанию. Этот фрагмент НЕ рекомендуется.
1

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

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

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

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

Что вы должны сделать, полностью опускает атрибут href.

Если вы посмотрите на исходный код для директивы элемента a (которая является частью ядра Angular), это состояния в строке 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;
}

Таким образом, вы даже можете сделать свой сайт более доступным, отметив реальные ссылки с тонким, другим стилем, а затем ссылками, которые выполняют функции.

Счастливое кодирование!

0
/* NG CLICK PREVENT DEFAULT */

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

Альтернативой может быть:

<span ng-click="do()">Click</span>
  • 0
    Это ужасная практика - злоупотреблять span для кликающих целей. Просто ответьте на вопрос @ tennisgent - якоря без определения href .
  • 0
    @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
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню