कोणीयजेएस में एक प्रसारण कार्यक्रम के लिए सदस्यता समाप्त कैसे करें। $ पर पंजीकृत फ़ंक्शन को कैसे निकालें


278

मैंने $ $ फ़ंक्शन का उपयोग करके अपने श्रोता को $ प्रसारण कार्यक्रम में पंजीकृत किया है

$scope.$on("onViewUpdated", this.callMe);

और मैं इस श्रोता को एक विशेष व्यावसायिक नियम के आधार पर पंजीकृत करना चाहता हूं। लेकिन मेरी समस्या यह है कि एक बार पंजीकृत होने के बाद मैं इसे पंजीकृत नहीं कर पा रहा हूं।

क्या किसी विशेष श्रोता को पंजीकृत करने के लिए AngularJS में कोई विधि है? इस पद्धति पर $ की तरह एक विधि इस घटना को पंजीकृत करती है, $ बंद हो सकती है। इतना है कि व्यापार तर्क के आधार पर मैं कह सकता हूँ

 $scope.$off("onViewUpdated", this.callMe);

और जब किसी ने "onViewUpdated" घटना प्रसारित की तो यह फंक्शन बंद हो जाएगा।

धन्यवाद

संपादित करें : मैं दूसरे समारोह से श्रोता को पंजीकृत करना चाहता हूं। वह फ़ंक्शन नहीं जहां मैं इसे पंजीकृत करता हूं।


2
किसी को भी आश्चर्य हो रहा है, लौटाया गया कार्य यहाँ
फागनर ब्रैक

जवाबों:


477

आपको दिए गए फ़ंक्शन को संग्रहीत करने और इवेंट से सदस्यता समाप्त करने के लिए कॉल करने की आवश्यकता है।

var deregisterListener = $scope.$on("onViewUpdated", callMe);
deregisterListener (); // this will deregister that listener

यह स्रोत कोड में पाया जाता है :) कम से कम 1.0.4 में। मैं अभी पूरा कोड पोस्ट करूंगा क्योंकि यह छोटा है

/**
  * @param {string} name Event name to listen on.
  * @param {function(event)} listener Function to call when the event is emitted.
  * @returns {function()} Returns a deregistration function for this listener.
  */
$on: function(name, listener) {
    var namedListeners = this.$$listeners[name];
    if (!namedListeners) {
      this.$$listeners[name] = namedListeners = [];
    }
    namedListeners.push(listener);

    return function() {
      namedListeners[indexOf(namedListeners, listener)] = null;
    };
},

इसके अलावा, डॉक्स देखें ।


हाँ। डिबेट कोड को डिबग करने के बाद मुझे पता चला कि एक $ $ श्रोता है, जिसमें सारी घटनाएँ हैं और मैंने अपना $ फंक्शन बनाया है। धन्यवाद
Hitesh.Aneja

वास्तविक उपयोग मामला क्या है जो आप डेरेगिस्टरिंग के प्रदान किए गए कोणीय तरीके का उपयोग नहीं कर सकते हैं? क्या दूसरे स्कोप में किए गए डेजिगिस्टरिंग को उस स्कोप से नहीं जोड़ा जाता है जो श्रोता को बनाता है?
लिवियू टी।

1
हाँ, मैंने वास्तव में अपना उत्तर हटा दिया है क्योंकि मैं लोगों को भ्रमित नहीं करना चाहता। ऐसा करने का यह उचित तरीका है।
बेन लेश

3
@Liviu: जो बढ़ते अनुप्रयोग के साथ सिरदर्द बन जाएगा। यह न केवल इस घटना है, बल्कि अन्य ईवेंट भी हैं और जरूरी नहीं कि मैं हमेशा एक ही स्कोप फंक्शन में डे-रजिस्टर करूं। ऐसे मामले हो सकते हैं जब मैं एक फ़ंक्शन को कॉल कर रहा हूं जो इस श्रोता को पंजीकृत कर रहा है, लेकिन दूसरे कॉल पर श्रोता को डी-रजिस्टर कर रहा है, यहां तक ​​कि उन मामलों को जब तक मैं अपने दायरे से बाहर स्टोर नहीं करता, तब तक मुझे संदर्भ नहीं मिलेगा। इसलिए मेरे वर्तमान कार्यान्वयन के लिए मेरा कार्यान्वयन मेरे लिए व्यवहार्य समाधान दिखता है। लेकिन निश्चित रूप से उन कारणों को जानना चाहेंगे कि एंगुलरजेएस ने इस तरह से ऐसा क्यों किया।
हितेश.अनेजा

