programing

AngularJS에서 컨트롤러 간에 통신하는 올바른 방법은 무엇입니까?

topblog 2023. 5. 3. 20:46
반응형

AngularJS에서 컨트롤러 간에 통신하는 올바른 방법은 무엇입니까?

컨트롤러 간의 올바른 통신 방법은 무엇입니까?

저는 현재 끔찍한 속임수를 쓰고 있습니다.window:

function StockSubgroupCtrl($scope, $http) {
    $scope.subgroups = [];
    $scope.handleSubgroupsLoaded = function(data, status) {
        $scope.subgroups = data;
    }
    $scope.fetch = function(prod_grp) {
        $http.get('/api/stock/groups/' + prod_grp + '/subgroups/').success($scope.handleSubgroupsLoaded);
    }
    window.fetchStockSubgroups = $scope.fetch;
}

function StockGroupCtrl($scope, $http) {
    ...
    $scope.select = function(prod_grp) {
        $scope.selectedGroup = prod_grp;
        window.fetchStockSubgroups(prod_grp);
    }
}

편집: 이 답변에서 해결된 문제는 angular.js 버전 1.2.7에서 해결되었습니다.$broadcast이제 등록되지 않은 범위에 거품이 생기는 것을 방지하고 $196만큼 빠르게 실행됩니다. $198 성능은 각이 1.2.16인 $198과 동일합니다.

이제 다음을 수행할 수 있습니다.

  • 사용하다$broadcast$rootScope
  • 사하여듣기를 $on 사건에 대해 알아야 할 지역으로부터.

아래의 원본 답변

사용하지 않는 것이 좋습니다.$rootScope.$broadcast+$scope.$on 히려오$rootScope.$emit+$rootScope.$on전자는 @numan이 제기한 것처럼 심각한 성능 문제를 일으킬 수 있습니다.그것은 그 행사가 모든 범위를 통해 거품이 빠질 것이기 때문입니다.

( 그나사후자용(러사)(후자용▁however나)를 사용합니다.$rootScope.$emit+$rootScope.$on)는 이러한 문제를 겪지 않으므로 빠른 통신 채널로 사용할 수 있습니다!

문로부터의 각 에서.$emit:

이벤트 이름을 스코프 계층을 통해 위쪽으로 발송하여 등록됨을 알립니다.

에 범위가 없기 $rootScope거품이 일어나는 일은 없습니다.그것은 사용하기에 완전히 안전합니다.$rootScope.$emit()/$rootScope.$on()이벤트 버스로서.

그러나 컨트롤러 내에서 사용할 때 하나의 gotcha가 있습니다.에 직접 $rootScope.$on()할 때 직접 바인딩을 $scope 여러 번 로 인해 결국 할 수 입니다. :) 서는이 (컨와달리션) 트이의수수있때있발메수누결요가모수국생리되어약할습니다바이딩인인해로이며파다이니괴문됩될화기스동명번가인여턴케안스러애러플리롤비스▁this)llers▁contro▁because▁(ation▁get▁is이다▁which메iated결누가니파in수있모발국수괴리▁leaks생어

등록을 취소하려면, 다음을 들으십시오.$scope$destroy이벤트를 수행한 다음 반환된 함수를 호출합니다.$rootScope.$on.

angular
    .module('MyApp')
    .controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {

            var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
                console.log('foo');
            });

            $scope.$on('$destroy', unbind);
        }
    ]);

리소스를 정리해야 하는 다른 EventBus 구현에도 적용되는 것처럼 구체적인 사항은 아닙니다.

하지만, 여러분은 그러한 경우들을 위해 여러분의 삶을 더 쉽게 만들 수 있습니다.예를 들어, 당신은 원숭이 패치를 할 수 있습니다.$rootScope그리고 그것을 주세요.$onRootScope에서 발생한 이벤트에 가입합니다.$rootScope하지만 로컬일 때 핸들러를 직접 청소하기도 합니다.$scope파괴됩니다.

를 패치하는 은 원숭이를 패치하는 것입니다.$rootScope그런 것을 제공하기 위해$onRootScope방법은 장식가를 통해서일 것입니다(런 블록도 아마 잘 할 것이지만, pssst, 아무에게도 말하지 마세요).

를 하기 위해.$onRootScope▁doesnating▁over를 열거할 때 속성이 예기치 $scope우리는 사용합니다.Object.defineProperty() 트세를 합니다.enumerablefalseES5 심이 필요할 수 있습니다.

