AngularJS. Jak wywołać funkcję kontrolera spoza komponentu kontrolera

Jak mogę wywołać funkcję zdefiniowaną pod controllerem z dowolnego miejsca strony www (poza komponentem controller)?

Działa idealnie, gdy naciskam przycisk "get". Ale muszę zadzwonić spoza kontrolera div. Logika jest taka: domyślnie mój div jest ukryty. Gdzieś w menu nawigacyjnym naciskam przycisk i powinien pokazać () mój div I wykonać funkcję "get". Jak mogę to osiągnąć?

Moja strona to:

<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>

Moje 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
Author: Whitecat, 2013-05-23

9 answers

Oto sposób wywołania funkcji kontrolera z zewnątrz:

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

Gdzie get() jest funkcją kontrolera.

You can switch

document.getElementById('yourControllerElementID')` 

Do

$('#yourControllerElementID')

Jeśli używasz jQuery.

Również, jeśli twoja funkcja oznacza zmianę czegokolwiek w widoku, powinieneś wywołać

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

Aby zastosować zmiany.

Jeszcze jedno, należy zauważyć, że zakresy są inicjalizowane po załadowaniu strony, więc wywołanie metod spoza zakres powinien być zawsze wykonywany po załadowaniu strony. W przeciwnym razie nie dotrzesz do lunety.

UPDATE:

Z najnowszymi wersjami angular, należy użyć

angular.element(document.getElementById('yourControllerElementID')).injector().‌​get('$rootScope')
I tak, to jest, w rzeczywistości, {23]}zła praktyka {24]}, ale czasami po prostu trzeba zrobić rzeczy szybko i brudne.
 306
Author: Dmitry Mina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-20 10:06:02

Znalazłem przykład w Internecie.

Jakiś facet napisał ten kod i zadziałał idealnie

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);
    });
}

Demo

*zrobiłem kilka modyfikacji, zobacz oryginał: font JSfiddle

 36
Author: Roger Ramos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-16 02:12:25

Odpowiedź Dmitrija działa dobrze. Zrobiłem prosty przykład używając tej samej techniki.

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
Author: Razan Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 23:03:26

Wolałbym włączyć fabrykę jako zależności od kontrolerów niż wstrzyknąć im własną linię kodu: http://jsfiddle.net/XqDxG/550/

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

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

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

 7
Author: getsetbro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-20 16:28:36

Rozwiązanie angular.element(document.getElementById('ID')).scope().get() przestał działać dla mnie w angular 1.5.2. Sombody wspomnieć w komentarzu, że to nie działa w 1.4.9 również. Poprawiłem go przechowując zakres w zmiennej globalnej:

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

Wywołanie z kodu niestandardowego:

scopeHolder.bar()

Jeśli chcesz ograniczyć zakres Tylko do tej metody. Aby zminimalizować ekspozycję całego zakresu. użyj następującej techniki.

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

Wywołanie z kodu niestandardowego:

scopeHolder()
 7
Author: user1121883,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-07 10:58:49

Warto zastanowić się, czy posiadanie menu bez powiązanego zakresu jest dobrym rozwiązaniem. To nie jest kanciasta droga.

Ale, jeśli jest to droga, którą musisz iść, możesz to zrobić, dodając funkcje do $rootScope, a następnie wewnątrz tych funkcji używając $broadcast do wysyłania zdarzeń. następnie twój kontroler używa $on do nasłuchiwania tych zdarzeń.

Kolejną rzeczą do rozważenia, jeśli skończysz z menu bez zakresu jest to, że jeśli masz wiele tras, to wszystkie kontrolery będą musiały posiadać własne funkcje upate I get. (zakładając, że masz wiele kontrolerów)

 4
Author: Anton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-23 09:14:16

Używam do pracy z $http, gdy chcesz uzyskać jakieś informacje z zasobu wykonuję następujące czynności:

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);
    }}
    });

Oraz kod w kontrolerze:

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);
    }
}

Wysyłam do serwisu jaką funkcję należy wywołać w kontrolerze

 4
Author: rodrimmb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-11 09:41:37

Mam wiele tras i wiele kontrolerów, więc nie mogłem uzyskać zaakceptowanej odpowiedzi do pracy. Okazało się, że dodanie funkcji do okna działa:

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;

}

Wtedy poza kontrolerem można to zrobić:

function ElsewhereOnThePage() {
    if (typeof(fooreinit) == 'function') { fooreinit(); }
}
 3
Author: jaybro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-18 21:21:07

Jestem użytkownikiem Ionic framework i znalazłem ten, który konsekwentnie dostarcza bieżącego kontrolera $scope:

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

Podejrzewam, że można to zmodyfikować tak, aby pasowało do większości scenariuszy niezależnie od frameworka (lub nie), znajdując zapytanie, które będzie kierowane do określonych elementów DOM, które są dostępne tylko podczas danej instancji kontrolera.

 0
Author: Matt Ray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-24 15:10:17