2
मुझे लगता है कि एंगुलर ने इसे इस तरह से किया क्योंकि फ़ंक्शन पर $ के लिए तर्क के रूप में बहुत समय इनलाइन अनाम फ़ंक्शन का उपयोग किया जाता है। $ स्कोप को कॉल करने के लिए। $ बंद (प्रकार, फ़ंक्शन) हमें अनाम फ़ंक्शन का संदर्भ रखना होगा। यह सिर्फ एक अलग तरीके से सोच रहा है कि कोई व्यक्ति सामान्य रूप से एक्शनस्क्रिप्ट या जावा में
ऑब्जर्वेबल

60

अधिकांश उत्तरों को देखते हुए, वे अत्यधिक जटिल लगते हैं। कोणीय को अपंजीकृत करने के लिए तंत्र में बनाया गया है।

द्वारा लौटाए गए deregistration फ़ंक्शन का$on उपयोग करें :

// Register and get a handle to the listener
var listener = $scope.$on('someMessage', function () {
    $log.log("Message received");
});

// Unregister
$scope.$on('$destroy', function () {
    $log.log("Unregistering listener");
    listener();
});

इन के रूप में सरल, वहाँ एक बहुत जवाब है, लेकिन यह अधिक संक्षिप्त है।
डेविड एगुइलर

8
तकनीकी रूप से सही है, हालांकि थोड़ा भ्रामक है, क्योंकि $scope.$onमैन्युअल रूप से अपंजीकृत होना जरूरी नहीं है $destroy। इसका उपयोग करने के लिए एक बेहतर उदाहरण होगा $rootScope.$on
13 फरवरी को hgoebl

2
सबसे अच्छा जवाब है, लेकिन उस श्रोता को $ नष्ट करने के लिए कॉल करने के बारे में अधिक स्पष्टीकरण देखना चाहते हैं ताकि सुनने वाले को मार सके।
मोहम्मद रफिघ

1
@MohammadRafigh $ नष्ट के अंदर श्रोता को बुला रहा है, जहां मैंने इसे लगाने के लिए चुना है। यदि मुझे सही ढंग से याद है, तो यह कोड था जो मेरे पास एक निर्देश के अंदर था और यह समझ में आया कि जब निर्देश क्षेत्र नष्ट हो गया था, तो श्रोताओं को अपंजीकृत होना चाहिए।
long2know

@ अहगोएल मुझे नहीं पता कि आपका क्या मतलब है। यदि मेरे पास है, उदाहरण के लिए, एक निर्देश जो कई स्थानों पर उपयोग किया जाता है, और प्रत्येक एक घटना के लिए एक श्रोता को पंजीकृत कर रहा है, तो मैं $ rootScope का उपयोग कैसे करूंगा। मेरी मदद पर $। निर्देशकों का दायरा निपटान अपने श्रोताओं के निपटान के लिए सबसे अच्छी जगह है।
long2know

26

यह कोड मेरे लिए काम करता है:

$rootScope.$$listeners.nameOfYourEvent=[];

1
$ RootScope को देखते हुए। $$ श्रोता श्रोता के जीवनचक्र का निरीक्षण करने और उसके साथ प्रयोग करने का एक अच्छा तरीका है।
XML

सरल और महान दिखता है। मुझे लगता है कि इसके कार्य का संदर्भ हटा दिया गया है। है ना?
जय शुक्ला

26
यह समाधान अनुशंसित नहीं है क्योंकि $$ श्रोताओं के सदस्य को निजी माना जाता है। वास्तव में, '$ $' उपसर्ग के साथ कोणीय वस्तु का कोई भी सदस्य सम्मेलन द्वारा निजी है।
शोवनिक 25

5
मैं इस विकल्प की सिफारिश नहीं करूंगा, क्योंकि यह सभी श्रोताओं को हटा देता है, न कि केवल एक जिसे आपको हटाने की आवश्यकता है। जब आप स्क्रिप्ट के दूसरे भाग में किसी अन्य श्रोता को जोड़ते हैं तो यह भविष्य में समस्याएँ पैदा कर सकता है।
रेनर प्लमर

10