angular
    .module('MyApp')
    .config(['$provide', function($provide){
        $provide.decorator('$rootScope', ['$delegate', function($delegate){

            Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
                value: function(name, listener){
                    var unsubscribe = $delegate.$on(name, listener);
                    this.$on('$destroy', unsubscribe);

                    return unsubscribe;
                },
                enumerable: false
            });


            return $delegate;
        }]);
    }]);

이 방법을 사용하면 위의 컨트롤러 코드를 다음과 같이 단순화할 수 있습니다.

angular
    .module('MyApp')
    .controller('MyController', ['$scope', function MyController($scope) {

            $scope.$onRootScope('someComponent.someCrazyEvent', function(){
                console.log('foo');
            });
        }
    ]);

그래서 이 모든 것의 최종 결과로서, 저는 당신이 사용할 것을 강력히 권고합니다.$rootScope.$emit+$scope.$onRootScope.

그나저나, 저는 각진 팀이 각진 코어 내에서 문제를 해결하도록 설득하려고 합니다.여기서 논의가 진행 중입니다. https://github.com/angular/angular.js/issues/4574

영향이 .$broadcast단 100명으로 괜찮은 시나리오로 테이블에 올립니다.$scope

http://jsperf.com/rootscope-emit-vs-rootscope-broadcast

jsperf 결과

여기서 가장 중요한 답변은 @zumallifeguard가 언급한 것처럼 더 이상 존재하지 않는 각도 문제(최소한 1.2.16 이상의 버전 및 "아마도 이전")에서 해결한 것입니다.하지만 저는 실제적인 해결책 없이 이 모든 답들을 읽게 됩니다.

제가 보기에 지금 답은

  • 사용하다$broadcast$rootScope
  • 사하여듣기를 $on 사건에 대해 알아야 할 지역으로부터.

게시하려면

// EXAMPLE PUBLISHER
angular.module('test').controller('CtrlPublish', ['$rootScope', '$scope',
function ($rootScope, $scope) {

  $rootScope.$broadcast('topic', 'message');

}]);

구독하기

// EXAMPLE SUBSCRIBER
angular.module('test').controller('ctrlSubscribe', ['$scope',
function ($scope) {

  $scope.$on('topic', function (event, arg) { 
    $scope.receiver = 'got your ' + arg;
  });

}]);

플런커스

에 청취자를 $scope연결된 컨트롤러가 제거되면 자동으로 삭제됩니다.

$rootScope를 사용합니다.$209 및 $scope.PubSub 통신에 대한 $on.

또한 다음 게시물을 참조하십시오.각진JS – 컨트롤러 간 통신

defineProperty는 브라우저 호환성 문제가 있으므로 서비스를 사용하는 것을 고려해 볼 수 있을 것 같습니다.

angular.module('myservice', [], function($provide) {
    $provide.factory('msgBus', ['$rootScope', function($rootScope) {
        var msgBus = {};
        msgBus.emitMsg = function(msg) {
        $rootScope.$emit(msg);
        };
        msgBus.onMsg = function(msg, scope, func) {
            var unbind = $rootScope.$on(msg, func);
            scope.$on('$destroy', unbind);
        };
        return msgBus;
    }]);
});

컨트롤러에서 다음과 같이 사용합니다.

  • 컨트롤러 1

    function($scope, msgBus) {
        $scope.sendmsg = function() {
            msgBus.emitMsg('somemsg')
        }
    }
    
  • 컨트롤러 2

    function($scope, msgBus) {
        msgBus.onMsg('somemsg', $scope, function() {
            // your logic
        });
    }
    

GridLinked는 꽤 설계된 것처럼 보이는 PubSub 솔루션을 게시했습니다.서비스는 여기에서 확인할 수 있습니다.

또한 서비스 다이어그램:

메시징 서비스

실제로 방출 및 브로드캐스트를 사용하는 것은 비효율적입니다. 이벤트가 범위 계층을 오르내리기 때문에 복잡한 애플리케이션의 성능 저하가 쉽게 발생할 수 있습니다.

저는 서비스를 이용할 것을 제안합니다.이것이 제가 최근에 프로젝트 중 하나인 https://gist.github.com/3384419 에서 구현한 방법입니다.

기본 아이디어 - 펍 서브/이벤트 버스를 서비스로 등록합니다.그런 다음 이벤트/주제를 구독하거나 게시해야 하는 모든 곳에 해당 이벤트 버스를 주입합니다.

서비스 내에서 get 및 set 메서드를 사용하면 컨트롤러 간에 메시지를 매우 쉽게 전달할 수 있습니다.

