क्लिक इवेंट पहले से ही बाध्य है या नहीं, इसकी जांच कैसे करें - JQuery


130

मैं एक बटन के साथ एक क्लिक घटना बांध रहा हूँ:

$('#myButton').bind('click',  onButtonClicked);

एक परिदृश्य में, इसे कई बार कहा जा रहा है, इसलिए जब मैं ए trigger हूं मुझे कई ऐजैक्स कॉल दिखाई देते हैं जिन्हें मैं रोकना चाहता हूं।

मैं bindही कैसे करूं अगर इसकी सीमा पहले न हो।


1
यार, मुझे लगता है कि + कोनराड गेरस में सबसे सुरक्षित एवरर ( stackoverflow.com/a/6930078/842768 ) है, अपने स्वीकृत उत्तर को बदलने पर विचार करें। चीयर्स! अद्यतन: चेक + हर्बर्ट पीटर्स की टिप्पणी के रूप में अच्छी तरह से! यही सबसे अच्छा तरीका है।
giovannipds

वर्तमान मानकों के लिए, नीचे @A Morel का उत्तर देखें ( stackoverflow.com/a/50097988/1163705 )। कम कोडिंग और सभी अनुमान कार्य, एल्गोरिदम और / या समीकरण से बाहर मौजूदा तत्वों की खोज में ले जाता है।
Xandor

जवाबों:


117

24 अगस्त '12 को अपडेट करें : jQuery 1.8 में, तत्व के ईवेंट का उपयोग करना संभव नहीं है .data('events')। ( विवरण के लिए इस बग को देखें।) jQuery._data(elem, 'events')एक आंतरिक डेटा संरचना के साथ एक ही डेटा तक पहुंचना संभव है , जो कि अनिर्दिष्ट है और इसलिए स्थिर रहने के लिए 100% गारंटी नहीं है। हालांकि, यह एक समस्या नहीं होनी चाहिए, और ऊपर दिए गए प्लगइन कोड की प्रासंगिक रेखा को निम्न में बदला जा सकता है:

var data = jQuery._data(this[0], 'events')[type];

jQuery की घटनाओं को डेटा ऑब्जेक्ट में संग्रहीत किया जाता है events, जिसे आप इसमें खोज सकते हैं:

var button = $('#myButton');
if (-1 !== $.inArray(onButtonClicked, button.data('events').click)) {
    button.click(onButtonClicked);
}

यह निश्चित रूप से सबसे अच्छा होगा, यदि आप अपने आवेदन को संरचित कर सकते हैं तो यह कोड केवल एक बार कॉल किया जाएगा।


यह एक प्लगइन में समझाया जा सकता है:

$.fn.isBound = function(type, fn) {
    var data = this.data('events')[type];

    if (data === undefined || data.length === 0) {
        return false;
    }

    return (-1 !== $.inArray(fn, data));
};

आप तब कॉल कर सकते हैं:

var button = $('#myButton');
if (!button.isBound('click', onButtonClicked)) {
    button.click(onButtonClicked);
}

10
संपादित करने के लिए +1। आज इस पोस्ट को पढ़ना और मैं 1.8 का उपयोग कर रहा हूं। धन्यवाद।
गिगी २ एम ०२

2
संपादन के लिए धन्यवाद। क्या यह केवल बटनों के लिए है या मैं इसके लिए भी इसका उपयोग कर सकता हूं <a>? क्योंकि जब मैं कोशिश करता हूं तो यह jQuery._data()निम्नलिखित त्रुटि पर कहता हैTypeError: a is undefined
होउमैन

मैं लाइन var data = jQuery._data(this[0], 'events')[type];को एक पकड़ने की कोशिश में लपेटूंगा और झूठ को पकड़ने में वापस आऊंगा। यदि कोई कॉल [प्रकार] के लिए [0] से जुड़ी नहीं है, तो "अपरिभाषित या अशक्त संदर्भ की संपत्ति पर क्लिक करने में असमर्थ" के कुछ बदलाव का कारण बनेगा और जाहिर है कि आपको यह भी बताता है कि आपको क्या जानना चाहिए।
रोबब वंडवीर

