AngularJS. Comment appeler la fonction de contrôleur de l'extérieur du composant contrôleur

Comment puis-je appeler une fonction définie sous controller à partir d'une page web quelconque (en dehors du composant controller)?

ça marche parfaitement quand j'appuie sur le bouton" get". Mais je dois l'appeler de l'extérieur de div controller. La logique est: par défaut mon div est caché. Quelque part dans le menu de navigation, j'appuie sur un bouton et il devrait afficher() ma div et exécuter la fonction "get". Comment je peux faire?

ma page web est:

<div ng-controller="MyController">
  <input type="text" ng-model="data.firstname" required>
  <input type='text' ng-model="data.lastname" required>

  <form ng-submit="update()"><input type="submit" value="update"></form>
  <form ng-submit="get()"><input type="submit" value="get"></form>
</div>

Mon js:

   function MyController($scope) {
      // default data and structure
      $scope.data = {
        "firstname" : "Nicolas",
        "lastname" : "Cage"
      };

      $scope.get = function() {
        $.ajax({
           url: "/php/get_data.php?",
           type: "POST",
           timeout: 10000, // 10 seconds for getting result, otherwise error.
           error:function() { alert("Temporary error. Please try again...");},
           complete: function(){ $.unblockUI();},
           beforeSend: function(){ $.blockUI()},
           success: function(data){
            json_answer = eval('(' + data + ')');
            if (json_answer){
                $scope.$apply(function () {
                  $scope.data = json_answer;
            });
            }
        }
    });
  };

  $scope.update = function() {
    $.ajax({
        url: "/php/update_data.php?",
        type: "POST",
        data: $scope.data,
        timeout: 10000, // 10 seconds for getting result, otherwise error.
        error:function() { alert("Temporary error. Please try again...");},
        complete: function(){ $.unblockUI();},
        beforeSend: function(){ $.blockUI()},
        success: function(data){ }
      });
    };
   }
179
demandé sur Whitecat 2013-05-23 12:45:00

9 réponses

Voici une façon d'appeler la fonction du contrôleur de l'extérieur:

angular.element(document.getElementById('yourControllerElementID')).scope().get();

get() est une fonction de votre contrôleur.

vous pouvez changer

