J'ai un service qui fait une demande AJAX au backend
Un service:
function GetCompaniesService(options)
{
this.url = '/company';
this.Companies = undefined;
this.CompaniesPromise = $http.get(this.url);
}
Manette:
var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(data){
$scope.Companies = data;
});
Je veux que mon service gère la fonction ".then" au lieu de devoir la gérer dans mon contrôleur, et je veux pouvoir faire en sorte que mon contrôleur agisse sur ces données du service, après que la promesse à l'intérieur du service a été résolue.
Fondamentalement, je veux pouvoir accéder aux données comme ceci:
var CompaniesOb = new GetCompanies();
$scope.Companies = CompaniesOb.Companies;
La résolution de la promesse étant gérée à l'intérieur du service lui-même.
Est-ce possible? Ou est-ce que la seule façon d'accéder à la résolution de cette promesse est de l'extérieur du service?
Si tout ce que vous voulez, c'est gérer la réponse de $http
dans le service lui-même, vous pouvez ajouter une fonction then
au service où vous effectuez plus de traitement que return
à partir de cette fonction then
, comme ceci:
function GetCompaniesService(options) {
this.url = '/company';
this.Companies = undefined;
this.CompaniesPromise = $http.get(this.url).then(function(response) {
/* handle response then */
return response
})
}
Mais vous devrez toujours utiliser une promesse dans le contrôleur, mais ce que vous récupérez aura déjà été traité dans le service.
var CompaniesOb = new GetCompanies();
CompaniesOb.CompaniesPromise.then(function(dataAlreadyHandledInService) {
$scope.Companies = dataAlreadyHandledInService;
});
Il n'y a aucun problème pour y parvenir!
La principale chose que vous devez garder à l'esprit est que vous devez conserver la même référence d'objet (et dans les tableaux javascript sont des objets) dans votre service.
voici notre HTML simple:
<div ng-controller = "companiesCtrl">
<ul ng-repeat="company in companies">
<li>{{company}}</li>
</ul>
</div>
Voici notre implémentation de service:
serviceDataCaching.service('companiesSrv', ['$timeout', function($timeout){
var self = this;
var httpResult = [
'company 1',
'company 2',
'company 3'
];
this.companies = ['preloaded company'];
this.getCompanies = function() {
// we simulate an async operation
return $timeout(function(){
// keep the array object reference!!
self.companies.splice(0, self.companies.length);
// if you use the following code:
// self.companies = [];
// the controller will loose the reference to the array object as we are creating an new one
// as a result it will no longer get the changes made here!
for(var i=0; i< httpResult.length; i++){
self.companies.Push(httpResult[i]);
}
return self.companies;
}, 3000);
}}]);
Et enfin le contrôleur comme vous le vouliez:
serviceDataCaching.controller('companiesCtrl', function ($scope, companiesSrv) {
$scope.companies = companiesSrv.companies;
companiesSrv.getCompanies();
});
Explications
Comme indiqué ci-dessus, l'astuce consiste à conserver la référence entre le service et le contrôleur. Une fois que vous respectez cela, vous pouvez lier totalement la portée de votre contrôleur sur une propriété publique de votre service.
Voici un violon qui l'enveloppe.
Dans les commentaires du code, vous pouvez essayer de décommenter la pièce qui ne fonctionne pas et vous verrez comment le contrôleur perd la référence. En fait, le contrôleur conservera une référence à l'ancienne baie tandis que le service changera la nouvelle.
Une dernière chose importante: gardez à l'esprit que le timeout $ déclenche un $ apply () sur le rootSCope. C'est pourquoi la portée de notre contrôleur est rafraîchissante "seule". Sans cela, et si vous essayez de le remplacer par un setTimeout () normal, vous verrez que le contrôleur ne met pas à jour la liste des sociétés. Pour contourner ce problème, vous pouvez:
J'espère que cela t'aides!