मुझे यकीन नहीं है कि _data ऑब्जेक्ट jQuery 2.0.3 में बदल गया है, लेकिन मैं इसके लिए $ .inArray का उपयोग नहीं कर सका। जिस फ़ंक्शन की आप तुलना करना चाहते हैं, वह "हैंडलर" नामक प्रत्येक डेटा आइटम की एक संपत्ति में है। मैंने इसे कथन के लिए एक सरल का उपयोग करने के लिए संशोधित किया और स्ट्रिंग तुल्यता के लिए जाँच की, जो मैं मान रहा हूँ कि मैंने किया है। for (var i = 0; i < data.length; i++) { if (data[i].handler.toString() === fn.toString()) { return true; } }
रॉब वंडवीर

अपने अपडेट को स्थानांतरित क्यों न करें / शीर्ष पर संपादित करें? ... यह वास्तविक सही उत्तर है।
डॉन चीडल

179

एक और तरीका - सीएसएस वर्ग और फिल्टर के साथ ऐसे बटन को चिह्नित करें:

$('#myButton:not(.bound)').addClass('bound').bind('click',  onButtonClicked);

हाल ही में jQuery के संस्करणों के bindसाथ बदलें on:

$('#myButton:not(.bound)').addClass('bound').on('click',  onButtonClicked);

4
अति उत्कृष्ट! धन्यवाद कोनराड, यह मीठा स्थान हिट करता है। मुझे इस तरह से सुरुचिपूर्ण और सरल दृष्टिकोण पसंद हैं। मुझे पूरा यकीन है कि यह अधिक अच्छा प्रदर्शन करने वाला है, साथ ही हर एक तत्व (जिसमें पहले से ही इवेंट हैंडलर संलग्न हैं) को हर एक की तुलना में कुछ बड़ी घटनाओं की बाल्टी में पूर्ण खोज करने की आवश्यकता नहीं है। मेरे कार्यान्वयन में मैंने अतिरिक्त सहायक वर्ग को "क्लिक-बाउंड" नाम दिया, जो मुझे लगता है कि एक अधिक अनुरक्षण विकल्प है: $ ("। सूची-आइटम: नहीं (.click- बाध्य)")। addClass ("क्लिक-बाउंड") ;
निकोलस पीटरसन

1
जैसा कि स्वीकृत उत्तर में कहा गया था: "यह सबसे अच्छा होगा, निश्चित रूप से, यदि आप अपने आवेदन की संरचना कर सकते हैं, तो यह कोड केवल एक बार कॉल किया जाएगा।" यह पूरा करता है।
जेफ डेगे

मेरी स्थिति में +1, ऑफ / ऑन और बाइंड / अनबंड ने कई कॉल्स को रोका। यह वह समाधान था जिसने काम किया।
Jay

2
यह प्रदर्शन के लिए बेहतर समाधान है क्योंकि कोड सीएसएस वर्ग की उपस्थिति और पहले से मौजूद स्लिप बाइंडिंग की उपस्थिति की जांच कर सकता है। अन्य समाधान अधिक ओवरहेड के साथ एक unbind-then-rebind प्रक्रिया को निष्पादित करते हैं (कम से कम fr4om जो मैं बता सकता हूं)।
फिल निकोलस

1
2 मुद्दे। (जब इसका उपयोग प्लग-इन में किया जा सकता है, तो यह कई तत्वों के लिए बाध्य हो सकता है) विंडो ऑब्जेक्ट के आकार परिवर्तन के लिए बाध्यकारी होने पर काम नहीं करेगा। AddClass के बजाय डेटा ('बाउंड', 1) का उपयोग करें ('बाउंड') एक और दृष्टिकोण है जो काम करता है। घटना को नष्ट करते समय ऐसा हो सकता है जबकि अन्य उदाहरण इस पर निर्भर करते हैं। इसलिए यह जांचना कि क्या अन्य उदाहरण अभी भी उपयोग में हैं, उचित है।
हर्बर्ट पीटर्स

59

यदि jQuery 1.7+ का उपयोग कर रहे हैं:

