Angular JS의 컨트롤러간에 데이터를 전달 하시겠습니까?


243

제품을 표시하는 기본 컨트롤러가 있습니다.

App.controller('ProductCtrl',function($scope,$productFactory){
     $productFactory.get().success(function(data){
           $scope.products = data;
     });
});

내 견해로는이 제품을 목록으로 표시하고 있습니다.

<ul>
    <li ng-repeat="product as products">
        {{product.name}}
    </li>
</ul

내가하려는 것은 누군가 제품 이름을 클릭 할 때이 제품이 추가 된 cart라는 다른보기가 있습니다.

 <ul class="cart">
      <li>
          //click one added here
      </li>
      <li>
          //click two added here
      </li>
 </ul>

내 의심은 여기에서 클릭 한 제품을 첫 번째 컨트롤러에서 두 번째 컨트롤러로 어떻게 전달합니까? 카트도 컨트롤러라고 가정했습니다.

지시문을 사용하여 클릭 이벤트를 처리합니다. 또한 위의 기능을 달성하기 위해 서비스를 사용해야한다고 생각합니다. 어떻게 이해할 수 없습니까? 장바구니는 사전 정의되므로 추가 된 제품 수는 페이지 사용자에 따라 5/10이 될 수 있습니다. 그래서 나는이 일반적인 것을 유지하고 싶습니다.

최신 정보:

브로드 캐스트하는 서비스를 만들었고 두 번째 컨트롤러에서 서비스를 받았습니다. 이제 쿼리는 어떻게 dom을 업데이트합니까? 제품 삭제 목록이 꽤 하드 코딩되었으므로.


답변:


322

설명에서 서비스를 사용해야하는 것처럼 보입니다. 확인 http://egghead.io/lessons/angularjs-sharing-data-between-controllers을 하고 컨트롤러 간 데이터를 전달 AngularJS와 서비스는 몇 가지 예를 볼 수 있습니다.

다음과 같이 제품 서비스를 공장으로 정의 할 수 있습니다.

app.factory('productService', function() {
  var productList = [];

  var addProduct = function(newObj) {
      productList.push(newObj);
  };

  var getProducts = function(){
      return productList;
  };

  return {
    addProduct: addProduct,
    getProducts: getProducts
  };

});

종속성은 서비스를 두 컨트롤러에 모두 주입합니다.

ProductController에서 선택한 객체를 배열에 추가하는 작업을 정의 하십시오 .

app.controller('ProductController', function($scope, productService) {
    $scope.callToAddToProductList = function(currObj){
        productService.addProduct(currObj);
    };
});

CartController의 서비스에서 제품을 받으십시오 .

app.controller('CartController', function($scope, productService) {
    $scope.products = productService.getProducts();
});

3
getProducts ()가 호출되면 카트 컨트롤러가 한 번 업데이트됩니까? 아니면 새로운 제품이 추가 될 때마다?
kishanio

1
자동으로 업데이트하려면 Maxim Shoustin의 응답에서 브로드 캐스트를 추가하고 $ on 함수 내에서 getProducts ()를 호출하여 CartCtrl의 범위를 업데이트 할 수 있습니다.
Chalise

2
@krillgar 당신은 처음에 간과되었던 완전히 정확합니다. 작동하는 솔루션을 반영하기 위해 답변을 편집했습니다.
Chalise

1
@DeveshM 예, 제안한대로하십시오. 메소드를 확장하여 메모리에 데이터를 보관하는 것이 아니라 더 지속적이되도록 ( $http예를 들어 호출을 통해 서버에 저장) 메소드를 확장하는 것이 좋습니다.
Chalise

1
예를 들어 2 개의 productController와 2 개의 카트가 있으면 어떻게됩니까? 둘 다 요소가 추가됩니까? 이 경우 어떻게 해결합니까?
atoth

67

이 클릭 한 제품을 첫 번째 컨트롤러에서 두 번째 컨트롤러로 어떻게 전달합니까?

클릭하면 브로드 캐스트 를 호출하는 메소드를 호출 할 수 있습니다 .

$rootScope.$broadcast('SOME_TAG', 'your value');

두 번째 컨트롤러는 다음과 같이이 태그를 수신합니다.

$scope.$on('SOME_TAG', function(response) {
      // ....
})

서비스에 $ scope를 주입 할 수 없기 때문에 singleton $ scope와 같은 것은 없습니다.

그러나 우리는 주입 할 수 있습니다 $rootScope. 따라서 서비스에 가치를 저장 $rootScope.$broadcast('SOME_TAG', 'your value');하면 서비스 본문에서 실행할 수 있습니다 . (서비스에 대한 @Charx 설명 참조)