var myApp = angular.module("myApp",[]);

myApp.factory('myFactoryService',function(){


    var data="";

    return{
        setData:function(str){
            data = str;
        },

        getData:function(){
            return data;
        }
    }


})


myApp.controller('FirstController',function($scope,myFactoryService){
    myFactoryService.setData("Im am set in first controller");
});



myApp.controller('SecondController',function($scope,myFactoryService){
    $scope.rslt = myFactoryService.getData();
});

HTML HTML에서 당신은 다음과 같이 확인할 수 있습니다.

<div ng-controller='FirstController'>  
</div>

<div ng-controller='SecondController'>
    {{rslt}}
</div>

원래 코드와 관련하여 - 스코프 간에 데이터를 공유하려는 것으로 보입니다.$scope 간에 데이터 또는 상태를 공유하려면 서비스를 사용하는 것이 좋습니다.

  • 컨트롤러 간에 공유되는 상태 비저장 또는 상태 저장 코드를 실행하려면 — 대신 각 서비스를 사용합니다.
  • 다른 구성 요소의 라이프사이클을 인스턴스화하거나 관리합니다(예: 서비스 인스턴스 생성).

참조: 여기에 있는 Angular Docs 링크

사실 저는 Postal.js를 컨트롤러 간의 메시지 버스로 사용하기 시작했습니다.

메시지 버스로서 AMQP 스타일 바인딩, 우편물이 iFrames 및 웹 소켓과 통합할 수 있는 방법 등 많은 이점이 있습니다.

장식가를 이용해서 우편물을 설치했습니다.$scope.$bus...

angular.module('MyApp')  
.config(function ($provide) {
    $provide.decorator('$rootScope', ['$delegate', function ($delegate) {
        Object.defineProperty($delegate.constructor.prototype, '$bus', {
            get: function() {
                var self = this;

                return {
                    subscribe: function() {
                        var sub = postal.subscribe.apply(postal, arguments);

                        self.$on('$destroy',
                        function() {
                            sub.unsubscribe();
                        });
                    },
                    channel: postal.channel,
                    publish: postal.publish
                };
            },
            enumerable: false
        });

        return $delegate;
    }]);
});

다음은 이 주제에 대한 블로그 게시물 링크입니다.
http://jonathancreamer.com//http://jonathancreamer.com/an-angular-event-bus-with-postal-js/

공장/서비스와 간단한 DI(Dependency Injection)사용하면 다음과 같이 처리할 수 있습니다.

myApp = angular.module('myApp', [])

# PeopleService holds the "data".
angular.module('myApp').factory 'PeopleService', ()->
  [
    {name: "Jack"}
  ]

# Controller where PeopleService is injected
angular.module('myApp').controller 'PersonFormCtrl', ['$scope','PeopleService', ($scope, PeopleService)->
  $scope.people = PeopleService
  $scope.person = {} 

  $scope.add = (person)->
    # Simply push some data to service
    PeopleService.push angular.copy(person)
]

# ... and again consume it in another controller somewhere...
angular.module('myApp').controller 'PeopleListCtrl', ['$scope','PeopleService', ($scope, PeopleService)->
  $scope.people = PeopleService
]

나는 그 방법이 좋았습니다.$rootscope.emit상호 통신을 달성하는 데 사용되었습니다.저는 글로벌 공간을 오염시키지 않는 깨끗하고 성능 효율적인 솔루션을 제안합니다.

module.factory("eventBus",function (){
    var obj = {};
    obj.handlers = {};
    obj.registerEvent = function (eventName,handler){
        if(typeof this.handlers[eventName] == 'undefined'){
        this.handlers[eventName] = [];  
    }       
    this.handlers[eventName].push(handler);
    }
    obj.fireEvent = function (eventName,objData){
       if(this.handlers[eventName]){
           for(var i=0;i<this.handlers[eventName].length;i++){
                this.handlers[eventName][i](objData);
           }

       }
    }
    return obj;
})

//Usage:

//In controller 1 write:
eventBus.registerEvent('fakeEvent',handler)
function handler(data){
      alert(data);
}

//In controller 2 write:
eventBus.fireEvent('fakeEvent','fakeData');

여기 빠르고 더러운 방법이 있습니다.

// Add $injector as a parameter for your controller

function myAngularController($scope,$injector){

    $scope.sendorders = function(){

       // now you can use $injector to get the 
       // handle of $rootScope and broadcast to all

       $injector.get('$rootScope').$broadcast('sinkallships');

    };

}

