Yuvalanmış ng-click çağrıları arasındaki olay yayılımını iptal etmenin en iyi yolu nedir?


180

İşte bir örnek. Diyelim ki birçok site gibi bir resim yer paylaşımım var. Dolayısıyla, bir küçük resmi tıkladığınızda, tüm pencerenizde siyah bir kaplama görünür ve görüntünün daha büyük bir sürümü ortada bulunur. Siyah kaplamayı tıklatmak onu kapatır; görüntüye tıklandığında sonraki görüntüyü gösteren bir işlev çağrılır.

Html:

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage()"/>
</div>

Javascript:

function OverlayCtrl($scope) {
    $scope.hideOverlay = function() {
        // Some code to hdie the overlay
    }
    $scope.nextImage = function() {
        // Some code to find and display the next image
    }
}

Görüntüyü tıklatıp hem eğer sorun, bu kurulumla ilgili olduğunu nextImage()ve hideOverlay()denir. Ama istediğim sadece nextImage()çağrılmak.

nextImage()Bu gibi fonksiyondaki olayı yakalayıp iptal edebileceğinizi biliyorum :

if (window.event) {
    window.event.stopPropagation();
}

... Ama bunu bu pasaj ile bindirme içindeki öğelerdeki tüm işlevlerin önekini eklememi gerektirmeyecek daha iyi bir AngularJS yolu olup olmadığını bilmek istiyorum.


1
return falsefonksiyonun sonunda
Jonathan de

1
İnanıyorum ki bunu yapmanın yolu bu onclickdeğil ng-click.
Michael Scheper

Yanıtlar:


193

@JosephSilber ne dedi, ya da $ event nesnesini ng-clickgeri aramaya aktar ve içindeki yayılımı durdur:

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
  <img src="http://some_src" ng-click="nextImage($event)"/>
</div>
$scope.nextImage = function($event) {
  $event.stopPropagation();
  // Some code to find and display the next image
}

8
$ event.preventDefault () kullanın; v> 1.5
KoolKabin

3
@KoolKabin Angular 1.5.8 ve $ event.stopPropagation () kullanıyorum, hala iyi çalışıyor. $ event.preventDefault () ancak çalışmıyor
HammerNL

1
Tuhaf, çünkü tam tersi bir durumum var. stopPropagation artık çalışmıyor, ancak preventDefault () çalışıyor. Tek fark, ng-click üzerinde doğrudan aradım. <tr ng-click = "ctr.foo (); $ event.preventDefault ()"> ..... </tr>
MilitelloVinx

171

Kullanım $event.stopPropagation():

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage(); $event.stopPropagation()" />
</div>

İşte bir demo: http://plnkr.co/edit/3Pp3NFbGxy30srl8OBmQ?p=preview


Ben olsun ReferenceError: $event is not definedkonsolda.
cilphex

Evet, öyle ... sıfırdan ayrı bir basit sürüm yazdığımda da işe yarıyor. Geliştirme kodumda neyin işe yaramayacağını anlamaya çalışıyorum. Dunno: \
cilphex

@cilphex - Angular'ın güncel bir sürümünü mü kullanıyorsunuz?
Joseph Silber

Evet - sorunu buldum. Test yaparken, çalışmadığı $event.stopPropagation()bir yere koymaya çalıştım . Kaldırmayı unuttum. Bu yüzden işe yaradığı yere koyduğumda bile, işe yaramadığı ikinci kez deniyordu. İşlevsel olmayan kopyadan kurtuldum ve başarılı oldu. Yardımınız için teşekkürler.
cilphex

101

Bunun için bir yönerge kullanma fikrini seviyorum:

.directive('stopEvent', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            element.bind('click', function (e) {
                e.stopPropagation();
            });
        }
    };
 });

Sonra aşağıdaki gibi yönergeyi kullanın:

<div ng-controller="OverlayCtrl" class="overlay" ng-click="hideOverlay()">
    <img src="http://some_src" ng-click="nextImage()" stop-event/>
</div>

İsterseniz, bu çözümü farklı bir sorunun cevabı gibi daha genel hale getirebilirsiniz: https://stackoverflow.com/a/14547223/347216


2
Öğeniz dinamik olarak DOM'dan eklenirse / kaldırılırsa, işleyiciyi bağlayabilmeniz için öğenizi '$ destroy' etkinliği için izlemeyi unutmayın. Örneğin, element.on ('$ destroy', function () {/ * burada bağlantıyı kaldırma * /});
broc.seib

olan stop-eventbir html niteliği? Mozilla Geliştirici Ağı'nda veya başka bir yerde bulamadım.
Ehtesh Choudhury

3
@EhteshChoudhury - "stop-event" yukarıdaki JS snippet'inde oluşturduğum yeni yönerge. Direktifleri beyan etme ve kullanma hakkında daha fazla bilgi için: docs.angularjs.org/guide/directive
David Ipsen

Güzel çözüm! Aslında angular-eat-eventbenzer şekilde çalışan bower yönergesini kaydettim !
gion_13