document.getElementById('yourControllerElementID')` 

à

$('#yourControllerElementID')

si vous utilisez jQuery.

aussi, si votre Fonction Signifie changer quoi que ce soit sur votre vue, vous devez appeler

angular.element(document.getElementById('yourControllerElementID')).scope().$apply();

pour l'application de la changement.

encore une chose, vous devriez noter que les portées sont initialisées après que la page est chargée, donc les méthodes d'appel de l'extérieur de la portée devraient toujours être faites après que la page est chargée. Sinon, vous n'obtiendrez pas à la portée de tous.

mise à jour:

avec les dernières versions d'angular, vous devez utiliser

angular.element(document.getElementById('yourControllerElementID')).injector().‌​get('$rootScope')

Et oui, c'est, en fait, une mauvaise pratique , mais parfois vous avez juste besoin de choses rapide et sale.

306
répondu Dmitry Mina 2016-06-20 10:06:02

j'ai trouvé un exemple sur internet.

un type a écrit ce code et a parfaitement fonctionné

HTML

<div ng-cloak ng-app="ManagerApp">
    <div id="MainWrap" class="container" ng-controller="ManagerCtrl">
       <span class="label label-info label-ext">Exposing Controller Function outside the module via onClick function call</span>
       <button onClick='ajaxResultPost("Update:Name:With:JOHN","accept",true);'>click me</button>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.data"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.type"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.res"></span>
       <br/>
       <input type="text" ng-model="sampletext" size="60">
       <br/>
    </div>
</div>

JAVASCRIPT

var angularApp = angular.module('ManagerApp', []);
angularApp.controller('ManagerCtrl', ['$scope', function ($scope) {

$scope.customParams = {};

$scope.updateCustomRequest = function (data, type, res) {
    $scope.customParams.data = data;
    $scope.customParams.type = type;
    $scope.customParams.res = res;
    $scope.sampletext = "input text: " + data;
};



}]);

function ajaxResultPost(data, type, res) {
    var scope = angular.element(document.getElementById("MainWrap")).scope();
    scope.$apply(function () {
    scope.updateCustomRequest(data, type, res);
    });
}

Démo

*j'ai fait quelques modifications, voir l'original: "police de la 1519190920" JSfiddle

36
répondu Roger Ramos 2018-07-16 02:12:25

la réponse de Dmitry fonctionne très bien. J'ai juste fait un exemple simple en utilisant la même technique.

jsfiddle: http://jsfiddle.net/o895a8n8/5 /

<button onclick="call()">Call Controller's method from outside</button>
<div  id="container" ng-app="" ng-controller="testController">
</div>

.

function call() {
    var scope = angular.element(document.getElementById('container')).scope();
      scope.$apply(function(){
        scope.msg = scope.msg + ' I am the newly addded message from the outside of the controller.';
    })
    alert(scope.returnHello());
}

function testController($scope) {
    $scope.msg = "Hello from a controller method.";
    $scope.returnHello = function() {
        return $scope.msg ; 
    }
}
11
répondu Razan Paul 2015-02-04 23:03:26

je préférerais inclure l'usine comme dépendances sur les contrôleurs que de leur injecter leur propre ligne de code: http://jsfiddle.net/XqDxG/550 /

myModule.factory('mySharedService', function($rootScope) {
    return sharedService = {thing:"value"};
});

function ControllerZero($scope, mySharedService) {
    $scope.thing = mySharedService.thing;

ControllerZero.$injecter = ['$champ', 'mySharedService'];

7
répondu getsetbro 2013-09-20 16:28:36

la solution angular.element(document.getElementById('ID')).scope().get() a cessé de travailler pour moi à l'angle 1.5.2. Quelqu'un mentionne dans un commentaire que cela ne fonctionne pas aussi en 1.4.9. Je l'ai fixé en stockant la portée dans une variable globale:

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope = function bar(){
        console.log("foo");        
    };
    scopeHolder = $scope;
})

appel de code personnalisé:

scopeHolder.bar()

si vous voulez limiter le champ d'application à cette seule méthode. Pour minimiser l'exposition de toute la portée. utilisez la technique suivante.

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope.bar = function(){
        console.log("foo");        
    };
    scopeHolder = $scope.bar;
})

appel du code personnalisé:

scopeHolder()
7
répondu user1121883 2017-06-07 10:58:49

il peut être intéressant de considérer si avoir votre menu sans aucune portée associée est la bonne façon d'aller. Ce n'est pas vraiment l'angulaire.

mais, si c'est la façon dont vous devez aller, alors vous pouvez le faire en ajoutant les fonctions à $rootScope et puis à l'intérieur de ces fonctions en utilisant $broadcast pour envoyer des événements. votre controller utilise alors $on pour écouter ces évènements.

une autre chose à considérer si vous finissez par avoir votre menu sans une portée est que si vous avez plusieurs routes, alors tous vos contrôleurs devront avoir leurs propres fonctions upate et get. (ceci suppose que vous avez plusieurs contrôleurs)

4
répondu Anton 2013-05-23 09:14:16

j'utilise pour travailler avec $http, quand je veux obtenir des informations à partir d'une ressource je fais ce qui suit:

angular.module('services.value', [])

.service('Value', function($http, $q) {

var URL = "http://localhost:8080/myWeb/rest/";

var valid = false;

return {
    isValid: valid,
    getIsValid: function(callback){
        return $http.get(URL + email+'/'+password, {cache: false})
                    .success(function(data){
            if(data === 'true'){ valid = true; }
        }).then(callback);
    }}
    });

et le code dans le contrôleur:

angular.module('controllers.value', ['services.value'])

.controller('ValueController', function($scope, Value) {
    $scope.obtainValue = function(){
        Value.getIsValid(function(){$scope.printValue();});
    }

    $scope.printValue = function(){
        console.log("Do it, and value is " Value.isValid);
    }
}

j'envoie au service quelle fonction doivent appeler dans le contrôleur

4
répondu rodrimmb 2014-04-11 09:41:37

j'ai plusieurs routes et plusieurs contrôleurs, donc je ne pouvais pas obtenir la réponse acceptée pour travailler. J'ai trouvé que l'ajout de la fonction à la fenêtre fonctionne:

fooModule.controller("fooViewModel", function ($scope, fooService, $http, $q, $routeParams, $window, $location, viewModelHelper, $interval) {
    $scope.initFoo = function () {
        // do angular stuff
    }
    var initialize = function () {
        $scope.initFoo();
    }

    initialize();

    window.fooreinit = initialize;

}

puis en dehors du contrôleur, cela peut être fait:

function ElsewhereOnThePage() {
    if (typeof(fooreinit) == 'function') { fooreinit(); }
}
3
répondu jaybro 2015-06-18 21:21:07

je suis un utilisateur de framework ionique et celui que j'ai trouvé qui fournirait systématiquement le $scope du contrôleur actuel est:

angular.element(document.querySelector('ion-view[nav-view="active"]')).scope()

je soupçonne que cela peut être modifié pour s'adapter à la plupart des scénarios indépendamment du framework (ou non) en trouvant la requête qui ciblera le(s) élément (s) DOM spécifique (s) qui sont disponibles seulement pendant une instance de contrôleur donnée.

0
répondu Matt Ray 2016-06-24 15:10:17