AngularJS 컨트롤러가 동일한 모듈의 다른 컨트롤러에서 상속 할 수 있습니까?


198

모듈 내에서 컨트롤러는 외부 컨트롤러에서 속성을 상속 할 수 있습니다.

var app = angular.module('angularjs-starter', []);

var ParentCtrl = function ($scope, $location) {
};

app.controller('ChildCtrl', function($scope, $injector) {
  $injector.invoke(ParentCtrl, this, {$scope: $scope});
});

예를 통해 : 데드 링크 : http://blog.omkarpatil.com/2013/02/controller-inheritance-in-angularjs.html

모듈 내부의 컨트롤러가 형제로부터 상속받을 수 있습니까?

var app = angular.module('angularjs-starter', []);

app.controller('ParentCtrl ', function($scope) {
  //I'm the sibling, but want to act as parent
});

app.controller('ChildCtrl', function($scope, $injector) {
  $injector.invoke(ParentCtrl, this, {$scope: $scope}); //This does not work
});

$injector.invoke첫 번째 매개 변수로 함수가 필요하고에 대한 참조를 찾지 못해 두 번째 코드가 작동 하지 않습니다 ParentCtrl.


도움이 될 것입니다 : stackoverflow.com/questions/16828287/…
Bart

2
따로 : 이것은 상속처럼 보이지 않지만 메소드 공유 또는 주입과 비슷합니다. 아마도 의미론 일 것입니다.
alockwood05

예제에 대한 링크가 더 이상 유효하지 않습니다.
AlexS

구글 캐시 링크 : webcache.googleusercontent.com/… 이 흥미로운 바이올린을 가리키는 : jsfiddle.net/mhevery/u6s88/12
Federico Elles

답변:


289

예, 가능하지만 $controller대신 서비스를 사용 하여 컨트롤러를 인스턴스화해야합니다.

var app = angular.module('angularjs-starter', []);

app.controller('ParentCtrl', function($scope) {
  // I'm the sibling, but want to act as parent
});

app.controller('ChildCtrl', function($scope, $controller) {
  $controller('ParentCtrl', {$scope: $scope}); //This works
});

ParentCtrl반드시 a controller아니면 가능하면을 사용하는 것입니다 service?
gontard

@gontard :이 경우 $controller등록 된 컨트롤러 만 사용할 수 있으므로 컨트롤러 여야합니다 .
ZeissS

10
아주 좋은 해결책입니다. 감사합니다. 그러나 Controller As 구문을 사용하는 경우 어떻게해야합니까?
Ka

1
위의 바이올린은 질문으로 요청되었습니다. 단순히 controllerAs을 지적 그것의 가치는 범위에 컨트롤러를 할당 - 변경 것 그래서 $scopethis(이론적으로)
댄 식료품 저장실

4
이것은 나를 위해 일했지만 부모 컨트롤러와 자식 컨트롤러가 같은 페이지에있는 방식 으로이 작업을 수행하려고합니다. 이로 인해 상위 컨트롤러의 $ http 작업이 두 번 실행됩니다. 자식 컨트롤러가 부모 컨트롤러의 범위를 주입하면 부모 컨트롤러가 실행하여 내 $ scope.AllMembers 배열이 두 번 채워지고 자식 컨트롤러가 다시 실행됩니다. 그것을 막을 방법이 있습니까?
Ryan Mann

20

vm컨트롤러 구문을 사용 하는 경우 내 솔루션은 다음과 같습니다.

.controller("BaseGenericCtrl", function ($scope) {

    var vm = this;
    vm.reload = reload;
    vm.items = [];

    function reload() {
        // this function will come from child controller scope - RESTDataService.getItemsA
        this.getItems();
    }
})

.controller("ChildCtrl", function ($scope, $controller, RESTDataService) {
    var vm = this;
    vm.getItems = RESTDataService.getItemsA;
    angular.extend(vm, $controller('BaseGenericCtrl', {$scope: $scope}));
})