다음은 형제 컨트롤러 내에 추가할 함수의 예입니다.

$scope.$on('sinkallships', function() {

    alert('Sink that ship!');                       

});

그리고 물론 여기 HTML이 있습니다.

<button ngclick="sendorders()">Sink Enemy Ships</button>

시작 각도 1.5 및 구성요소 기반 개발 포커스입니다.구성 요소가 상호 작용하는 권장 방법은 '필수' 속성을 사용하고 속성 바인딩(입력/출력)을 사용하는 것입니다.

구성 요소에는 다른 구성 요소(예: 루트 구성 요소)가 필요하며 해당 컨트롤러에 대한 참조를 가져옵니다.

angular.module('app').component('book', {
    bindings: {},
    require: {api: '^app'},
    template: 'Product page of the book: ES6 - The Essentials',
    controller: controller
});

그런 다음 하위 구성 요소에서 루트 구성 요소의 방법을 사용할 수 있습니다.

$ctrl.api.addWatchedBook('ES6 - The Essentials');

루트 구성 요소 컨트롤러 기능은 다음과 같습니다.

function addWatchedBook(bookName){

  booksWatched.push(bookName);

}

다음은 전체 아키텍처 개요입니다.구성 요소 통신

이 Hello 기능은 모듈의 어느 곳에서나 액세스할 수 있습니다.

컨트롤러 1

 $scope.save = function() {
    $scope.hello();
  }

보조 제어기

  $rootScope.hello = function() {
    console.log('hello');
  }

자세한 내용은 여기에 있습니다.

나는 서비스를 만들고 알림을 사용할 것입니다.

  1. Notification Service에서 메서드 생성
  2. Notification Service에서 알림을 브로드캐스트하는 일반 메서드를 만듭니다.
  3. 소스 컨트롤러에서 알림 서비스를 호출합니다.방법. 또한 필요할 경우 해당 개체를 전달하여 지속합니다.
  4. 메소드 내에서, 나는 알림 서비스에 데이터를 유지하고 일반 알림 메소드를 호출합니다.
  5. 대상 컨트롤러에서 브로드캐스트 이벤트를 수신하고 알림 서비스의 데이터에 액세스합니다($scope.on).

Notification 서비스는 어느 시점에서나 단일화되어 있기 때문에 지속적인 데이터를 제공할 수 있어야 합니다.

이것이 도움이 되길 바랍니다.

Angular Angular를 사용할 수 . 서비스 JS 주식회사$rootScope두 컨트롤러 모두에 이 서비스를 주입합니다.그런 다음 $rootScope 개체에서 발생하는 이벤트를 수신할 수 있습니다.

는 $rootScope라는 두 합니다.$emit and $broadcast 지정일 수 을하며, 사용자 지정 이벤트를 사용합니다.$rootScope.$on이벤트 수신기를 추가하는 함수입니다.

은 이 . 왜냐하면, 당은서합니면다하, 왜냐신야이용.$rootscope전체 응용 프로그램에서 액세스할 수 있으므로 로드가 증가합니다. 데이터가 이보다 많지 않으면 루트 매개 변수를 사용할 수 있습니다.

function mySrvc() {
  var callback = function() {

  }
  return {
    onSaveClick: function(fn) {
      callback = fn;
    },
    fireSaveClick: function(data) {
      callback(data);
    }
  }
}

function controllerA($scope, mySrvc) {
  mySrvc.onSaveClick(function(data) {
    console.log(data)
  })
}

function controllerB($scope, mySrvc) {
  mySrvc.fireSaveClick(data);
}

$emit 및 $broadcast인 각 이벤트를 사용하여 수행할 수 있습니다.우리가 아는 바로는 이것이 가장 좋고 효율적이며 효과적인 방법입니다.

먼저 하나의 컨트롤러에서 함수를 호출합니다.

var myApp = angular.module('sample', []);
myApp.controller('firstCtrl', function($scope) {
    $scope.sum = function() {
        $scope.$emit('sumTwoNumber', [1, 2]);
    };
});
myApp.controller('secondCtrl', function($scope) {
    $scope.$on('sumTwoNumber', function(e, data) {
        var sum = 0;
        for (var a = 0; a < data.length; a++) {
            sum = sum + data[a];
        }
        console.log('event working', sum);

    });
});

$scope 대신 $rootScope를 사용할 수도 있습니다.그에 따라 컨트롤러를 사용합니다.

언급URL : https://stackoverflow.com/questions/11252780/whats-the-correct-way-to-communicate-between-controllers-in-angularjs

반응형