संपादित करें: ऐसा करने का सही तरीका @ LiviuT के उत्तर में है!

आप हमेशा इस तरह के श्रोताओं को हटाने की अनुमति देने के लिए कोणीय के दायरे को बढ़ा सकते हैं:

//A little hack to add an $off() method to $scopes.
(function () {
  var injector = angular.injector(['ng']),
      rootScope = injector.get('$rootScope');
      rootScope.constructor.prototype.$off = function(eventName, fn) {
        if(this.$$listeners) {
          var eventArr = this.$$listeners[eventName];
          if(eventArr) {
            for(var i = 0; i < eventArr.length; i++) {
              if(eventArr[i] === fn) {
                eventArr.splice(i, 1);
              }
            }
          }
        }
      }
}());

और यहां बताया गया है कि यह कैसे काम करेगा:

  function myEvent() {
    alert('test');
  }
  $scope.$on('test', myEvent);
  $scope.$broadcast('test');
  $scope.$off('test', myEvent);
  $scope.$broadcast('test');

और यहाँ कार्रवाई में इसका एक प्लंकर है


एक जादू की तरह काम किया! लेकिन मैंने इसे थोड़ा एडिट किया। मैंने इसे
.run

इस घोल से प्यार करें। एक बहुत क्लीनर समाधान के लिए बनाता है - इतना आसान पढ़ने के लिए। +1
रिक

7

कोड को डीबग करने के बाद, मैंने अपना फ़ंक्शन "blesh" के उत्तर की तरह बनाया। तो यही वह है जो मैंने किया

MyModule = angular.module('FIT', [])
.run(function ($rootScope) {
        // Custom $off function to un-register the listener.
        $rootScope.$off = function (name, listener) {
            var namedListeners = this.$$listeners[name];
            if (namedListeners) {
                // Loop through the array of named listeners and remove them from the array.
                for (var i = 0; i < namedListeners.length; i++) {
                    if (namedListeners[i] === listener) {
                        return namedListeners.splice(i, 1);
                    }
                }
            }
        }
});

इसलिए मेरे कार्य को $ rootcope में संलग्न करके अब यह मेरे सभी नियंत्रकों के लिए उपलब्ध है।

और मेरे कोड में मैं कर रहा हूँ

$scope.$off("onViewUpdated", callMe);

धन्यवाद

संपादित करें: ऐसा करने का AngularJS @ LiviuT के उत्तर में है! लेकिन यदि आप श्रोता को किसी अन्य दायरे में पंजीकृत करना चाहते हैं और उसी समय डे-रजिस्टर फ़ंक्शन के संदर्भों को रखने के लिए स्थानीय चर बनाने से दूर रहना चाहते हैं। यह एक संभव उपाय है।


1
मैं वास्तव में अपना उत्तर हटा रहा हूं, क्योंकि @ LiviuT का उत्तर 100% सही है।
बेन लेश

@blesh LiviuT का उत्तर सही है और एक कोण से एक एंगुलर ने डी-रजिस्टर के लिए दृष्टिकोण प्रदान किया है, लेकिन उन परिदृश्यों के लिए अच्छी तरह से हुक-अप नहीं करता है जहां आपको श्रोता को अलग-अलग दायरे में डी-रजिस्टर करना है। तो यह एक आसान विकल्प है।
हितेश। स्नेहा

1
यह एक ही हुक प्रदान करता है किसी भी अन्य समाधान होगा। आप एक बाहरी बंद या यहां तक ​​कि एक वैश्विक संग्रह में विनाश फ़ंक्शन वाले चर को डाल सकते हैं ... या कहीं भी आप चाहते हैं।
बेन लेश

मैं डी-पंजीकरण कार्यों के संदर्भों को बनाए रखने के लिए वैश्विक चर बनाना नहीं चाहता हूं और साथ ही मैं अपने स्वयं के $ $ फ़ंक्शन का उपयोग करने के साथ कोई समस्या नहीं देखता हूं।
हितेश.नेजा

1

