programing

AngularJS : 서비스 $broadcast 및 $watch가 수신 컨트롤러에서 트리거되지 않음

elecom 2023. 9. 20. 20:05
반응형

AngularJS : 서비스 $broadcast 및 $watch가 수신 컨트롤러에서 트리거되지 않음

Angular JS nook 여기, Angular Envelopment로 가는 나의 길 :)

상황은 이렇습니다.

제 모듈 '앱' 안에 '오디오 플레이어' 서비스를 구현하여 다음과 같이 등록하였습니다.

 app.service('AudioPlayer', function($rootScope) {

     // ...

     this.next = function () {
         // loads the next track in the playlist
         this.loadTrack(playlist[++playIndex]);     
     };

     this.loadTrack = function(track) {
         // ... loads the track and plays it
         // broadcast 'trackLoaded' event when done
         $rootScope.$broadcast('trackLoaded', track); 
     };
 }

여기 '수신기' 컨트롤러(주로 UI/프레젠테이션 로직용)가 있습니다.

app.controller('PlayerCtrl', function PlayerCtrl($scope, AudioPlayer) {


    // AudioPlayer broadcasts the event when the track is loaded

    $scope.$on('trackLoaded', function(event, track) {
        // assign the loaded track as the 'current' 
        $scope.current = track;
    });

    $scope.next = function() {
        AudioPlayer.next();
    };
}

현재 트랙 정보는 다음과 같이 표시합니다.

<div ng-controller="PlayerCtrl">
    <button ng-click="next()"></button>
    // ...
    <p id="info">{{current.title}} by {{current.author}}</p>
</div>

다음() 메서드는 PlayerCtrl에 정의되어 있으며 오디오 플레이어 서비스에서 동일한 메서드를 호출합니다.

문제가

수동 상호 작용이 있을 때(즉, 다음() 버튼을 클릭할 때), 흐름은 다음과 같습니다.

  1. 플레이어 Ctrl이 클릭을 가로채 자신의 다음() 방법을 발사합니다.
  2. 그러면 AudioPlayer.next() 메서드가 실행됩니다.
  3. 재생 목록에서 다음 트랙을 찾고 loadTrack() 메서드를 호출합니다.
  4. loadTrack() $broadcasting 'trackLoaded' 이벤트(트랙 자체를 함께 전송)
  5. 플레이어 Ctrl은 브로드캐스트 이벤트를 듣고 트랙을 현재 개체에 할당합니다.
  6. 보기가 올바르게 업데이트되고 current. title 및 current가 표시됩니다.저자정보

그러나 '백그라운드'(즉, 트랙이 끝나면)의 오디오 서비스 내에서 다음() 메서드가 호출되면 1부터 5까지의 모든 단계가 수행되지만 보기는 플레이어 Ctrl의 '현재' 개체의 변경 사항을 알리지 않습니다.

플레이어 Ctrl에서 새 트랙 객체가 할당되는 것을 명확하게 볼 수 있지만, 보기에 변경 사항이 통지되지 않는 것과 같습니다.저는 초보자인데 도움이 될지는 모르겠지만 PlayerCtrl에서 $watch 표현을 추가하려고 했습니다.

$scope.$watch('current', function(newVal, oldVal) {
    console.log('Current changed');
})

'수동' 상호작용을 할 때만 출력됩니다

다시 말하지만, 이미 말했듯이 $on listener에 console.log(current)를 이렇게 추가하면 다음과 같습니다.

$scope.$on('trackLoaded', function(event, track) {
    $scope.current = track;
    console.log($scope.current);
});

항상 올바르게 인쇄됩니다.

내가 뭘 잘못하고 있는 거지?

(ps HTML5 오디오 플레이어에 AudioJS를 사용하고 있지만 여기서 탓할 일은 아닌 것 같습니다...)

클릭 이벤트가 있을 때 $scope이 업데이트되고 이벤트가 없으면 $apply를 사용해야 합니다.

$scope.$apply(function () {
    $scope.current = track;
});

소화기 내부를 들여다보는 것은 안전하지 않기 때문에 가장 쉬운 방법은$timeout:

$timeout(function () {
    $scope.current = track;
}, 0);

콜백은 항상 좋은 환경에서 실행됩니다.

편집: 실제로 적용 단계에서 랩핑해야 하는 기능은

 this.loadTrack = function(track) {
     // ... loads the track and plays it
     // broadcast 'trackLoaded' event when done
     $timeout(function() { $rootScope.$broadcast('trackLoaded', track); });
 };

그렇지 않으면 방송이 빗나갈 것입니다.

~~~~~~

실제로, (적어도 의미론적 관점에서) 대안이 더 나을 수 있으며, 그것은 다이제스트 사이클 내부 또는 외부에서 동일하게 작동할 것입니다.

$scope.$evalAsync(function (scope) {
    scope.current = track;
});
  • 에서의 이점$scope.$apply를 알 당신이 소화 주기에 있는지 알 필요는 없습니다.
  • 에서의 이점$timeout , 를 더 수 .0매개 변수.
// apply changes
$scope.current = track;
try {
 if (!$scope.$$phase) {
  $scope.$apply($scope.current);
 }
} catch (err) {
 console.log(err);
}

걸 요, 와 잘 $rootScope.$applyAsync(function() {});

언급URL : https://stackoverflow.com/questions/12928840/angularjs-service-broadcast-and-watch-not-triggering-on-receiving-controller

반응형