app.service('productService',  function($rootScope) {/*....*/}

$ broadcast , $ emit에 대한 좋은 기사를 확인하십시오


1
예, 이것은 공장을 사용하는 매력처럼 작동합니까? 내가 붙어있는 마지막 한 가지가 있습니다. 제품을 클릭 할 때마다 새 컨트롤러에서 데이터를 얻습니다. 이제 DOM에서 어떻게 업데이트합니까? 내가 이미 가지고 있기 때문에 각 제품은 그 내부에 갈 필요가 그래서 테두리 하드 코딩 (5)의 말 목록 수
kishanio

1
@KT-답을 얻었습니까? 명백한 질문처럼 보이지만 어디서나 답을 찾을 수 없습니다. 컨트롤러가 값을 변경하고 싶습니다. 해당 앱 값이 변경되면 다른 청취 컨트롤러는 필요에 따라 스스로 업데이트해야합니다. 찾을 수 없습니다.
raddevus

2
@daylight 귀하의 질문에 대한 답변. 병렬 또는 자식 부모의 컨트롤러 구조를 기반으로합니다. $rootScope.$broadcast병렬 구조 (일명 동일한 레벨)를 가진 모든 컨트롤러에 알립니다.
Maxim Shoustin

@MS 답장을 보내 주셔서 감사합니다. $ watch를 사용하여 이것을 수행하는 방법이 있습니까? BTW, Mine은 병렬 컨트롤러이며 귀하의 방법을 사용하여 작동합니다. 나를 위해 $ watch ($ rootScope까지)를 추가하려고 할 때마다 두 번째 컨트롤러의 $ watch와 관련된 메소드는 처음으로 만 발생합니다 (두 번째 컨트롤러의 초기화). 감사.
raddevus

1
$watch값이 $rootScope레벨 에 있으면 사용할 수 있습니다 . 그렇지 않으면 브로드 캐스트 만 다른 컨트롤러에 알릴 수 있습니다. 참고로, 다른 프로그래머가 여러분의 코드를 본다면, broadcast"브로드 캐스트 이벤트"라는 논리가 당신이 무엇을하려고하는지 분명합니다. 어쨌든 내 특급에서. 이 아니 좋은 연습 사용하기 rootscope위해 watch. "첫 번째 화재 만"정보 : plnkr.co/edit/5zqkj7iYloeHYkzK1Prt?p= 이전 값과 새 값이 있는지 미리보기 이전과 같지 않은 새로운 가치를 얻을 때마다
Maxim Shoustin

24

$ rootScope를 사용하여 서비스를 작성하지 않은 솔루션 :

앱 컨트롤러간에 속성을 공유하려면 Angular $ rootScope를 사용할 수 있습니다. 이것은 사람들이 정보를 알 수 있도록 데이터를 공유하는 또 다른 옵션입니다.

Controllers에서 일부 기능을 공유하는 기본 방법은 Services이며 $ rootscope를 사용할 수있는 전역 속성을 읽거나 변경하는 것입니다.

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

템플리트에서 $ rootScope 사용 ($ root를 사용하여 액세스 특성) :

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>

27
$rootScope가능한 한 피해야합니다.
Shaz

1
@Shaz 왜 당신은 정교한 수 있습니까?
Mirko

5
@Mirko 누구나 변경할 수 있기 때문에 가능한 한 전역 상태를 피해야합니다. 프로그램 상태를 예측할 수 없게 만듭니다.
Umut Seven

4
$ rootScope에는 전역 범위가 있으므로 기본 전역 변수와 같이 신중하게 사용해야합니다. 컨트롤러가 값을 변경하면 전역 범위에 맞게 변경됩니다.
Sanjeev

1
서비스 및 공장은 모두 Singleton이지만 Controller에 서비스를 주입하거나 주입하지 않도록 선택할 수 있습니다. 그러나 모든 하위 범위는 루트 스코프에서 파생되며 프로토 타입 체인을 따릅니다. 따라서 범위의 속성에 액세스하려고 시도하지만 해당 속성이 없으면 체인을 찾습니다. rootscope 속성을 원치 않게 변경할 수 있습니다.
Sanjeev

16

두 가지 방법으로이 작업을 수행 할 수 있습니다.

  1. 를 사용 $rootscope하지만 권장하지 않습니다. 는 $rootScope최상위 범위이다. 앱에는 앱의 $rootScope모든 구성 요소간에 공유 할 앱이 하나만 있을 수 있습니다. 따라서 전역 변수처럼 작동합니다.

  2. 서비스 사용 두 컨트롤러간에 서비스를 공유하여이를 수행 할 수 있습니다. 서비스 코드는 다음과 같습니다.

    app.service('shareDataService', function() {
        var myList = [];
    
        var addList = function(newObj) {
            myList.push(newObj);
        }
    
        var getList = function(){
            return myList;
        }
    
        return {
            addList: addList,
            getList: getList
        };
    });

    당신은 내 바이올린을 볼 수 있습니다 여기에 .


그리고 세 번째 옵션, 당신은 목록에 추가하기 위해 이벤트를 보낼 수 있습니다
DanteTheSmith

사용자가 페이지를 다시 만들면 어떻게됩니까? THEN getProducts ()는 당신에게 아무것도주지 말 것 (U 새로 고침에 모든 사용자를 말할 수 없다, 수 유를?)!
shreedhar을 바트

2
@shreedharbhat이 질문은 페이지를 다시로드 할 때 데이터를 유지하는 것에 대해 묻지 않습니다.
Jack Vial

9

컨트롤러간에 데이터를 공유하는보다 간단한 방법은 중첩 된 데이터 구조를 사용하는 것입니다. 예를 들어

$scope.customer = {};

우리는 사용할 수 있습니다

$scope.data = { customer: {} };

data속성은 상위 범위에서 상속되므로 다른 컨트롤러의 액세스를 유지하면서 필드를 덮어 쓸 수 있습니다.


1
컨트롤러는 상위 컨트롤러에서 자체 범위로 범위 속성을 상속합니다. 깨끗한! 단순성으로 인해
아름답습니다

그것을 작동시킬 수 없습니다. 두 번째 컨트롤러에서는 $ scope.data를 사용하며 정의되지 않았습니다.
Bart Calixto

그는 내 생각에 중첩 컨트롤러에 대해 이야기하고 있습니다. 나에게별로 사용하지 않습니다.
Norbert Norbertson

8
angular.module('testAppControllers', [])
    .controller('ctrlOne', function ($scope) {
        $scope.$broadcast('test');
    })
    .controller('ctrlTwo', function ($scope) {
        $scope.$on('test', function() {
        });
    });

그것은 niether를 사용합니다
Leathan

5

우리는 세션에 데이터를 저장하고 외부 프로그램의 어느 곳에서나 사용할 수 있습니다.

$window.sessionStorage.setItem("Mydata",data);

다른 장소

$scope.data = $window.sessionStorage.getItem("Mydata");

4

여기에서 답변을 보았으며 컨트롤러간에 데이터를 공유하는 문제에 대답하고 있지만 한 컨트롤러가 다른 브로드 캐스트를 사용하지 않고 데이터가 변경되었다는 사실을 알리려면 어떻게해야합니까? 쉬운! 유명한 방문자 패턴을 사용하면됩니다.

myApp.service('myService', function() {

    var visitors = [];

    var registerVisitor = function (visitor) {
        visitors.push(visitor);
    }

    var notifyAll = function() {
        for (var index = 0; index < visitors.length; ++index)
            visitors[index].visit();
    }

    var myData = ["some", "list", "of", "data"];

    var setData = function (newData) {
        myData = newData;
        notifyAll();
    }

    var getData = function () {
        return myData;
    }

    return {
        registerVisitor: registerVisitor,
        setData: setData,
        getData: getData
    };
}

myApp.controller('firstController', ['$scope', 'myService',
    function firstController($scope, myService) {

        var setData = function (data) {
            myService.setData(data);
        }

    }
]);

myApp.controller('secondController', ['$scope', 'myService',
    function secondController($scope, myService) {

        myService.registerVisitor(this);

        this.visit = function () {
            $scope.data = myService.getData();
        }

        $scope.data = myService.getData();
    }
]);

이 간단한 방식으로 한 컨트롤러는 일부 데이터가 업데이트 된 다른 컨트롤러를 업데이트 할 수 있습니다.


2
옵저버 패턴 ( en.wikipedia.org/wiki/Observer_pattern )이 더 관련성이 없습니까? 방문자 패턴은 다른 것입니다 ... en.wikipedia.org/wiki/Visitor_pattern
Ant Kutschera

3

경로 경로 패턴 사이의 공유 범위를 제어하는 ​​팩토리를 만들었으므로 사용자가 동일한 경로 상위 경로를 탐색 할 때만 공유 데이터를 유지할 수 있습니다.

.controller('CadastroController', ['$scope', 'RouteSharedScope',
    function($scope, routeSharedScope) {
      var customerScope = routeSharedScope.scopeFor('/Customer');
      //var indexScope = routeSharedScope.scopeFor('/');
    }
 ])

따라서 사용자가 다른 경로 경로 (예 : '/ Support')로 이동하면 경로 '/ Customer'에 대한 공유 데이터가 자동으로 삭제됩니다. 그러나이 대신 사용자가 '/ Customer / 1'또는 '/ Customer / list'와 같은 'child'경로로 이동하면 범위가 손상되지 않습니다.

여기에서 샘플을 볼 수 있습니다 : http://plnkr.co/edit/OL8of9


3

1

using $localStorage

app.controller('ProductController', function($scope, $localStorage) {
    $scope.setSelectedProduct = function(selectedObj){
        $localStorage.selectedObj= selectedObj;
    };
});

app.controller('CartController', function($scope,$localStorage) { 
    $scope.selectedProducts = $localStorage.selectedObj;
    $localStorage.$reset();//to remove
});

2

클릭하면 브로드 캐스트를 호출하는 메소드를 호출 할 수 있습니다.

$rootScope.$broadcast('SOME_TAG', 'your value');

and the second controller will listen on this tag like:
$scope.$on('SOME_TAG', function(response) {
      // ....
})

using $rootScope:

4

window.sessionStorage.setItem("Mydata",data);
$scope.data = $window.sessionStorage.getItem("Mydata");

5

각도 서비스를 사용하는 한 가지 방법 :

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

app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});

