2013-05-23 3 views
163

Как я могу вызывать функцию, определенную под контроллером, из любого места веб-страницы (вне компонента контроллера)?AngularJS. Как вызвать функцию контроллера извне компонента контроллера

Он отлично работает, когда я нажимаю кнопку «получить». Но мне нужно вызвать его из-за пределов контроллера div. Логика такова: по умолчанию мой div скрыт. Где-то в меню навигации я нажимаю кнопку, и она должна показывать() мой div и выполнять функцию «получить». Как я могу это достичь?

Моя веб-страница:

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

Мои ЯШ:

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

Когда вы говорите «... где-то в меню навигации вы нажимаете кнопку ...», вы хотите сказать, что эта навигация является частью другого контроллера, и вы хотите вызвать 'get()' MyController из другой контроллер? – callmekatootie

+1

На данный момент меню навигации не является контроллером. Просто html. Не уверен, что его можно вызвать функцию контроллера из html/javascript, вот почему я разместил этот вопрос. Но да, логично сделать меню навигации отдельным контроллером. Как я могу вызвать функцию MyController.get() из NavigationMenu.Controller? –

ответ

290

Вот способ вызова функции контроллера из за его пределами:

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

где get() является функцией от контроллера.

Вы можете переключить

document.getElementById('yourControllerElementID')` 

в

$('#yourControllerElementID') 

Если вы используете JQuery.

Кроме того, если ваша функция означает, что-нибудь на ваш взгляд изменения, вы должны вызвать

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

, чтобы применить изменения.

Еще одна вещь, вы должны отметить, что области запускаются после загрузки страницы, поэтому вызов методов из-за пределов видимости всегда должен выполняться после загрузки страницы. Иначе вы вообще не попадете в сферу действия.

UPDATE:

С последними версиями угловатый, вы должны использовать

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

И да, это, по сути, плохая практика, но иногда вам просто нужны вещи сделано быстро и грязно.

+30

Это похоже на запах кода, поскольку философия Angular не должна смешивать DOM-код с угловым кодом. .. – JoeCool

+8

, так что если вы не должны смешивать код DOM с угловым кодом, если вы хотите, чтобы некоторые анимации JQuery запускались в ответ на переменное изменение в вашем угловом контроллере - как именно вы это делаете? Это было бы тривиально делать с контроллера, но я понятия не имею, как это сделать чисто. – Jan

+3

Я не мог заставить часть $ $ apply работать для меня, пока я не завернул код в функцию, например. '... scope. $ apply (function() {scope.get()});' – surfitscrollit

4

Может быть, стоит обратить внимание, если с вашего меню без каких-либо связанного рамки является правильный путь. На самом деле это не угловой путь.

Но если это так, как вам нужно, вы можете сделать это, добавив функции в $ rootScope, а затем в те функции, используя $ broadcast для отправки событий. ваш контроллер затем использует $ on для прослушивания этих событий.

Еще одна вещь, которую следует учитывать, если у вас есть меню без области видимости, заключается в том, что если у вас несколько маршрутов, все ваши контроллеры должны будут иметь свои собственные функции и получить функции. (Это если у вас есть несколько контроллеров)

+0

вы можете дать простой пример того, как вызвать функцию .get() ControllerOne из ControllerTwo? моя логика заключается в том, что каждый контроллер будет иметь свои собственные функции .get() .update(). У меня будет MainMenuController, из которого мне нужно выполнить (в соответствии с пунктом меню) .get() необходимого контроллера. –

+1

http://jsfiddle.net/simpulton/XqDxG/ – Anton

+0

ps, ​​а не мой код, но он показывает, как использовать функции управления несколькими контроллерами. – Anton

6

Я предпочел бы включать в себя завод в качестве зависимостей от контроллеров, чем инъекционные их с их собственной линии кода: http://jsfiddle.net/XqDxG/550/

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

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

ControllerZero $ впрыснуть = [ '$ объем', 'mySharedService'];.

+0

Хм. @ Антон прокомментировал скрипку ниже (в мае 13), которая делает ОБА. –

3

Я использую для работы с $ HTTP, когда хотят получить какую-то информацию от ресурса я делаю следующее:

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

И код в контроллере:

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

I отправьте на службу какую функцию нужно вызвать в контроллере

35

Я нашел пример в Интернете.

Какой-то парень написал этот код и работал отлично

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

* Я сделал некоторые изменения, см. Оригинал: шрифт JSfiddle

+2

Спасибо, Роджер, очень полезно! – Eduardo

+0

Работа с устаревшей библиотекой проверки jQuery, которая ДОЛЖНА использоваться. Итак, это либо 1: переписать библиотеку, 2: создать директиву для обертывания библиотеки, 3: 2 строки кода, чтобы вызвать угловую подачу, когда она действительна ... –

+0

, если я не использую применить, тогда функция, которая будет обновлять данные просмотра, будет не отражаются? –

7

Ответ Дмитрия отлично работает. Я просто сделал простой пример, используя ту же технику.

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

У меня есть несколько маршрутов и несколько контроллеров, поэтому я не смог получить принятый ответ на работу. Я обнаружил, что добавление функции в окне работы:

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; 

} 

Тогда вне контроллера, это можно сделать:

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

Решение angular.element(document.getElementById('ID')).scope().get() перестал работать для меня в угловой 1.5.2. Sombody упоминает в комментарии, что это тоже не работает в 1.4.9. Я установил ее, сохраняя объем в глобальном переменном:

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

вызова из пользовательского кода:

scopeHolder.bar() 

если вы хотите ограничить область применения только этот метод. Чтобы свести к минимуму воздействие всего объема. использование следующий technique.

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

вызова из пользовательского кода:

scopeHolder() 
+0

Это отлично подойдет для меня (даже изнутри компонента). Есть ли недостаток, чтобы сделать это иначе, чем просто «плохая практика, чтобы называть угловые вещи из-за угла», которые я не могу избежать в своем сценарии? http://stackoverflow.com/questions/42123120/how-to-call-a-function-inside-an-angular-component-triggered-by-jquery-events/ – RichC

0

Я основа пользователя Ионные и один я обнаружил, что будет постоянно обеспечивать $ объем текущего контроллера является:

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

Я подозреваю, что это может быть изменено, чтобы соответствовать большинству сценариев, независимо от структуры (или нет), путем поиска запроса, который будет нацелен на конкретные элементы (элементы) DOM, которые доступны только во время данного экземпляра контроллера.

Смежные вопросы