it-swarm.com.de

Kann ein AngularJS-Controller einen anderen aufrufen?

Kann ein Controller einen anderen verwenden?

Zum Beispiel:

Dieses HTML-Dokument druckt einfach eine Nachricht aus, die vom MessageCtrl-Controller in der messageCtrl.js -Datei übermittelt wird.

<html xmlns:ng="http://angularjs.org/">
<head>
    <meta charset="utf-8" />
    <title>Inter Controller Communication</title>
</head>
<body>
    <div ng:controller="MessageCtrl">
        <p>{{message}}</p>
    </div>

    <!-- Angular Scripts -->
    <script src="http://code.angularjs.org/angular-0.9.19.js" ng:autobind></script>
    <script src="js/messageCtrl.js" type="text/javascript"></script>
</body>
</html>

Die Controller-Datei enthält den folgenden Code:

function MessageCtrl()
{
    this.message = function() { 
        return "The current date is: " + new Date().toString(); 
    };
}

Welche druckt einfach das aktuelle Datum;

Wenn ich einen weiteren Controller hinzufügen würde, DateCtrl, der das Datum in einem bestimmten Format an MessageCtrl zurückgibt, wie würde man dies tun? Das DI-Framework scheint sich mit XmlHttpRequests und dem Zugriff auf Dienste zu befassen.

572
BanksySan

Es gibt mehrere Möglichkeiten zur Kommunikation zwischen Controllern.

Das Beste ist wahrscheinlich, einen Dienst zu teilen:

function FirstController(someDataService) 
{
  // use the data service, bind to template...
  // or call methods on someDataService to send a request to server
}

function SecondController(someDataService) 
{
  // has a reference to the same instance of the service
  // so if the service updates state for example, this controller knows about it
}

Ein anderer Weg ist das Aussenden eines Ereignisses über den Umfang:

function FirstController($scope) 
{
  $scope.$on('someEvent', function(event, args) {});
  // another controller or even directive
}

function SecondController($scope) 
{
  $scope.$emit('someEvent', args);
}

In beiden Fällen können Sie auch mit jeder Anweisung kommunizieren.

700
Vojta

Siehe diese Geige: http://jsfiddle.net/simpulton/XqDxG/

Sehen Sie sich auch das folgende Video an: Kommunikation zwischen Controllern

HTML:

<div ng-controller="ControllerZero">
  <input ng-model="message" >
  <button ng-click="handleClick(message);">LOG</button>
</div>

<div ng-controller="ControllerOne">
  <input ng-model="message" >
</div>

<div ng-controller="ControllerTwo">
  <input ng-model="message" >
</div>

javascript:

var myModule = angular.module('myModule', []);
myModule.factory('mySharedService', function($rootScope) {
  var sharedService = {};

  sharedService.message = '';

  sharedService.prepForBroadcast = function(msg) {
    this.message = msg;
    this.broadcastItem();
  };

  sharedService.broadcastItem = function() {
    $rootScope.$broadcast('handleBroadcast');
  };

  return sharedService;
});

function ControllerZero($scope, sharedService) {
  $scope.handleClick = function(msg) {
    sharedService.prepForBroadcast(msg);
  };

  $scope.$on('handleBroadcast', function() {
    $scope.message = sharedService.message;
  });        
}

function ControllerOne($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'ONE: ' + sharedService.message;
  });        
}

function ControllerTwo($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'TWO: ' + sharedService.message;
  });
}

ControllerZero.$inject = ['$scope', 'mySharedService'];        

ControllerOne.$inject = ['$scope', 'mySharedService'];

ControllerTwo.$inject = ['$scope', 'mySharedService'];
121
adardesign

Hier ist ein einseitiges Beispiel für zwei Controller, die Dienstdaten gemeinsam nutzen:

<!doctype html>
<html ng-app="project">
<head>
    <title>Angular: Service example</title>
    <script src="http://code.angularjs.org/angular-1.0.1.js"></script>
    <script>
var projectModule = angular.module('project',[]);

projectModule.factory('theService', function() {  
    return {
        thing : {
            x : 100
        }
    };
});

function FirstCtrl($scope, theService) {
    $scope.thing = theService.thing;
    $scope.name = "First Controller";
}

function SecondCtrl($scope, theService) {   
    $scope.someThing = theService.thing; 
    $scope.name = "Second Controller!";
}
    </script>