app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});

app.factory('ser1', function(){
return {o: ''};
});

2
답변에 더 많은 설명을 넣으십시오.
게르하르트 바 너드

2

모듈에서 팩토리를 만들고 컨트롤러에서 팩토리의 참조를 추가하고 컨트롤러에서 변수를 사용하고 원하는 위치에 참조를 추가하여 다른 컨트롤러에서 데이터 값을 가져옵니다.


2

그것이 누군가에게 도움이 될지 모르겠지만 Charx (감사합니다!)에 따라 간단한 캐시 서비스를 만들었습니다. 자유롭게 사용하고 리믹스하고 공유하십시오 :

angular.service('cache', function() {
    var _cache, _store, _get, _set, _clear;
    _cache = {};

    _store = function(data) {
        angular.merge(_cache, data);
    };

    _set = function(data) {
        _cache = angular.extend({}, data);
    };

    _get = function(key) {
        if(key == null) {
            return _cache;
        } else {
            return _cache[key];
        }
    };

    _clear = function() {
        _cache = {};
    };

    return {
        get: _get,
        set: _set,
        store: _store,
        clear: _clear
    };
});

2

각도 서비스를 사용하는 한 가지 방법 :

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

app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});


app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});

app.factory('ser1', function(){
return {o: ''};
});