@ LiviuT का उत्तर भयानक है, लेकिन बहुत सारे लोगों को यह सोचकर छोड़ देता है कि हैंडलर के आंसू-डाउन फ़ंक्शन को एक और $ गुंजाइश या फ़ंक्शन से फिर से कैसे एक्सेस किया जाए, यदि आप इसे उस जगह से अलग करना चाहते हैं जहां इसे बनाया गया था। @ Рустем Мусабеков का जवाब सिर्फ महान काम करता है, लेकिन बहुत मुहावरेदार नहीं है। (और क्या एक निजी कार्यान्वयन विस्तार होना चाहिए पर निर्भर करता है, जो किसी भी समय बदल सकता है।) और वहाँ से, यह बस और अधिक जटिल हो जाता है ...

मुझे लगता है कि यहाँ आसान उत्तर केवल offCallMeFnहैंडलर में आंसू-डाउन फ़ंक्शन ( उनके उदाहरण में) का संदर्भ लेना है, और फिर इसे कुछ शर्त के आधार पर कॉल करना है; शायद एक arg कि आप इस घटना पर आप $ प्रसारण या $ emit शामिल हैं। हैंडलर इस प्रकार स्वयं को तबाह कर सकते हैं, जब भी आप चाहें, जहां चाहें, अपने स्वयं के विनाश के बीज के आसपास ले जा सकते हैं। इस तरह:

// Creation of our handler:
var tearDownFunc = $rootScope.$on('demo-event', function(event, booleanParam) {
    var selfDestruct = tearDownFunc;
    if (booleanParam === false) {
        console.log('This is the routine handler here. I can do your normal handling-type stuff.')
    }
    if (booleanParam === true) {
        console.log("5... 4... 3... 2... 1...")
        selfDestruct();
    }
});

// These two functions are purely for demonstration
window.trigger = function(booleanArg) {
    $scope.$emit('demo-event', booleanArg);
}
window.check = function() {
    // shows us where Angular is stashing our handlers, while they exist
    console.log($rootScope.$$listeners['demo-event'])
};

// Interactive Demo:

>> trigger(false);
// "This is the routine handler here. I can do your normal handling-type stuff."

>> check();
// [function] (So, there's a handler registered at this point.)  

>> trigger(true);
// "5... 4... 3... 2... 1..."

>> check();
// [null] (No more handler.)

>> trigger(false);
// undefined (He's dead, Jim.)

दो विचार:

  1. रन-वे हैंडलर के लिए यह एक बेहतरीन फॉर्मूला है। बस सशर्तों को छोड़ दें और selfDestructजैसे ही वह आत्मघाती मिशन पूरा करे, चला जाए ।
  2. मुझे आश्चर्य है कि क्या मूल गुंजाइश कभी नष्ट हो जाएगी और कचरा एकत्र किया जाएगा, यह देखते हुए कि आप बंद चर का संदर्भ ले रहे हैं। आपको इनमें से एक लाख का उपयोग करना होगा, यहां तक ​​कि यह एक स्मृति समस्या भी हो सकती है, लेकिन मैं उत्सुक हूं। अगर किसी के पास कोई अंतर्दृष्टि है, तो कृपया साझा करें।

1

घटक हटाए जाने पर अपने श्रोताओं को सदस्यता समाप्त करने के लिए एक हुक पंजीकृत करें:

$scope.$on('$destroy', function () {
   delete $rootScope.$$listeners["youreventname"];
});  

जबकि ऐसा करने के लिए आम तौर पर स्वीकृत तरीका नहीं है, कई बार यह आवश्यक उपाय है।
टोनी ब्रजुनस

1

ऐसे मामले में जब आपको कई बार श्रोता को चालू और बंद करने की आवश्यकता होती है, तो आप booleanपैरामीटर के साथ एक फ़ंक्शन बना सकते हैं

function switchListen(_switch) {
    if (_switch) {
      $scope.$on("onViewUpdated", this.callMe);
    } else {
      $rootScope.$$listeners.onViewUpdated = [];
    }
}

0

'$ पर' स्वयं अपंजीकृत के लिए कार्य करता है

 var unregister=  $rootScope.$on('$stateChangeStart',
            function(event, toState, toParams, fromState, fromParams, options) { 
                alert('state changing'); 
            });

आप उस श्रोता को अपंजीकृत करने के लिए अपंजीकृत () फ़ंक्शन को कॉल कर सकते हैं


0

एक तरीका यह है कि आप श्रोता को बस एक बार नष्ट कर दें।

var removeListener = $scope.$on('navBarRight-ready', function () {
        $rootScope.$broadcast('workerProfile-display', $scope.worker)
        removeListener(); //destroy the listener
    })
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.