</head>
<body>  
    <div ng-controller="FirstCtrl">
        <h2>{{name}}</h2>
        <input ng-model="thing.x"/>         
    </div>

    <div ng-controller="SecondCtrl">
        <h2>{{name}}</h2>
        <input ng-model="someThing.x"/>             
    </div>
</body>
</html>

Auch hier: https://Gist.github.com/3595424

52
exclsr

Wenn Sie einen Controller in einen anderen aufrufen möchten, stehen vier Methoden zur Verfügung

  1. $ rootScope. $ emit () und $ rootScope. $ broadcast ()
  2. Wenn der zweite Controller untergeordnet ist, können Sie die übergeordnete untergeordnete Kommunikation verwenden.
  3. Verwenden Sie Dienste
  4. Art von Hack - mit Hilfe von angular.element ()

1. $ rootScope. $ Emit () und $ rootScope. $ Broadcast ()

Der Controller und sein Bereich können zerstört werden, aber das $ rootScope bleibt in der gesamten Anwendung erhalten. Aus diesem Grund verwenden wir das $ rootScope, da das $ rootScope allen Bereichen übergeordnet ist.

Wenn Sie eine Kommunikation von Eltern zu Kindern durchführen und sogar Kinder mit ihren Geschwistern kommunizieren möchten, können Sie $ broadcast verwenden

Wenn Sie eine Kommunikation von einem Kind zu einem Elternteil durchführen, an der keine Geschwister beteiligt sind, können Sie $ rootScope. $ Emit verwenden

HTML

<body ng-app="myApp">
    <div ng-controller="ParentCtrl" class="ng-scope">
      // ParentCtrl
      <div ng-controller="Sibling1" class="ng-scope">
        // Sibling first controller
      </div>
      <div ng-controller="Sibling2" class="ng-scope">
        // Sibling Second controller
        <div ng-controller="Child" class="ng-scope">
          // Child controller
        </div>
      </div>
    </div>
</body>

Angularjs Code

 var app =  angular.module('myApp',[]);//We will use it throughout the example 
    app.controller('Child', function($rootScope) {
      $rootScope.$emit('childEmit', 'Child calling parent');
      $rootScope.$broadcast('siblingAndParent');
    });

app.controller('Sibling1', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling one');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('Sibling2', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling two');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('ParentCtrl', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside parent controller');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

In der obigen Codekonsole von $ emit ruft 'childEmit' nicht innerhalb von untergeordneten Geschwistern auf, und es ruft nur innerhalb von übergeordneten Geschwistern auf, wobei $ broadcast auch innerhalb von übergeordneten Geschwistern aufgerufen wird Dies ist vorzuziehen, wenn Sie die Kommunikation von Kind zu Eltern verwenden, da einige Dirty Checks übersprungen werden.

2. Wenn der zweite Controller untergeordnet ist, können Sie die Child Parent-Kommunikation verwenden

Es ist eine der besten Methoden. Wenn Sie Kommunikation mit untergeordneten Eltern ausführen möchten, mit der das Kind kommunizieren möchte direkte Eltern, dann würde es keine Art von $ broadcast oder $ emit benötigen, aber Wenn Sie von einem Elternteil zu einem anderen Kind kommunizieren möchten, müssen Sie entweder service oder $ broadcast verwenden

Zum Beispiel HTML: -

<div ng-controller="ParentCtrl">
 <div ng-controller="ChildCtrl">
 </div>
</div>

Angularjs

 app.controller('ParentCtrl', function($scope) {
   $scope.value='Its parent';
      });
  app.controller('ChildCtrl', function($scope) {
   console.log($scope.value);
  });

Wenn Sie die Kommunikation von Kind zu Eltern verwenden, sucht Angularjs nach einer Variablen innerhalb des Kindes. Wenn diese Variable nicht innerhalb des Kindes vorhanden ist, werden die Werte innerhalb des Eltern-Controllers angezeigt.

.Use Services

AngularJS unterstützt die Konzepte der "Trennung von Bedenken" unter Verwendung der Dienstarchitektur. Dienste sind Javascript-Funktionen und sind nur für bestimmte Aufgaben verantwortlich. Dies macht sie zu einer individuellen Entität, die wartbar und testbar. Dienste, die zum Injizieren unter Verwendung des Abhängigkeitsinjektionsmechanismus von Angularjs verwendet werden .

Angularjs Code:

app.service('communicate',function(){
  this.communicateValue='Hello';
});

app.controller('ParentCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Parent World");
});