불행히도 $controller.call(vm, 'BaseGenericCtrl'...)현재 컨텍스트를 클로저 (for reload()) 함수 에 전달 하는 데 사용할 수 없으므로 컨텍스트 this를 동적으로 변경하기 위해 상속 된 함수 내부 를 사용하는 솔루션은 하나뿐입니다 .


방금 대신이 작업을 수행 할 수 없었습니까? > $ controller ( 'BaseGenericControl', {vm : vm});
herringtown

vm컨트롤러 내부의 변수 일뿐이므로 Angular가 예상대로 사용할 수 있다고 생각하지 않습니다.
IProblemFactory

8

두 컨트롤러에 액세스 가능한 기능이나 데이터를 제공하려면 공장이나 서비스를 사용해야한다고 생각합니다.

다음은 비슷한 질문입니다 ---> AngularJS 컨트롤러 상속


예, 한 가지 방법입니다. 감사합니다. 솔루션을 검색 할 때 그 게시물을 보았습니다. 컨트롤러 기능을로드하고 "this"를 확장 할 수있는 방법이 있는지 생각하고있었습니다.
Ka Ka

나는 loading데이터가로드 될 때 항상 똑같은 일을 할 수 있도록 범용 변수 를 갖고 싶습니다 . 공장이 그렇게 할 수 있다고 생각하지 않습니다. 부모 컨트롤러는 로딩 변수를 가질 수 있지만 팩토리는 그것을 조작 할 수 없습니다 ... 맞습니까?!
PixMach

7

gmontague가이 답변 에서 제기 한 문제에 응답 하여 $ controller ()를 사용하여 컨트롤러를 상속하고 컨트롤러 "as"구문을 사용하는 방법을 찾았습니다.

먼저 $ controller () 호출을 상속 할 때 "as"구문을 사용하십시오.

    app.controller('ParentCtrl', function(etc...) {
        this.foo = 'bar';
    });
    app.controller('ChildCtrl', function($scope, $controller, etc...) {
        var ctrl = $controller('ParentCtrl as parent', {etc: etc, ...});
        angular.extend(this, ctrl);

    });

그런 다음 HTML 템플리트에서 특성이 상위에 의해 정의 된 경우이를 사용 parent.하여 상위에서 상속 된 특성을 검색하십시오. child에 의해 정의 된 경우 child.이를 사용 하여 검색하십시오.

    <div ng-controller="ChildCtrl as child">{{ parent.foo }}</div>

5

글쎄, 나는 다른 방법으로 이것을했다. 필자의 경우 다른 컨트롤러에서 동일한 기능과 속성을 적용하는 기능을 원했습니다. 매개 변수를 제외하고는 마음에 들었습니다. 이런 식으로, 귀하의 모든 ChildCtrl은 $ location을 받아야합니다.

var app = angular.module('angularjs-starter', []);

function BaseCtrl ($scope, $location) {
    $scope.myProp = 'Foo';
    $scope.myMethod = function bar(){ /* do magic */ };
}

app.controller('ChildCtrl', function($scope, $location) {
    BaseCtrl.call(this, $scope, $location);

    // it works
    $scope.myMethod();
});

4

궁금한 점이 있으시면 허용되는 답변의 방법을 사용하여 동일한 방식으로 구성 요소 컨트롤러를 확장 할 수 있습니다.

다음 접근법을 사용하십시오.

상위 컴포넌트 (확장) :

/**
 * Module definition and dependencies
 */
angular.module('App.Parent', [])

/**
 * Component
 */
.component('parent', {
  templateUrl: 'parent.html',
  controller: 'ParentCtrl',
})

/**
 * Controller
 */
.controller('ParentCtrl', function($parentDep) {

  //Get controller
  const $ctrl = this;

  /**
   * On init
   */
  this.$onInit = function() {

    //Do stuff
    this.something = true;
  };
});

하위 구성 요소 (확장 된 구성 요소) :

/**
 * Module definition and dependencies
 */
angular.module('App.Child', [])

/**
 * Component
 */
.component('child', {
  templateUrl: 'child.html',
  controller: 'ChildCtrl',
})

/**
 * Controller
 */