çalışmıyor gibi görünüyor, ng-click yönergeden önce değerlendirir. bu yüzden direktifin yürütülmesini engelleyebilirim ama tam tersini yapamam.
Rafael

31

Bazen, sadece bunu yapmak en mantıklı olabilir:

<widget ng-click="myClickHandler(); $event.stopPropagation()"/>

Bu şekilde yapmayı seçtim çünkü myClickHandler()kullanıldığı birçok yerde olay yayılımını durdurmak istemedim .

Elbette, işleyici işlevine bir boole parametresi ekleyebilirdim, ancak stopPropagation()sadece çok daha anlamlı true.


2
Ben her zaman bu sürümü sevdim, elemanın yuvalama ben çağırıyorum fonksiyonu ile ilgili olmamalıdır görünüyor
mcfedr

$event.stopPropagation()İç unsurlara eklemek zorunda kaldım .
Kishor Pawar

@KishorPawar: Neden? Cevapta yaptığım yol işinize yaramadı mı? Olmasaydı, bunun Açısal çalışma biçimindeki bir değişiklik mi yoksa kodunuzdaki bir sorun mu olduğunu öğrenmek bizim için iyi olurdu.
Michael Scheper

@MichaelScheper Ben sahip am checkboxsarılı divelemanı. Benim div12 sütun alıyor ve checkbox3 sütun alıyor. Bir işlevi çağırmak istedim Atıklamasıyla üzerinde divve işlev Btıklamasıyla üzerinde checkbox. Ben tıklarken checkboxher iki fonksiyon da çağrılıyordu. Ben eklediğinizde ng-click="$event.stopPropagation()"için checkbox, sadece işlevi var Bçağrılır.
Kishor Pawar

@KishorPawar: Ah. Evet, bunu beklerdim ve asıl önemli olan stopPropagation()olayın ana öğelere yayılmasını durdurmaktır. Ben aradığınız emin nasıl değilim Biçeri specififed değil çünkü ng-click, ama cevap noktası Bunu olmasıdır: <checkbox ng-click="B(); $event.stopPropagation()">. Bu stopPropagation()işlevi içine dahil etmek zorunda değilsiniz B.
Michael Scheper

7

Bu benim için çalışıyor:

<a href="" ng-click="doSomething($event)">Action</a>

this.doSomething = function($event) {
  $event.stopPropagation();
  $event.preventDefault();
};

Fare tıklamalarını Ctrl tuşuna basarak veya Ctrl tuşuna basmadan işlemek istedim. Kullanıcı Ctrl tuşunu basılı tutarak çeşitli öğeleri tıklattığında tarayıcıdaki HTML öğelerinin seçimini (ve benim durumumda IE 11) durdurmak için ng-mousedown olayını kullanmak ve $ event aracılığıyla varsayılan davranışı iptal etmek zorunda kaldım .preventDefault ()
pholpar

4

Durdurma yayılımını tüm bağlantılara eklemek istemiyorsanız bu da işe yarar. Biraz daha ölçeklenebilir.

$scope.hideOverlay( $event ){

   // only hide the overlay if we click on the actual div
   if( $event.target.className.indexOf('overlay') ) 
      // hide overlay logic

}

2
Bu çözüm sağlanan örnek için işe yarar (bu harika!), Ancak dış div href / ng-tıklamadan önce n veya daha fazla iç içe öğeye sahip olduğunda çalışmaz. Daha sonra hideOverlay () geri çağırma çağrıldığında hedef, ng-tıklama yönergesine sahip en dıştaki öğeden değil, iç içe geçmiş öğelerden biridir. İç içe öğeleri düşünmek için, ebeveynleri almak için jquery kullanabilir ve ilk tıklanabilir (a, ng-click vb.) Ebeveynin kaplama sınıfına sahip olup olmadığını görebilir, ancak bu biraz hantal görünüyor ...
Amir

console.log ("potatooverlay" .indexOf ("yer paylaşımı")! = -1); console.log (/ \ boverlay b \ / g.test ( "potatooverlay"));

açısal yapmanıza izin verir event.target.classList.indexOf('overlay') Ve div diğer divlarda yuvalanmış olsa bile bu hile iyi çalışıyor
deltree

0

Şablonunuzun üst öğesine ng-click = "$ event.stopPropagation" eklerseniz, stopPropogation ağacı oluştururken yakalanır, böylece tüm şablonunuz için yalnızca bir kez yazmanız gerekir.


0

ng-clickÜstüne ng-clickolay yayılımının varsayılan davranışını değiştiren ve durduran başka bir yönerge kaydedebilirsiniz . Bu şekilde $event.stopPropagationelle eklemek zorunda kalmazsınız .

app.directive('ngClick', function() {
    return {
        restrict: 'A',
        compile: function($element, attr) {
            return function(scope, element, attr) {
                element.on('click', function(event) {
                    event.stopPropagation();
                });
            };
        }
    }
});

0
<div ng-click="methodName(event)"></div>

IN denetleyici kullanımı

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

İlk bunu yapmak için yöntemde olay gönder
Dinesh Jain

Cevabınız 4 yıl önce kabul
edilene
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.