AngularJS : 서비스 속성에 올바른 바인딩 방법


162

AngularJS에서 서비스 속성에 바인딩하는 방법에 대한 모범 사례를 찾고 있습니다.

AngularJS를 사용하여 만든 서비스의 속성에 바인딩하는 방법을 이해하기 위해 여러 예제를 살펴 보았습니다.

아래에는 서비스의 속성에 바인딩하는 방법에 대한 두 가지 예가 있습니다. 그들은 둘 다 작동합니다. 첫 번째 예는 기본 바인딩을 사용하고 두 번째 예는 $ scope. $ watch를 사용하여 서비스 속성에 바인딩합니다.

서비스의 속성에 바인딩 할 때 이러한 예제 중 하나를 선호합니까, 아니면 알지 못하는 다른 옵션이 권장됩니까?

이 예제의 전제는 서비스가 5 초마다“lastUpdated”및“calls”속성을 업데이트해야한다는 것입니다. 서비스 속성이 업데이트되면 뷰에 이러한 변경 사항이 반영되어야합니다. 이 두 예제는 모두 성공적으로 작동합니다. 더 좋은 방법이 있는지 궁금합니다.

기본 바인딩

다음 코드를보고 실행할 수 있습니다. http://plnkr.co/edit/d3c16z

<html>
<body ng-app="ServiceNotification" >

    <div ng-controller="TimerCtrl1" style="border-style:dotted"> 
        TimerCtrl1 <br/>
        Last Updated: {{timerData.lastUpdated}}<br/>
        Last Updated: {{timerData.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.timerData = Timer.data;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

서비스 속성에 대한 바인딩을 해결하는 다른 방법은 컨트롤러에서 $ scope. $ watch를 사용하는 것입니다.

$ scope. $ watch

다음 코드를보고 실행할 수 있습니다. http://plnkr.co/edit/dSBlC9

<html>
<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.$watch(function () { return Timer.data.lastUpdated; },
                function (value) {
                    console.log("In $watch - lastUpdated:" + value);
                    $scope.lastUpdated = value;
                }
            );

            $scope.$watch(function () { return Timer.data.calls; },
                function (value) {
                    console.log("In $watch - calls:" + value);
                    $scope.calls = value;
                }
            );
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

서비스에서 $ rootscope. $ broadcast를 사용할 수 있고 컨트롤러에서 $ root. $ on을 사용할 수 있다는 것을 알고 있지만 첫 번째 브로드 캐스트에서 $ broadcast / $를 사용하도록 만든 다른 예에서는 브로드 캐스트되는 추가 호출이 컨트롤러에서 트리거됩니다. $ rootscope. $ broadcast 문제를 해결하는 방법을 알고 있다면 답변을 제공하십시오.

그러나 앞에서 언급 한 내용을 다시 설명하기 위해 서비스 속성에 바인딩하는 방법에 대한 모범 사례를 알고 싶습니다.


최신 정보

이 질문은 원래 2013 년 4 월에 요청 및 답변되었습니다. 2014 년 5 월, Gil Birman은 새로운 답변을 제공했는데, 정답으로 바뀌 었습니다. Gil Birman의 답변에는 투표가 거의 없기 때문에이 질문을 읽는 사람들은 더 많은 투표로 다른 답변에 찬성하여 그의 답변을 무시할 것입니다. 최고의 답변이 무엇인지 결정하기 전에 Gil Birman의 답변을 적극 권장합니다.


조 데이비드 밀러의 대답이 길 버먼의 대답보다 낫다고 생각합니다. 그리고 $ watch, $ watchGroup 및 $ watchCollection을 사용하면 훨씬 더 나아질 수 있습니다. 중대형 앱에서는 관심사 분리가 매우 중요합니다.
Jonathan

@ bardev 나는 두 가지 대답이 모두 유용하지 않다고 생각하고, 새로운 개발자는 완전히 잘못 이해합니다.
Zalaboza

당신이 요구하는 문제는 객체 참조의 네이티브 JavaScript 변수 동작에 관한 것입니다. 아래에 약간의 설명을 추가했습니다.
Zalaboza

답변:


100

두 번째 접근 방식의 장단점을 고려하십시오 .

  • {{lastUpdated}}대신 {{timerData.lastUpdated}}쉽게 {{timer.lastUpdated}}읽을 수있는 0 대신에 0 은 더 읽기 쉽다고 주장하지만 (논쟁하지 말고 ...이 점에 중립 등급을 부여하므로 직접 결정하십시오)

  • +1 컨트롤러가 마크 업을위한 일종의 API 역할을하는 것이 편리 할 수 ​​있습니다. 따라서 데이터 모델의 구조가 변경되는 경우 이론적으로 html 부분을 건드리지 않고 컨트롤러의 API 매핑 을 업데이트 할 수 있습니다 .

  • -1 그러나 이론은 항상 실천되지 않고 나는 보통 자신을 마크 업 수정하지 찾을 수 변경이 요구 될 때, 컨트롤러 로직을 어쨌든 . 따라서 API를 작성하려는 추가 노력으로 인해 이점이 무효화됩니다.

  • -1 또한이 방법은 그리 건조하지 않습니다.

  • -1 데이터를 ng-model코드 에 바인딩 $scope.scalar_values하려면 컨트롤러에서 패키지를 다시 패키지하여 새 REST 호출 을 수행해야하므로 DRY가 줄어 듭니다 .

  • -0.1 추가 감시자를 만들면 성능이 약간 저하됩니다. 또한 데이터 속성이 특정 컨트롤러에서 감시 할 필요가없는 모델에 연결되어 있으면 심층 감시자에게 추가 오버 헤드가 발생합니다.

  • -1 여러 컨트롤러에 동일한 데이터 모델이 필요한 경우 어떻게합니까? 즉, 모든 모델 변경 시마다 업데이트 할 여러 API가 있습니다.

$scope.timerData = Timer.data;지금 막 강렬한 유혹을 느끼기 시작하고 있습니다 ... 마지막 요점을 조금 더 깊이 살펴 보도록하겠습니다. 백엔드 (서버)의 모델? 아니면 프론트 엔드에서만 만들어지고 존재하는 모델입니까? 어느 경우이든, 본질적으로 데이터 맵핑 API프론트 엔드 서비스 계층 (각 팩토리 또는 서비스)에 속한다 . (첫 번째 예-선호 사항)에는 서비스 계층 에 이러한 API 가 없으므로 필요하지 않기 때문에 간단합니다.

결론적 으로 모든 것을 분리 할 필요는 없습니다. 그리고 마크 업을 데이터 모델에서 완전히 분리하는 한, 단점이 장점보다 중요합니다.


컨트롤러는 일반적으로 로 흩어지지 않아야합니다 $scope = injectable.data.scalar. 오히려, 그들은 함께 뿌려해야한다 $scope = injectable.data의, promise.then(..)의, 그리고 $scope.complexClickAction = function() {..}

데이터 디커플링 따라서보기 - 캡슐화하는 유일한 장소 달성하기위한 다른 방법으로 정말 모델에서보기 분리하는 것이 합리적 이다 지시문과를 . 그러나 거기에도 또는 함수 $watch에 스칼라 값을 두지 마십시오 . 시간을 절약하거나 코드를 유지 관리하거나 읽을 수있게하지는 않습니다. 각도에서의 강력한 테스트는 일반적으로 결과 DOM 을 테스트하기 때문에 테스트를 더 쉽게 할 수 없습니다 . 오히려 지시문에서 데이터 API 를 객체 형태로 요구하고에 의해 생성 된 er 만 사용 하는 것이 좋습니다.controllerlink$watchng-bind


http://plnkr.co/edit/MVeU1GKRTN4bqA3h9Yio

<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Bad:<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
        Good:<br/>
        Last Updated: {{data.lastUpdated}}<br/>
        Last Updated: {{data.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.data = Timer.data;
            $scope.lastUpdated = Timer.data.lastUpdated;
            $scope.calls = Timer.data.calls;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 500);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>

업데이트 : 마지막 으로이 질문으로 돌아와 두 가지 접근 방식이 "잘못된"것이라고 생각하지 않는다고 덧붙였습니다. 원래 나는 Josh David Miller의 대답이 틀렸다고 썼지 만 회고하면 그의 견해, 특히 우려의 분리에 관한 그의 견해는 완전히 유효합니다.

우려를 따로 (그러나 접선 적으로 관련) 분리하면, 방어 카피 에는 고려해야 또 다른 이유가 있습니다. 이 질문은 주로 서비스에서 직접 데이터를 읽는 것에 관한 것입니다. 그러나 팀의 개발자가 뷰가 데이터를 표시하기 전에 컨트롤러가 데이터를 사소한 방식으로 변환해야한다고 결정하면 어떻게 될까요? (컨트롤러가 데이터를 변환해야하는지 여부에 대해서는 또 다른 논의가 있습니다.) 오브젝트의 사본을 먼저 작성하지 않으면 동일한 데이터를 사용하는 다른보기 구성 요소에서 무의식적으로 회귀가 발생할 수 있습니다.

이 질문에서 실제로 강조하는 것은 전형적인 앵귤러 응용 프로그램 (그리고 실제로는 모든 JavaScript 응용 프로그램)의 구조적 단점, 우려의 엄격한 결합 및 객체 변경 가능성입니다. 최근 React 불변의 데이터 구조를 사용하여 설계 응용 프로그램에 매료되었습니다 . 그렇게하면 다음 두 가지 문제가 훌륭하게 해결됩니다.

  1. 우려 분리 : 구성 요소는 소품을 통해 모든 데이터를 사용하며 전역 단일 톤 (예 : 각도 서비스)에 거의 의존하지 않으며 뷰 계층에서 그 위에 일어난 일에 대해서는 전혀 알지 못합니다 .

  2. 변경 성 : 모든 소품은 변경이 불가능하여 의도 하지 않은 데이터 변이의 위험을 제거합니다.

Angular 2.0은 이제 React에서 많은 돈을 빌려 위의 두 가지 포인트를 달성 할 수 있습니다.


1
더 많이 이해하면 AngularJS와 함께 일하고 있습니다. AngularJS 컨트롤러는 가능한 한 단순하고 얇아 야한다고 생각합니다. 컨트롤러에 $ watches를 추가하면 로직이 복잡해집니다. 서비스의 가치를 참조하면 훨씬 간단하고 AngularJS 방식에 가깝습니다. –
Mike Barlow-BarDev 2016 년

3
AngularJS의 "10 계명" 이유는 선언적입니다.
pilau

Josh David Miller의 답변은 "INCORRECT"가 아닙니다. 모든 것을위한 시간과 장소가 있습니다.
JoshuaDavid

당신이 맞다고 생각합니다, @FireCoding. 답변을 업데이트 할 계획입니다.
Gil Birman

@ GilBirman 훌륭한 답변입니다. 지침에 대한 글을 작성하고 모범을 보이시겠습니까? "모델과 뷰를 분리하는 것이 실제로 의미가있는 유일한 곳은 지시문을 사용하는 것입니다. [...] 오히려 지시문에서 데이터 API를 객체 형태로 요구하고 $ 만 사용하는 것이 좋습니다. ng-bind가 만든 감시자 "
klode

78

내 관점에서 볼 $watch때 가장 좋은 방법입니다.

실제로 예제를 약간 단순화 할 수 있습니다.

function TimerCtrl1($scope, Timer) {
  $scope.$watch( function () { return Timer.data; }, function (data) {
    $scope.lastUpdated = data.lastUpdated;
    $scope.calls = data.calls;
  }, true);
}

그게 당신이 필요한 전부입니다.

속성이 동시에 업데이트되므로 하나의 시계 만 필요합니다. 또한 그것들은 하나의 작은 물체에서 나왔기 때문에 Timer.data속성을 보도록 변경했습니다 . 전달 된 마지막 매개 변수 $watch는 참조가 동일한 지 확인하지 않고 깊은 평등을 검사 하도록 지시합니다.


약간의 맥락을 제공하기 위해 서비스 방법을 범위에 직접 배치하는 것보다이 방법을 선호하는 이유는 우려를 적절히 분리하는 것입니다. 서비스를 운영하기 위해 서비스에 대해 알 필요가 없습니다. 컨트롤러의 역할은 모든 것을 하나로 묶는 것입니다. 업무는 서비스에서 데이터를 가져와 필요한 방식으로 처리 한 다음 필요한 특정 정보를 제공하는 것입니다. 그러나 나는 그 임무가 단지 서비스를 바로보기에 전달하는 것이라고 생각하지 않습니다. 그렇지 않으면 컨트롤러가 무엇을하고 있습니까? AngularJS 개발자들은 템플릿에 "논리"를 포함시키지 않기로 선택했을 때와 같은 추론을 따랐습니다 (예 : if진술).

공평하게, 여기에 여러 관점이있을 수 있으며 다른 답변을 기대합니다.


3
좀 더 정교하게 할 수 있습니까? 보기가 서비스에 덜 연결되어 있기 때문에 $ watches를 선호합니까? 즉, {{lastUpdated}}{{timerData.lastUpdated}}
마크 Rajcok

2
Timer.data$ watch에 Timer전달하는 문자열식이 범위에 대해 평가되므로 $ watch 에 사용하려면 @BarDev를 $ scope에 정의해야합니다. 다음은 그 작업을 수행하는 방법을 보여주는 플런저 입니다. 여기에 objectEquality 매개 변수가 설명되어 있습니다 ( 3 번째 매개 변수).
Mark Rajcok

2
현명한 성능 $watch은 매우 비효율적입니다. stackoverflow.com/a/17558885/932632stackoverflow.com/questions/12576798/…
Krym

11
@Kyrm 아마도 어떤 상황에서는 사실 일 것입니다. 그러나 성능을 다룰 때는 통계적으로 중요한 일반화 된 것보다는 "임상 적으로 중요한"성능 향상을 찾아야합니다. 기존 응용 프로그램에 성능 문제가 있으면 해결해야합니다. 그렇지 않으면, 그것은 조기 최적화의 경우에 불과하며, 이는 모범 사례를 따르지 않고 입증 된 이점이없는 읽기 어려운, 버그가 발생하기 쉬운 코드로 이어집니다.
Josh David Miller

1
감시자가 함수를 사용하여 getter를 호출한다고 가정하면 그렇습니다. 잘 작동한다. 또한 컬렉션에서 인스턴스를 반환하는 서비스를 제안하는 사람입니다. 여기서 es5의 getter 및 setter 기능은 상당히 잘 사용됩니다.
Josh David Miller

19

파티에 늦었지만 미래의 Google 직원에게는 제공된 답변을 사용하지 마십시오.

JavaScript는 "숫자, 문자열 등"값에 대해 얕은 사본 만 전달하는 반면 참조로 오브젝트를 전달하는 메커니즘을 가지고 있습니다.

위의 예에서 서비스의 속성을 바인딩하는 대신 서비스를 범위에 노출시키지 않는 이유는 무엇입니까?

$scope.hello = HelloService;

이 간단한 접근 방식을 통해 각도는 양방향 바인딩과 필요한 모든 마법 같은 작업을 수행 할 수 있습니다. 감시자 또는 불필요한 마크 업으로 컨트롤러를 해킹하지 마십시오.

뷰가 실수로 서비스 속성을 덮어 쓰는 것이 걱정되는 경우 defineProperty이를 사용 하여 읽기, 열거 가능, 구성 가능 또는 게터 및 세터를 정의하십시오. 서비스를보다 견고하게 만들어 많은 제어권을 얻을 수 있습니다.

마지막 팁 : 컨트롤러보다 서비스에서 작업하는 데 시간을 보낸다면 잘못하고 있습니다 :(.

제공 한 특정 데모 코드에서 다음을 수행하는 것이 좋습니다.

 function TimerCtrl1($scope, Timer) {
   $scope.timer = Timer;
 }
///Inside view
{{ timer.time_updated }}
{{ timer.other_property }}
etc...

편집하다:

위에서 언급했듯이 다음을 사용하여 서비스 속성의 동작을 제어 할 수 있습니다 defineProperty

예:

// Lets expose a property named "propertyWithSetter" on our service
// and hook a setter function that automatically saves new value to db !
Object.defineProperty(self, 'propertyWithSetter', {
  get: function() { return self.data.variable; },
  set: function(newValue) { 
         self.data.variable = newValue; 
         // let's update the database too to reflect changes in data-model !
         self.updateDatabaseWithNewData(data);
       },
  enumerable: true,
  configurable: true
});

이제 컨트롤러에서

$scope.hello = HelloService;
$scope.hello.propertyWithSetter = 'NEW VALUE';

우리의 서비스는 propertyWithSetter어떻게 든 가치를 변화시키고 새로운 가치를 데이터베이스에 게시 할 것입니다!

또는 원하는 방식으로 접근 할 수 있습니다.

에 대한 MDN 설명서 를 참조하십시오 defineProperty.


확신 내가 함께, 위에서 설명 된 무엇 그 $scope.model = {timerData: Timer.data};그냥 범위 대신 직접 모델에 첨부.
Scott Silvi

1
AFAIK, js 객체 참조는 서비스의 모든 작업에 적용됩니다. $ scope.controllerVar = ServiceVar와 같이 코딩하면 $ scope.controllerVar에서 수행하는 모든 작업은 ServiceVar에서도 수행됩니다.
Kai Wang

@KaiWang은 DefineAttribute를 사용하기로 결정하지 않는 한 컨트롤러가 실수로 서비스 데이터를 변경하지 못하도록 서비스에 setter 함수를 만들 수 있음에 동의합니다.
Zalaboza

12

나는이 질문에 맥락 적 구성 요소가 있다고 생각합니다.

단순히 서비스에서 데이터를 가져 와서 그 정보를 볼 수 있다면 서비스 속성에 직접 바인딩하는 것이 좋습니다. 단순히 서비스 속성을 모델 속성에 매핑하여 내 관점에서 소비 하는 많은 상용구 코드 를 작성 하고 싶지 않습니다 .

또한 각도에서의 성능은 두 가지를 기반으로합니다. 첫 번째는 페이지에 몇 개의 바인딩이 있는지입니다. 두 번째는 getter 함수의 가격입니다. Misko는 여기 에 대해 이야기합니다 .

서비스 자체에 적용된 데이터 마사지와 달리 서비스 데이터에 대해 인스턴스 특정 로직을 수행해야하고 그 결과가 뷰에 노출 된 데이터 모델에 영향을 미치는 경우 $ watcher가 적절하다고 말할 수 있습니다. 기능이 엄청나게 비싸지 않는 한. 비싼 함수의 경우 결과를 로컬 (컨트롤러) 변수에 캐싱하고 $ watcher 함수 외부에서 복잡한 작업을 수행 한 다음 범위를 그 결과에 바인딩하는 것이 좋습니다.

경고로 $ scope에서 직접 속성을 걸면 안됩니다 . $scope변수는 모델이 아닙니다. 모델에 대한 참조가 있습니다.

내 생각에는 단순히 서비스에서 아래로 정보를 발산하는 "모범 사례":

function TimerCtrl1($scope, Timer) {
  $scope.model = {timerData: Timer.data};
};

그리고 당신의 견해에는가 포함 {{model.timerData.lastupdated}}됩니다.


그 제안에주의를 기울이면 자바 스크립트 전문가가 아닌 사람은 문자열 속성을 사용하여 시도 할 수 있습니다. 이 경우 javascript는 객체를 참조하지 않지만 raw는 문자열을 복사합니다. (변경되는 경우 업데이트되지 않는 나쁜 원인)
Valerio

7
필자는 항상 점을 사용해야하는 내 '캐비티'로 덮지 않았습니까 (즉, $ scope에 매달리지 말고 $ scope.model에 매달리지 마십시오). $ scope.model.someStringProperty가 있고 뷰에서 model.someStringProperty를 참조하면 내부 감시자가 소품이 아닌 객체에 있기 때문에 업데이트됩니다.
Scott Silvi

6

위의 예제를 바탕으로 컨트롤러 변수를 서비스 변수에 투명하게 바인딩하는 방법으로 던질 것이라고 생각했습니다.

아래 예에서 Controller $scope.count변수 에 대한 변경 사항 은 Service count변수 에 자동으로 반영됩니다 .

프로덕션 환경에서는 실제로이 바인딩을 사용하여 서비스의 ID를 업데이트 한 다음 비동기 적으로 데이터를 가져오고 서비스 변수를 업데이트합니다. 추가 바인딩은 서비스가 자체적으로 업데이트 될 때 컨트롤러가 자동으로 업데이트됨을 의미합니다.

아래 코드는 http://jsfiddle.net/xuUHS/163/ 에서 작동하는 것으로 볼 수 있습니다

전망:

<div ng-controller="ServiceCtrl">
    <p> This is my countService variable : {{count}}</p>
    <input type="number" ng-model="count">
    <p> This is my updated after click variable : {{countS}}</p>

    <button ng-click="clickC()" >Controller ++ </button>
    <button ng-click="chkC()" >Check Controller Count</button>
    </br>

    <button ng-click="clickS()" >Service ++ </button>
    <button ng-click="chkS()" >Check Service Count</button>
</div>

서비스 / 컨트롤러 :

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

app.service('testService', function(){
    var count = 10;

    function incrementCount() {
      count++;
      return count;
    };

    function getCount() { return count; }

    return {
        get count() { return count },
        set count(val) {
            count = val;
        },
        getCount: getCount,
        incrementCount: incrementCount
    }

});

function ServiceCtrl($scope, testService)
{

    Object.defineProperty($scope, 'count', {
        get: function() { return testService.count; },
        set: function(val) { testService.count = val; },
    });

    $scope.clickC = function () {
       $scope.count++;
    };
    $scope.chkC = function () {
        alert($scope.count);
    };

    $scope.clickS = function () {
       ++testService.count;
    };
    $scope.chkS = function () {
        alert(testService.count);
    };

}

이것은 훌륭한 솔루션입니다. 감사합니다.이 작업은 매우 현명한 방법이었습니다. :)
Javis Perez

2

서비스 자체 의 속성 대신 서비스 자체에 바인딩 하는 것이 더 좋은 방법이라고 생각 합니다.

이유는 다음과 같습니다.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.7/angular.min.js"></script>
<body ng-app="BindToService">

  <div ng-controller="BindToServiceCtrl as ctrl">
    ArrService.arrOne: <span ng-repeat="v in ArrService.arrOne">{{v}}</span>
    <br />
    ArrService.arrTwo: <span ng-repeat="v in ArrService.arrTwo">{{v}}</span>
    <br />
    <br />
    <!-- This is empty since $scope.arrOne never changes -->
    arrOne: <span ng-repeat="v in arrOne">{{v}}</span>
    <br />
    <!-- This is not empty since $scope.arrTwo === ArrService.arrTwo -->
    <!-- Both of them point the memory space modified by the `push` function below -->
    arrTwo: <span ng-repeat="v in arrTwo">{{v}}</span>
  </div>

  <script type="text/javascript">
    var app = angular.module("BindToService", []);

    app.controller("BindToServiceCtrl", function ($scope, ArrService) {
      $scope.ArrService = ArrService;
      $scope.arrOne = ArrService.arrOne;
      $scope.arrTwo = ArrService.arrTwo;
    });

    app.service("ArrService", function ($interval) {
      var that = this,
          i = 0;
      this.arrOne = [];
      that.arrTwo = [];

      $interval(function () {
        // This will change arrOne (the pointer).
        // However, $scope.arrOne is still same as the original arrOne.
        that.arrOne = that.arrOne.concat([i]);

        // This line changes the memory block pointed by arrTwo.
        // And arrTwo (the pointer) itself never changes.
        that.arrTwo.push(i);
        i += 1;
      }, 1000);

    });
  </script>
</body> 

이 플 런커 에서 재생할 수 있습니다 .


1

차라리 감시자를 최대한 줄이려고합니다. 내 이유는 내 경험을 바탕으로하고 있으며 이론적으로 주장 할 수 있습니다.
감시자를 사용하는 문제는 범위의 모든 속성을 사용하여 원하는 구성 요소 또는 서비스의 메서드를 호출 할 수 있다는 것입니다.
현실 세계 프로젝트에서, 곧 당신이 될 겁니다 비 tracable 방법의 체인 호출되는 및 값 특별히 온 보딩 프로세스가 비극적 만드는 변경되는 (더 나은 하드 트레이스했다)가.


0

서비스를 보내는 데이터를 바인딩하는 것은 좋은 생각이 아닙니다 (아키텍처). 더 이상 필요한 경우 두 가지 방법을 제안합니다

1) 서비스 내부가 아닌 데이터를 얻을 수 있습니다. 컨트롤러 / 지시문 내부에서 데이터를 얻을 수 있으며 어디서나 바인딩 할 수있는 문제가 없습니다.

2) angularjs 이벤트를 사용할 수 있습니다. 원할 때마다 ($ rootScope에서) 신호를 보내고 원하는 곳 어디에서나 잡을 수 있습니다. 해당 eventName에 대한 데이터를 보낼 수도 있습니다.

어쩌면 이것이 도움이 될 수 있습니다. 더 많은 예제가 필요하면 여기 링크가 있습니다.

http://www.w3docs.com/snippets/angularjs/bind-value-between-service-and-controller-directive.html


-1

이건 어떤가요

scope = _.extend(scope, ParentScope);

ParentScope가 주입 된 서비스는 어디에 있습니까?


-2

가장 우아한 솔루션 ...

app.service('svc', function(){ this.attr = []; return this; });
app.controller('ctrl', function($scope, svc){
    $scope.attr = svc.attr || [];
    $scope.$watch('attr', function(neo, old){ /* if necessary */ });
});
app.run(function($rootScope, svc){
    $rootScope.svc = svc;
    $rootScope.$watch('svc', function(neo, old){ /* change the world */ });
});

또한 EDA (Event-Driven Architectures)를 작성하므로 다음과 같은 [단순화 된 버전]과 같은 작업을 수행하는 경향이 있습니다.

var Service = function Service($rootScope) {
    var $scope = $rootScope.$new(this);
    $scope.that = [];
    $scope.$watch('that', thatObserver, true);
    function thatObserver(what) {
        $scope.$broadcast('that:changed', what);
    }
};

그런 다음 원하는 채널의 컨트롤러에 리스너를 넣고 로컬 범위를 최신 방식으로 유지하십시오.

오히려 그 - 결론적으로, 많이 "모범 사례"의이 아니라 주로 선호 - 긴 너가 이렇게 유지 일 SOLID 약한 커플 링을 사용한다. 후자의 코드를 옹호하는 이유는 EDA가 본질적으로 가능한 가장 낮은 결합을 가지고 있기 때문 입니다. 그리고 당신이이 사실에 대해 너무 걱정하지 않는다면, 우리는 같은 프로젝트에서 함께 일하지 않도록합시다.

도움이 되었기를 바랍니다...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.