app.controller('ChildCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Child World");
});

Es werden die Ausgaben Hello Child World und Hello Parent World ausgegeben. Nach Angular Servicedokumenten Singletons - Jede von einem Service abhängige Komponente erhält eine Referenz auf die von der Service Factory generierte Einzelinstanz .

4. Art des Hacks - mit Hilfe von angle.element ()

Diese Methode ruft scope () vom Element ab, indem ihre ID/unique class.angular.element () -Methode element zurückgibt, und scope () gibt die Variable $ scope einer anderen Variablen zurück, wobei die Variable $ scope eines Controllers in einem anderen Controller nicht empfohlen wird.

HTML: -

<div id='parent' ng-controller='ParentCtrl'>{{varParent}}
 <span ng-click='getValueFromChild()'>Click to get ValueFormChild</span>
 <div id='child' ng-controller='childCtrl'>{{varChild}}
   <span ng-click='getValueFromParent()'>Click to get ValueFormParent </span>
 </div>
</div>

Winkel: -

app.controller('ParentCtrl',function($scope){
 $scope.varParent="Hello Parent";
  $scope.getValueFromChild=function(){
  var childScope=angular.element('#child').scope();
  console.log(childScope.varChild);
  }
});

app.controller('ChildCtrl',function($scope){
 $scope.varChild="Hello Child";
  $scope.getValueFromParent=function(){
  var parentScope=angular.element('#parent').scope();
  console.log(parentScope.varParent);
  }
}); 

In obigem Code zeigen Controller ihren eigenen Wert in HTML an. Wenn Sie auf Text klicken, werden die entsprechenden Werte in der Konsole angezeigt. Wenn Sie auf die Spanne der übergeordneten Controller klicken, zeigt der Browser den Wert von child und umgekehrt an.

51
Shubham Nigam

Wenn Sie Ereignisse senden und senden möchten, um Daten auszutauschen oder Funktionen zwischen Controllern aufzurufen , lesen Sie bitte diese Link : und Überprüfen Sie die Antwort mit zbynour (Antwort mit maximaler Stimmenzahl). Ich zitiere seine Antwort !!!

Wenn der Bereich von firstCtrl dem Bereich von secondCtrl übergeordnet ist, sollte Ihr Code funktionieren, indem Sie in firstCtrl $ emit durch $ broadcast ersetzen:

function firstCtrl($scope){
    $scope.$broadcast('someEvent', [1,2,3]);
}

function secondCtrl($scope){
    $scope.$on('someEvent', function(event, mass) {console.log(mass)});
}

Falls zwischen Ihren Gültigkeitsbereichen keine Parent-Child-Beziehung besteht, können Sie $ rootScope in den Controller einfügen und das Ereignis an alle untergeordneten Gültigkeitsbereiche senden (dh auch secondCtrl).

function firstCtrl($rootScope){
    $rootScope.$broadcast('someEvent', [1,2,3]);
}

Schließlich können Sie $ scope. $ Emit verwenden, wenn Sie das Ereignis vom untergeordneten Controller nach oben auslösen müssen. Wenn der Bereich von firstCtrl übergeordnet zum Bereich von secondCtrl ist:

function firstCtrl($scope){
    $scope.$on('someEvent', function(event, data) { console.log(data); });
}

function secondCtrl($scope){
    $scope.$emit('someEvent', [1,2,3]);
}
32
SharpCoder

Zwei weitere Geigen: (Non-Service-Ansatz)

1) Für Eltern-Kind-Controller - Verwenden von $scope des Eltern-Controllers zum Aussenden/Senden von Ereignissen. http://jsfiddle.net/laan_sachin/jnj6y/

2) Verwenden von $rootScope auf nicht verwandten Controllern. http://jsfiddle.net/VxafF/

24
DarkKnight

Die tatsächliche Verwendung von "Senden" und "Senden" ist ineffizient, da das Ereignis in der Bereichshierarchie auf und ab sprudelt, was bei einer komplexen Anwendung leicht zu Leistungseinbußen führen kann.

Ich würde vorschlagen, einen Dienst zu nutzen. So habe ich es kürzlich in einem meiner Projekte implementiert - https://Gist.github.com/3384419 .

Grundidee - einen Pub-Sub/Event-Bus als Service registrieren. Dann fügen Sie diesen Event-Bus ein, wo immer Sie Ereignisse/Themen abonnieren oder veröffentlichen müssen.

