AngularJS. Como chamar a function do controlador de fora do componente do controlador

Como posso chamar a function definida sob o controlador de qualquer local da página da web (fora do componente do controlador)?

Funciona perfeitamente quando pressiono o botão “get”. Mas eu preciso chamá-lo de fora do controlador div. A lógica é: por padrão, meu div está oculto. Em algum lugar no menu de navegação eu pressiono um botão e ele deve mostrar () meu div e executar a function “get”. Como posso conseguir isso?

Minha página da web é:

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

Aqui está uma maneira de chamar a function do controlador de fora dele:

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

onde get() é uma function do seu controlador.

Você pode trocar

 document.getElementById('yourControllerElementID')` 

para

 $('#yourControllerElementID') 

Se você estiver usando o jQuery.

Além disso, se a sua function significa mudar alguma coisa na sua Visualização, você deve ligar

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

para aplicar as alterações.

Só mais uma coisa, você deve notar é que os escopos são inicializados após a página ser carregada, então os methods de chamada de fora do escopo devem sempre ser feitos após a página ser carregada. Senão você não vai chegar ao escopo em tudo.

ATUALIZAR:

Com as versões mais recentes de angular, você deve usar

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

E sim, isso é, de fato, uma prática ruim , mas às vezes você só precisa de coisas rápidas e sujas.

Eu encontrei um exemplo na internet.

Um cara escreveu esse código e trabalhou perfeitamente

HTML

 
Exposing Controller Function outside the module via onClick function call




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

Demonstração

* Fiz algumas modificações, veja original: fonte JSfiddle

A resposta de Dmitry funciona bem. Acabei de fazer um exemplo simples usando a mesma técnica.

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

  

.

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

Eu preferiria include a fábrica como dependencies nos controladores do que injetá-los com sua própria linha de código: 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’];

A solução angular.element(document.getElementById('ID')).scope().get() parou de funcionar para mim em 1.5.2 angular. Sombody menciona em um comentário que isso não funciona em 1.4.9 também. Eu corrigi-lo, armazenando o escopo em uma variável global:

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

chamada do código personalizado:

 scopeHolder.bar() 

se você quiser restringir o escopo apenas a este método. Minimizar a exposição de todo o escopo. use a seguinte técnica.

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

chamada do código personalizado:

 scopeHolder() 

Pode valer a pena considerar se ter seu menu sem qualquer escopo associado é o caminho certo a seguir. Não é realmente o caminho angular.

Mas, se for a maneira que você precisa ir, então você pode fazê-lo adicionando as funções a $ rootScope e dentro dessas funções usando $ broadcast para enviar events. seu controlador então usa $ on para ouvir esses events.

Outra coisa a considerar se você acabar tendo o seu menu sem um escopo é que se você tem múltiplas rotas, então todos os seus controladores terão que ter suas próprias funções de upate e get. (isto presumindo que você tenha vários controladores)

Eu uso para trabalhar com $ http, quando quero obter algumas informações de um recurso eu faço o seguinte:

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

E o código no controlador:

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

Eu envio para o serviço que function tem que chamar no controlador

Tenho várias rotas e vários controladores, por isso não consegui que a resposta aceite funcionasse. Eu achei que adicionando a function para a janela funciona:

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

Então fora do controlador, isso pode ser feito:

 function ElsewhereOnThePage() { if (typeof(fooreinit) == 'function') { fooreinit(); } } 

Eu sou um usuário de estrutura iônica e o que eu encontrei que forneceria consistentemente o escopo $ do controlador atual é:

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

Eu suspeito que isso pode ser modificado para caber a maioria dos cenários, independentemente do quadro (ou não), encontrando a consulta que irá direcionar os elementos DOM específicos que estão disponíveis apenas durante uma determinada instância do controlador.