.controller('ChildCtrl', function($controller) {

  //Get controllers
  const $ctrl = this;
  const $base = $controller('ParentCtrl', {});
  //NOTE: no need to pass $parentDep in here, it is resolved automatically
  //if it's a global service/dependency

  //Extend
  angular.extend($ctrl, $base);

  /**
   * On init
   */
  this.$onInit = function() {

    //Call parent init
    $base.$onInit.call(this);

    //Do other stuff
    this.somethingElse = true;
  };
});

요령은 컴포넌트 정의에서 컨트롤러를 정의하는 대신 명명 된 컨트롤러를 사용하는 것입니다.


2

허용 된 답변에 언급 된 $controller('ParentCtrl', {$scope: $scope, etc: etc});대로 하위 컨트롤러에서 다음 을 호출하여 상위 컨트롤러의 $ scope 및 기타 서비스 수정 사항을 "상속"할 수 있습니다 .

그러나 컨트롤러 'as'구문을 사용하는 데 익숙한 경우 (예 :

<div ng-controller="ChildCtrl as child">{{ child.foo }}</div>

foo를 통해 상위 컨트롤러에 설정되어 있으면 this.foo = ...하위 컨트롤러에 액세스 할 수 없습니다.

주석에서 언급했듯이 $ controller의 결과를 범위에 직접 할당 할 수 있습니다.

var app = angular.module('angularjs-starter', []);
app.controller('ParentCtrl ', function(etc...) {
    this.foo = 'bar';
});
app.controller('ChildCtrl', function($scope, $controller, etc...) {
    var inst = $controller('ParentCtrl', {etc: etc, ...});

    // Perform extensions to inst
    inst.baz = inst.foo + " extended";

    // Attach to the scope
    $scope.child = inst;
});

참고 : 그런 다음 있어야 에서 '로'부분을 제거하지 ng-controller=더 이상 템플릿을 코드에서 인스턴스 이름을 지정하고 있기 때문에.


"Controller as"구문을 사용해도 문제가 없습니다. 내 답변보기 : stackoverflow.com/a/36549465/2197555
gm2008

2

"Controller as"구문을 사용하여 컨트롤러 vm = this를 상속하려고했습니다. 부모 컨트롤러에 변수를 수정하는 함수가 있으면 문제가있었습니다.

사용 IProblemFactory의살만 압바스의 답변을, 나는 부모 변수에 액세스 할 수 있도록 다음과 같은했다 :

(function () {
  'use strict';
  angular
      .module('MyApp',[])
      .controller('AbstractController', AbstractController)
      .controller('ChildController', ChildController);

  function AbstractController(child) {
    var vm = child;
    vm.foo = 0;
    
    vm.addToFoo = function() {
      vm.foo+=1;
    }
  };
  
  function ChildController($controller) {
    var vm = this;
    angular.extend(vm, $controller('AbstractController', {child: vm}));
  };
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="ChildController as childCtrl" layout="column" ng-cloak="" ng-app="MyApp">
  <button type="button" ng-click="childCtrl.addToFoo()">
    add
  </button>
  <span>
      -- {{childCtrl.foo}} --
  </span>
</div>


0

간단한 JavaScript 상속 메커니즘을 사용할 수 있습니다. 또한 .call 메소드를 호출하기 위해 필요한 각도 서비스를 전달하는 것을 잊지 마십시오.

//simple function (js class)
function baseCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService) {//any serrvices and your 2

   this.id = $routeParams.id;
   $scope.id = this.id;

   this.someFunc = function(){
      $http.get("url?id="+this.id)
      .then(success function(response){
        ....
       } ) 

   }
...
}

angular
        .module('app')
        .controller('childCtrl', childCtrl);

//angular controller function
function childCtrl($http, $scope, $location, $rootScope, $routeParams, $log, $timeout, $window, modalService) {      
   var ctrl = this;
   baseCtrl.call(this, $http, $scope, $location, $rootScope,  $routeParams, $log, $timeout, $window, modalService);

   var idCopy = ctrl.id;
   if($scope.id == ctrl.id){//just for sample
      ctrl.someFunc();
   }
}

//also you can copy prototype of the base controller
childCtrl.prototype = Object.create(baseCtrl.prototype);

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