<div ng-app='home'>

<div ng-controller='one'>
  Type in text: 
  <input type='text' ng-model="inputText.o"/>
</div>
<br />

<div ng-controller='two'>
  Type in text:
  <input type='text' ng-model="inputTextTwo.o"/>
</div>

</div>

https://jsfiddle.net/1w64222q/



1

@Maxim이 $ broadcast를 사용하여 제안한 솔루션을 개선하기 위해 데이터를 보내지 마십시오.

$rootScope.$broadcast('SOME_TAG', 'my variable');

하지만 듣는 데이터

$scope.$on('SOME_TAG', function(event, args) {
    console.log("My variable is", args);// args is value of your variable
})


0
var custApp = angular.module("custApp", [])
.controller('FirstController', FirstController)
.controller('SecondController',SecondController)
.service('sharedData', SharedData);

FirstController.$inject = ['sharedData'];
function FirstController(sharedData) {
this.data = sharedData.data;
}

SecondController.$inject['sharedData'];
function SecondController(sharedData) {
this.data = sharedData.data;
}

function SharedData() {
this.data = {
    value: 'default Value'
}
}

첫 컨트롤러

<div ng-controller="FirstController as vm">
<input type=text ng-model="vm.data.value" />
</div>

두 번째 컨트롤러

 <div ng-controller="SecondController as vm">
    Second Controller<br>
    {{vm.data.value}}
</div>

-1

내가 생각하기에

가장 좋은 방법은

$ localStorage를 사용하는 것입니다. (항상 작동)

app.controller('ProductController', function($scope, $localStorage) {
    $scope.setSelectedProduct = function(selectedObj){
        $localStorage.selectedObj= selectedObj;
    };
});

귀하의 cardController는

app.controller('CartController', function($scope,$localStorage) { 
    $scope.selectedProducts = $localStorage.selectedObj;
    $localStorage.$reset();//to remove
});

추가 할 수도 있습니다

if($localStorage.selectedObj){
    $scope.selectedProducts = $localStorage.selectedObj;
}else{
    //redirect to select product using $location.url('/select-product')
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.