앵커 태그에서 기본값을 방지하는 방법은 무엇입니까?


342

다음과 같은 앵커 태그가 있다고 가정 해 봅시다.

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

AngularJS 에서 브라우저가 #으로 이동하지 못하게하려면 어떻게 해야합니까?


14
Chris가 아래에 말한 것처럼을 제외하십시오 href.
— Jesse

13
제시 href=''는 마우스 포인터 동작을 유지하기 위해 사용 하는 것이 아닙니다 .
— oma

1
href에서 # 기호를 제거하면 괜찮습니다.
— HENG Vongkol

4
또는 href = "javascript : void (0);"를 사용하십시오. 포인터를 유지하지만 동작이 없음 (다른 클릭 핸들러를 추가 할 때까지)
— Robba

1
- 당신은 대부분의 크리스 하나 선정 최고의로 변경 허용 대답하시기 바랍니다 수 stackoverflow.com/a/11672909를 ?
— Piotr Dobrogost

답변:


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에게 감사드립니다. 덜 "더러운"것으로 만드는 제안?
— tennisgent

1
다른 답변에서 언급했듯이 공백 href속성은 브라우저마다 다르게 작동합니다. 나는 그것이 가장 깨끗하고 가장 효율적인 솔루션이라는 데 동의하지만 브라우저 간 문제가 있습니다. 지시어 접근 방식을 사용하면 브라우저가 <a>평소와 같이 태그 를 처리 할 수 있지만 여전히 원하는 답을 OP에 표시 할 수 있습니다.
— tennisgent

2
이것은 매우 간단한 문제로 심각하게 과도하게 작동합니다. Angular를 사용하면 $ event로 이벤트 객체에 액세스 할 수 있으므로 일반 js 또는 jquery 클릭 이벤트에서 수행 할 작업을 정확하게 수행 할 수 있습니다. 이 답변을보십시오 stackoverflow.com/a/19240232/1826354 그리고 그것에 대한 내 의견
— Charlie Martin

1
네. 할 수 있습니다. 이 게시물에는 이미 설명하고있는 다른 두 가지 답변이 있습니다. 그리고 나는 동의합니다. 그것은 과잉입니다. 그래서 업데이트를 한 것입니다.
— tennisgent

6
사이트의 접근성 에 신경 쓰지 않으면 괜찮습니다 . href를 생략하면 키보드를 사용하여 해당 항목을 탭할 수 없습니다. tabindex를 추가하지 않은 경우 모든 것을 염두에두고, preventDefault를 사용하지 않는 이유는 무엇입니까? 그것이 거기에있는 것입니다.
— duhseekoh

319

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
이것이 정답입니다. <a> 속성에서 href를 삭제하면 AngularJS는 기본값 방지를 호출합니다.
— pkozlowski.opensource

25
href 속성을 제거하는 유일한 단점은 링크를 가리킬 때 정상적인 '포인터'커서를 잃는다는 것입니다. 스타일 시트에 규칙을 추가하여이 문제를 해결할 수 있습니다. a : hover {cursor : pointer; }
— karlgold

35
또한 태그를 탭할 수 없게되므로 접근하기가 쉽지 않습니다.
— Richard Szalay

3
나를 위해 브라우저는 여전히 클릭 동작을 버블 링합니다 : /
— Matej

238

기본 이벤트 $event.preventDefault()가 발생하지 않도록 $ event 객체를 메소드에 전달하고 호출 할 수 있습니다.

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

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

13
예, $ event.stopPropagation ()을 호출하여 이벤트가 버블 링되지 않도록 할 수 있습니다 (기본적으로 W3C에 정의 된대로 Event 객체에 액세스 할 수 있음) : w3.org/TR/DOM-Level-2- Events / events.html # Events-Event )
— mna

1
작성된 시점에 href를 비워 두거나 IE8 / 9 및 Opera 에서 href를 비워 두지 않았습니다 . 이것은 1 년 전이며 다시 시도 할 기회가 없었습니다 (Github에서 문제를 다시 열었지만 몇 시간 전에 문제를 재설정했다고 생각합니다). 이것이 고정되어 있거나 브라우저에 신경 쓰지 않는다면 반드시 Chris의 대답을 사용하십시오! 누군가가 그것을 시도하고 답변을 주석 / 편집 할 수 있다면 더 좋습니다.
— mna

1
@PuerkitoBio-IE8 이하에서는 여전히 $event.preventDefault()IE 세금이 필요하다는 것을 확인할 수 있습니다 .
— Scotty.NET