आप offपहले कॉल कर सकते हैं on:

$('#myButton').off('click', onButtonClicked) // remove handler
              .on('click', onButtonClicked); // add handler

अगर नहीं:

आप इसे पहली घटना को अनबाइंड कर सकते हैं:

$('#myButton').unbind('click', onButtonClicked) //remove handler
              .bind('click', onButtonClicked);  //add handler

1
यह ठीक एक सुंदर समाधान नहीं है, लेकिन यह केवल एक हैंडलर अनबाइंडिंग द्वारा सुधार किया जा जाएगा: .unbind('click', onButtonClicked)मैनुअल देखें
lonesomeday

16
आप वास्तव में अपने हैंडलर को नामांकित कर सकते हैं जैसे ही आप उन्हें जोड़ते हैं, तो unbinding बहुत सरल हो जाता है। $(sel).unbind("click.myNamespace");
मार्क

@lonesomeday 'unbind' का उपयोग करके आपका उदाहरण कुछ अलग दिखाने के लिए था? .Unbind प्रभावी रूप से .off के समान नहीं है इसलिए आपको लिखना होगा$('#myButton').unbind('click', onButtonClicked).bind('click', onButtonClicked);
जिम

1
@Jim आप देखेंगे कि मेरी टिप्पणी के तीन साल बाद प्रश्न संपादित किया गया था! (और मेरी टिप्पणी के तुरंत बाद के मिनटों में भी। मैं जिस सामग्री पर टिप्पणी कर रहा था, वह अब मौजूद नहीं है, यही वजह है कि यह शायद ज्यादा समझ में नहीं आता है।)
lonesomeday

@lonesomeday हम्म मुझे यकीन नहीं है कि इसे क्यों संपादित किया गया था, क्या आपको लगता है कि मुझे रोलबैक करना चाहिए?
नफ्ताली उर्फ ​​नील

8

मेरे द्वारा देखे जाने का सबसे अच्छा तरीका लाइव का उपयोग करना है () या प्रतिनिधि () माता-पिता की घटना को पकड़ने के लिए और प्रत्येक बच्चे के तत्व में नहीं।

यदि आपका बटन एक # तत्व के अंदर है, तो आप प्रतिस्थापित कर सकते हैं:

$('#myButton').bind('click', onButtonClicked);

द्वारा

$('#parent').delegate('#myButton', 'click', onButtonClicked);

भले ही यह कोड निष्पादित होने पर #myButton अभी तक मौजूद नहीं है।


2
पदावनत विधियाँ
नोब्स

8

मैंने एक बहुत छोटा प्लगइन लिखा है जिसे "एक बार" कहा जाता है जो ऐसा करता है। तत्व में छूट और पर।

$.fn.once = function(a, b) {
    return this.each(function() {
        $(this).off(a).on(a,b);
    });
};

और बस:

$(element).once('click', function(){
});

9
.one () पहले निष्पादन के बाद हैंडलर को छोड़ देगा।
रोडोल्फो जोर्ज नेमर नोगीरा

3
यहाँ "एक बार" एक बार हैंडलर संलग्न करने के लिए है। jquery में "एक" एक बार नहीं जुड़ने पर चलने के लिए है।
शिशिर अरोरा

1
मुझे पता है कि मैं इस तथ्य के बाद आ रहा हूं, लेकिन offदिए गए प्रकार के लिए सभी हैंडलर को नहीं हटाता? मतलब अगर एक अलग क्लिक हैंडलर असंबंधित था, लेकिन एक ही आइटम पर, तो क्या वह भी नहीं निकाला जाएगा?
Xandor

सिर्फ घटना पर एक नाम स्थान का उपयोग करें ताकि यह सभी हैंडलर को न गिराए: 'keypup.test123'
सिमेंटिकेन

6

इसका उपयोग क्यों नहीं करते

unbind() इससे पहले bind()

$('#myButton').unbind().bind('click',  onButtonClicked);

1
$('#myButton').off().on('click', onButtonClicked);मेरे लिए भी काम करता है।
वीरकरन सेरेरुन्गुरुंगुल