16
numan salati

Ich weiß nicht, ob dies nicht den Standards entspricht, aber wenn Sie alle Controller in derselben Datei haben, können Sie Folgendes tun:

app = angular.module('dashboardBuzzAdmin', ['ngResource', 'ui.bootstrap']);

var indicatorsCtrl;
var perdiosCtrl;
var finesCtrl;

app.controller('IndicatorsCtrl', ['$scope', '$http', function ($scope, $http) {
  indicatorsCtrl = this;
  this.updateCharts = function () {
    finesCtrl.updateChart();
    periodsCtrl.updateChart();
  };
}]);

app.controller('periodsCtrl', ['$scope', '$http', function ($scope, $http) {
  periodsCtrl = this;
  this.updateChart = function() {...}
}]);

app.controller('FinesCtrl', ['$scope', '$http', function ($scope, $http) {
  finesCtrl = this;
  this.updateChart = function() {...}
}]);

Wie Sie sehen, ruft indicatorStrl beim Aufruf von updateCharts die updateChart-Funktionen der beiden anderen Controller auf.

3
tomascharad

Ich kenne auch diesen Weg.

angular.element($('#__userProfile')).scope().close();

Aber ich benutze es nicht zu oft, weil ich jQuery-Selektoren nicht gerne in angular Code verwende.

3
Andrey Korchak

Es gibt eine Methode, die nicht von Diensten abhängig ist, $broadcast oder $emit. Es ist nicht in allen Fällen geeignet, aber wenn Sie zwei verwandte Controller haben, die in Direktiven abstrahiert werden können, können Sie die Option require in der Direktivendefinition verwenden. So kommunizieren ngModel und ngForm höchstwahrscheinlich. Sie können dies verwenden, um zwischen Direktiven-Controllern zu kommunizieren, die entweder verschachtelt sind oder sich auf demselben Element befinden.

Für eine Eltern/Kind-Situation wäre die Verwendung wie folgt:

<div parent-directive>
  <div inner-directive></div>
</div>

Und die wichtigsten Punkte, um es zum Laufen zu bringen: In der übergeordneten Direktive sollten Sie die aufzurufenden Methoden in this definieren (nicht in $scope):

controller: function($scope) {
  this.publicMethodOnParentDirective = function() {
    // Do something
  }
}

In der Definition der untergeordneten Direktive können Sie die Option require verwenden, damit der übergeordnete Controller an die Verknüpfungsfunktion übergeben wird (damit Sie Funktionen in der Anweisung scope der untergeordneten Direktive aufrufen können.

require: '^parentDirective',
template: '<span ng-click="onClick()">Click on this to call parent directive</span>',
link: function link(scope, iElement, iAttrs, parentController) {
  scope.onClick = function() {
    parentController.publicMethodOnParentDirective();
  }
}

Die oben genannten Informationen finden Sie unter http://plnkr.co/edit/poeq460VmQER8Gl9w8Oz?p=preview

Eine Geschwister-Direktive wird ähnlich verwendet, aber beide Direktiven betreffen dasselbe Element:

<div directive1 directive2>
</div>

Wird beim Erstellen einer Methode für directive1 verwendet:

controller: function($scope) {
  this.publicMethod = function() {
    // Do something
  }
}

Und in Direktive2 kann dies mit der Option require aufgerufen werden, was dazu führt, dass der siblingController an die Link-Funktion übergeben wird:

require: 'directive1',
template: '<span ng-click="onClick()">Click on this to call sibling directive1</span>',
link: function link(scope, iElement, iAttrs, siblingController) {
  scope.onClick = function() {
    siblingController.publicMethod();
  }
}

Dies ist zu sehen unter http://plnkr.co/edit/MUD2snf9zvadfnDXq85w?p=preview .

Die Verwendung von diesem?

  • Übergeordnet: Jeder Fall, in dem sich untergeordnete Elemente bei einem übergeordneten Element "registrieren" müssen. Ähnlich wie die Beziehung zwischen ngModel und ngForm. Hierdurch kann ein bestimmtes Verhalten hinzugefügt werden, das sich auf Modelle auswirken kann. Möglicherweise haben Sie auch ein rein DOM-basiertes Element, bei dem ein übergeordnetes Element die Positionen bestimmter untergeordneter Elemente verwalten muss, um beispielsweise das Scrollen zu verwalten oder darauf zu reagieren.

  • Geschwister: Zulassen, dass das Verhalten einer Richtlinie geändert wird. ngModel ist der klassische Fall, um Parser/Validierung zur Verwendung von ngModel für Eingaben hinzuzufügen.

2
Michal Charemza

Sie können den Dienst '$ controller' in Ihren übergeordneten Controller (MessageCtrl) einfügen und dann den untergeordneten Controller (DateCtrl) instanziieren/einfügen, indem Sie Folgendes verwenden:
$scope.childController = $controller('childController', { $scope: $scope.$new() });

Jetzt können Sie auf Daten von Ihrem untergeordneten Controller zugreifen, indem Sie dessen Methoden aufrufen, da es sich um einen Dienst handelt.
Lass es mich wissen, wenn es ein Problem gibt.

2

Es folgt ein publish-subscribe Ansatz, der unabhängig von Angular JS ist.

Search Param Controller

//Note: Multiple entities publish the same event
regionButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'region');
},

plantButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'plant');
},

Search Choices Controller

//Note: It subscribes for the 'onSearchParamSelectedEvent' published by the Search Param Controller
localSubscribe: function () {
        EM.on('onSearchParamSelectedEvent', this.loadChoicesView, this);

});


loadChoicesView: function (e) {

        //Get the entity name from eData attribute which was set in the event manager
        var entity = $(e.target).attr('eData');

        console.log(entity);

        currentSelectedEntity = entity;
        if (entity == 'region') {
            $('.getvalue').hide();
            this.loadRegionsView();
            this.collapseEntities();
        }
        else if (entity == 'plant') {
            $('.getvalue').hide();
            this.loadPlantsView();
            this.collapseEntities();
        }


});

Event Manager

myBase.EventManager = {

    eventArray:new Array(),


    on: function(event, handler, exchangeId) {
        var idArray;
        if (this.eventArray[event] == null) {
            idArray = new Array();
        } else { 
            idArray = this.eventArray[event];
        }
        idArray.Push(exchangeId);
        this.eventArray[event] = idArray;

        //Binding using jQuery
        $(exchangeId).bind(event, handler);
    },

    un: function(event, handler, exchangeId) {

        if (this.eventArray[event] != null) {
            var idArray = this.eventArray[event];
            idArray.pop(exchangeId);
            this.eventArray[event] = idArray;

            $(exchangeId).unbind(event, handler);
        }
    },

    fireEvent: function(event, info) {
        var ids = this.eventArray[event];

        for (idindex = 0; idindex < ids.length; idindex++) {
            if (ids[idindex]) {

                //Add attribute eData
                $(ids[idindex]).attr('eData', info);
                $(ids[idindex]).trigger(event);
            }
        }
    }
};

Global

var EM = myBase.EventManager;
1
Lijo

In angular 1.5 kann dies folgendermaßen erreicht werden:

(function() {
  'use strict';

  angular
    .module('app')
    .component('parentComponent',{
      bindings: {},
      templateUrl: '/templates/products/product.html',
      controller: 'ProductCtrl as vm'
    });

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

  function ProductCtrl() {
    var vm = this;
    vm.openAccordion = false;

    // Capture stuff from each of the product forms
    vm.productForms = [{}];

    vm.addNewForm = function() {
      vm.productForms.Push({});
    }
  }

}());

Dies ist die übergeordnete Komponente. In diesem habe ich eine Funktion erstellt, die ein anderes Objekt in mein productForms Array schiebt - Anmerkung - dies ist nur mein Beispiel, diese Funktion kann wirklich alles sein.

Jetzt können wir eine weitere Komponente erstellen, die require verwendet:

(function() {
  'use strict';

  angular
    .module('app')
    .component('childComponent', {
      bindings: {},
      require: {
        parent: '^parentComponent'
      },
      templateUrl: '/templates/products/product-form.html',
      controller: 'ProductFormCtrl as vm'
    });

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

  function ProductFormCtrl() {
    var vm = this;

    // Initialization - make use of the parent controllers function
    vm.$onInit = function() {
      vm.addNewForm = vm.parent.addNewForm;
    };  
  }

}());

Hier erstellt die untergeordnete Komponente einen Verweis auf die übergeordnete Komponentenfunktion addNewForm, die dann an den HTML-Code gebunden und wie jede andere Funktion aufgerufen werden kann.

1
Katana24