4
$ event를 컨트롤러에 전달한다는 것은 컨트롤러에서 DOM을 참조한다는 것을 의미합니다. 이는 뷰와 컨트롤러를 결합한 것을 의미합니다. 평가 된 표현식에서 $ event 메소드를 직접 호출 할 수 있습니다. ng-click="do(); $event.preventDefault()예를 들어, 아래의 @Chris의 답변이 올바른 것이기 때문에 필요하지는 않습니다. $event.stopPropagation()그러나 ngClick이 중첩되어 있고을 호출하려는 상황에있는 사람들에게 도움이 될 수 있습니다 .
— Ben Lesh

2
마지막으로 SEO 친화적 인 솔루션. ng-view-joelsaupe.com/programming / ... 을 다시로드하지 않고 브라우저 URL을 업데이트 할 수도 있습니다. 이렇게하면 뷰를 다시로드하지 않지만 새 탭에서 열 수 있고 검색 엔진이이를 따라갈 수있는 링크가 있습니다. 예!
— Tom

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 자체 세트를 제공합니다.
— Neil

3
추가 이점 -이것은 중요한 경우 IE8 이하 에서도 작동 합니다.
— Scotty.NET

1
나는 받고있다 Error: $ is not defined. 내가 무엇을 놓치고 있습니까?
— Bilal Mirza

7
나는 노력했다 angular.element(element).bind('click', function(event){...});. 효과가있었습니다. 참조 : jQLite
— Bilal Mirza

3
만약 당신이 저에게 물어 보면 그와 같은 간단한 것에 대한 지시어가 약간 부풀어 오른 것 같습니다 ... Chris에게 아래의 대답을 확인하십시오
— Wilt

54

Renaud는 훌륭한 솔루션을 제공했지만

<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
이것이 가장 좋은 해결책입니다. 물론 $ event 객체를 스코프 함수로 전달할 수도 있습니다. ng-click = "myFunction ($ event, otherParams), 그런 다음 myFunction의 $ event.preventDefault ()와 같이 직접 지시어를 롤링하는 것은 너무 과도합니다
— Charlie Martin

34

내가 찾은 가장 쉬운 해결책은 다음과 같습니다.

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

이것은 가장 쉬운 방법 일뿐만 아니라 다른 솔루션에서 제안한 것처럼 이벤트를 컨트롤러와 연결하지도 않습니다. 컨트롤러에 이벤트를 연결하는 것은 테스트를 훨씬 어렵게하기 때문에 모든 비용을 피해야합니다.
— jornare

11

따라서 @Chris는이 답변을 통해 여전히 가장 "올바른"답변을 가지고 있다고 생각하지만 한 가지 문제가 있지만 "포인터"를 표시하지 않습니다 ....

따라서 커서를 추가하지 않고도이 문제를 해결하는 두 가지 방법이 있습니다. 포인터 스타일 :

  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) 에 설명 된 다른 이점이 있습니다 . 그 링크에는 "최소한의 자바 스크립트"에 대한 토론도 있습니다.이 링크는 매우 최근에 이루어졌으며 반드시 각도 응용 프로그램에 직접 적용되지는 않습니다.


2
이것이 왜 다운 보트입니까? 또한 Chris의 답변에 포인터가 표시되지 않는 것으로 나타났습니다.
— Wim Deblauwe

2
javascript : void (0)은 경로를 잘못 구성하면 경로에서 작동 할 수있는 #보다 훨씬 낫습니다. +1
— Shay Elkayam

2
나는 이것에 대한 답을 쓰려고했다. 당신은 또한 할 수 있습니다javascript:;
— Adrian

10

다음과 같이 할 수 있습니다

1. hrefanchor ( a) 태그 에서 속성 제거

2. CSS의 포인터 커서를 클릭 요소로 설정하십시오.

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

9

HTML

여기 순수한 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()
}

7

아직 볼 수없는이 옵션을 사용해보십시오 :

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

6

웹앱을 제작하고 있는데 왜 링크가 필요합니까?

앵커를 버튼으로 바꾸십시오!

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

2
webapps에 앵커를 가질 수 없기 때문에?
— Robin van Baalen

1
나는 대부분의 웹 응용 프로그램이 웹 사이트와 같은 상대 링크를 필요로하지 않는다는 점을 언급하고 있었고, 종종 앵커 링크를 자바 스크립트 트리거로 사용하고 페이지에 링크하지 않습니다. 따라서 기본 스타일이 재설정 된 버튼은 의미가 맞지 않으면 의미 론적으로 정확합니다.
— sidonaldson