मेरे लिए काम करता है ... gr8 solution
imdadhusen

सुंदर। मेरे लिए पूरी तरह से एक बटन के लिए काम करता है जो पहले से ही बाध्य था।
सीनाबेदेन

3

यहाँ मेरा संस्करण है:

Utils.eventBoundToFunction = function (element, eventType, fCallback) {
    if (!element || !element.data('events') || !element.data('events')[eventType] || !fCallback) {
        return false;
    }

    for (runner in element.data('events')[eventType]) {
        if (element.data('events')[eventType][runner].handler == fCallback) {
            return true;
        }

    }

    return false;
};

उपयोग:

Utils.eventBoundToFunction(okButton, 'click', handleOkButtonFunction)

2

@ कोनराड-गार्स उत्तर के आधार पर, लेकिन उपयोग करना data, क्योंकि मेरा मानना ​​है कि classइसका इस्तेमाल ज्यादातर स्टाइल के लिए किया जाना चाहिए।

if (!el.data("bound")) {
  el.data("bound", true);
  el.on("event", function(e) { ... });
}

2

चेक / बाइंड / अनबाइंड से बचने के लिए, आप अपना दृष्टिकोण बदल सकते हैं! आप Jquery .on () का उपयोग क्यों नहीं करते?

Jquery 1.7 के बाद से .live (), .delegate () को हटा दिया गया है, अब आप उपयोग कर सकते हैं ()।

सभी तत्वों के लिए एक घटना हैंडलर संलग्न करें जो वर्तमान चयनकर्ता से मेल खाता है, अभी और भविष्य में

इसका मतलब है कि आप किसी घटना को किसी ऐसे मूल तत्व से जोड़ सकते हैं जो अभी भी विद्यमान है और बच्चों के तत्वों को संलग्न करता है चाहे वे मौजूद हों या नहीं!

जब आप इस तरह .on () का उपयोग करते हैं:

$('#Parent').on('click', '#myButton'  onButtonClicked);

यदि आप पेरेंट पर ईवेंट क्लिक करते हैं और यह मौजूद है तो बच्चे '#myButton' को खोजें ...

इसलिए जब आप बच्चे के तत्व को हटाते हैं या जोड़ते हैं, तो आपको इस बारे में चिंता करने की ज़रूरत नहीं है कि क्या घटना को जोड़ना या निकालना है।


यह वर्तमान मानकों के लिए यहाँ पर सबसे अच्छा जवाब है। मुझे नहीं लगता कि बच्चे को देखने के लिए माता-पिता पर हैंडलर स्थापित करने की यह सुविधा अच्छी तरह से विज्ञापित की गई है, बल्कि एक सुंदर समाधान है। मुझे कई बार एक घटना में आग लग गई थी और हर बार जितनी बार फायरिंग हुई, कुल राशि बढ़ती गई। इस एकल पंक्ति ने पूरी चाल चली और .offजिसके बिना मुझे विश्वास था कि इस प्रक्रिया में असंबद्ध हैंडलर को हटा दिया जाएगा।
Xandor


0
if ($("#btn").data('events') != undefined && $("#btn").data('events').click != undefined) {
    //do nothing as the click event is already there
} else {
    $("#btn").click(function (e) {
        alert('test');
    });
}

0

जून 2019 तक, मैंने फ़ंक्शन को अपडेट कर दिया है (और यह मेरी ज़रूरत के लिए काम कर रहा है)

$.fn.isBound = function (type) {
    var data = $._data($(this)[0], 'events');

    if (data[type] === undefined || data.length === 0) {
        return false;
    }
    return true;
};

-2

JQuery के पास है समाधान है :

$( "#foo" ).one( "click", function() {
  alert( "This will be displayed only once." );
}); 

बराबर:

$( "#foo" ).on( "click", function( event ) {
  alert( "This will be displayed only once." );
  $( this ).off( event );
});

1
आपका उत्तर प्रश्न से संबंधित नहीं है। प्रश्न केवल एक बार तत्व की घटना के लिए बाध्यकारी कार्य के बारे में है।
मिकाल ज़्लावेस्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.