[angularjs] angularJS에서 브로드 캐스트 이벤트를 구독 취소하는 방법 $ on을 통해 등록 된 기능을 제거하는 방법

$ on 함수를 사용하여 청취자를 $ broadcast 이벤트에 등록했습니다.

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

특정 비즈니스 규칙에 따라이 리스너의 등록을 취소하고 싶습니다. 그러나 내 문제는 일단 등록되면 등록을 취소 할 수 없다는 것입니다.

AngularJS에 특정 리스너의 등록을 해제하는 방법이 있습니까? 이 이벤트를 등록 취소하는 $ on과 같은 방법은 $ off 일 수 있습니다. 비즈니스 로직을 바탕으로 말할 수 있습니다.

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

이 함수는 누군가 “onViewUpdated”이벤트를 브로드 캐스트 할 때 호출이 중지됩니다.

감사

편집 : 다른 기능에서 리스너를 등록 취소하고 싶습니다. 내가 등록한 기능이 아닙니다.



답변

반환 된 함수를 저장하고 이벤트에서 구독을 취소하려면 호출해야합니다.

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;
    };
},

또한 docs를 참조하십시오 .


답변

대부분의 답글을 보면 지나치게 복잡해 보입니다. Angular에는 등록 해제 메커니즘이 내장되어 있습니다.

다음에 의해 반환 된 등록 해제 기능을$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();
});


답변

이 코드는 저에게 효과적입니다.

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


답변

편집 : 이것을 수행하는 올바른 방법은 @LiviuT의 답변입니다!

이러한 청취자를 다음과 같이 제거 할 수 있도록 항상 Angular의 범위를 확장 할 수 있습니다.

//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');

그리고 여기에 행동의 무리가 있습니다


답변

코드를 디버깅 한 후 “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);
                    }
                }
            }
        }
});

내 기능을 $ rootscope에 첨부하면 모든 컨트롤러에서 사용할 수 있습니다.

내 코드에서 내가하고있다

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

감사

편집 : 이것을 수행하는 AngularJS 방법은 @LiviuT의 답변에 있습니다! 그러나 다른 범위에서 리스너를 등록 취소하고 동시에 등록 취소 기능의 참조를 유지하기 위해 로컬 변수를 작성하지 않으려는 경우. 가능한 해결책입니다.


답변

@ LiviuT의 답변은 훌륭하지만 다른 $ scope 또는 함수에서 처리기의 분해 기능에 다시 액세스하는 방법을 궁금해하는 사람들이 많이 있습니다. @ Рустем Мусабеков의 답변은 훌륭하게 작동하지만 관용적이지는 않습니다. (그리고 개인 구현 세부 사항에 의존해야하며 언제든지 변경 될 수 있습니다.) 그리고 더 복잡해집니다 …

여기서 쉬운 해답 offCallMeFn은 핸들러 자체에서 테어 다운 함수 ( 예를 들어)에 대한 참조를 수행 한 다음 조건에 따라 호출하는 것입니다. 아마도 당신이 $ broadcast 또는 $ 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. 클로저 변수에 대한 참조를 가지고 있다고 가정하면 원래 범위가 올바르게 파괴되고 가비지 수집 될지 궁금합니다. 메모리 문제가 되려면 백만 가지를 사용해야하지만 궁금합니다. 누군가 통찰력이 있으면 공유하십시오.

답변

구성 요소가 제거 될 때 청취자를 구독 취소하려면 후크를 등록하십시오.

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