3
@sidonaldson 사실, 오늘날 많은 웹앱은 링크에 크게 의존합니다. angularjs 라우팅을보십시오.
— Robert

1
@Robert 예. 그러나 기본 제공 라우팅을 사용하면 기본값을 방지 할 필요가 없습니다. 나는 포스터가 그가 루트가 아닌 링크에 대해 이야기하고있는 앵커 링크를 취소하고 싶어한다고 가정합니다. 예를 들어 모달 등 시작
— sidonaldson

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는 기본값 방지를 처리합니다!

전체적으로이 기본 방지 기능이 혼란 스럽기 때문에 Angular가 기본을 방지하는 시간과 위치를 보여주는 JSFiddle 을 만들었습니다 .

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 속성 (또는 "#")을 사용할 수 없지만 이벤트가 필요하기 때문에 위의 코드가 작동하지 않았습니다 ( 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>

2

tennisgent의 답변에서 차용. 모든 링크에 추가하기 위해 사용자 지정 지시문을 만들 필요는 없습니다. 그러나 IE8에서 그의 일을 할 수 없었습니다. 마지막으로 나를 위해 일한 것이 있습니다 (각도 1.0.6 사용).

'바인드'를 사용하면 각도로 제공되는 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전파를 원하지만 기본 동작은 원하지 않습니다. 이 스 니펫은 권장 되지 않습니다.
— Robin van Baalen

2

각도 부트 스트랩 드롭 다운에 앵커를 사용할 때도 동일한 문제가 발생했습니다. 원하지 않는 부작용을 피하는 유일한 해결책 (예 : preventDefault () 사용으로 인해 드롭 다운이 닫히지 않음)은 다음을 사용하는 것입니다.

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

2

href로 가고 싶지 않다면 마크 업을 변경하고 의미 상 앵커 또는 링크가 아니기 때문에 앵커 태그가 아닌 버튼을 사용해야합니다. 반대로 검사를 한 다음 리디렉션하는 버튼이 있으면 버튼은 아닌 링크 / 앵커 태그 여야합니다. SEO 목적뿐만 아니라 테스트도 여기 [테스트 스위트 삽입].

변경 사항을 저장하라는 메시지와 같이 조건부로만 리디렉션하거나 더티 상태를 확인하려는 링크의 경우 ng-click = "someFunction ($ event)"및 validationError preventDefault 및 / 또는 stopPropagation에 someFunction을 사용해야합니다.

또한 당신이해야한다는 것을 의미 할 수 없기 때문에 . javascript : void (0)는 하루 전에 잘 작동했지만 악의적 인 해커 / 크래커 브라우저로 인해 href 내에서 javascript를 사용하는 앱 / 사이트에 플래그가 지정되었습니다.

2010 년 이후 2016 년 이후로 버튼처럼 작동하는 링크를 사용해야하는 이유는 없습니다. 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 속성을 완전히 것입니다.

요소 지시문 (앵귤러 코어의 일부)에 대한 소스 코드 를 보면 a29-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

목표를 달성하기 위해 $ location의 Html5Mode 내에서 URL 리디렉션을 비활성화 할 수 있습니다. 페이지에 사용 된 특정 컨트롤러 내에서 정의 할 수 있습니다. 이 같은:

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클릭 목적으로 악용하는 것은 끔찍한 관행 입니다. @ tennisgent 's answer- href정의 되지 않은 앵커로 이동하십시오 .
— Robin van Baalen

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
— Terence Bandoian

1
언제 클릭 할 수 있습니까? <span> Hello </ span>를 수행하는 경우 사양에 따르면 <span>은 <a> 또는 <button>과 같은 클릭 가능한 요소 내부에서 사용할 수 있습니다. 그러나 다시 모든 인라인 블록 요소 (img, span 등)를 클릭 방식으로 클릭 할 수 있습니다. 범위 자체는 클릭 할 수 없습니다.
— Robin van Baalen

1
@RobinvanBaalen 위의 링크를 참조하십시오. span 요소의 onclick 속성은 HTML 4.01 이상부터 정의되었습니다.
— Terence Bandoian

1
이벤트 핸들러를 추가해도 범위가 작동하지 않는다고 말한 적이 없습니다. 자바 스크립트 이벤트 핸들러를 사용하여 span, div, section, ul, li 등과 같은 클릭 할 수없는 요소를 클릭 가능하게 만드는 것은 나쁜 습관이라고 말했습니다. 의미에 관한 모든 것입니다. HTML의 의미는 적절한 요소를 사용하여 페이지 의미와 구조에 내용을 제공하는 방법입니다.
— Robin van Baalen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.