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){ }
});
};
}
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();
où 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.
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);
});
}
*j'ai fait quelques modifications, voir l'original: "police de la 1519190920" JSfiddle
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 ;
}
}
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'];
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()
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)
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
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(); }
}
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.