66 votes

Utilisation d'un chemin relatif pour un appel de service dans AngularJS

J'ai le code suivant, qui fonctionnait bien jusqu'à ce que je le déploie sur un serveur de test :

$scope.getUserList = function (userName) {
    $http({
        method: "get",
        url: "GetUserList",
        params: { userName: userName }
    }).
        success(function (data) {
            $scope.users = data;
        }).
        error(function () {
            alert("Error getting users.");

Le problème est que j'ai effectué un déploiement dans un répertoire virtuel et que l'appel ci-dessous tente de lancer GetUserList à partir de la racine du serveur. C'est logique, et je connais un certain nombre de façons de résoudre ce problème.

Ce que je voudrais savoir, c'est le droite pour référencer l'URL du service d'une manière qui soit portable et maintenable dans Angular.

105voto

Barnabas Kendall Points 2184

Je suggère d'utiliser une balise HTML de base dans l'en-tête, et de coder tous les chemins relatifs à cette balise. En ASP.NET, par exemple, vous pouvez obtenir une référence à la base de l'application, qui peut être ou ne pas être le chemin d'accès principal du site, donc l'utilisation d'une balise base est utile. Bonus : cela fonctionne également pour toutes les autres ressources.

Vous pouvez avoir un chemin de base comme ceci :

<base href="http://stackoverflow.com/application_root/" />

...et alors des liens comme "foo/bar.html" seront en fait /application_root/foo/bar.html.

Une autre approche que j'aime utiliser consiste à placer des liens nommés dans l'en-tête. J'ai souvent une racine d'API à un endroit et une racine de modèle de directive à un autre endroit. Dans l'en-tête, j'ajoute ensuite des balises comme celle-ci :

<link id="linkApiRoot" href="http://stackoverflow.com/application_root/api/"/>
<link id="linkTemplateRoot" href="http://stackoverflow.com/application_root/Content/Templates/"/>

... et ensuite utiliser $provide dans le module pour obtenir le lien href et l'exposer aux services et directives comme ceci :

angular.module("app.services", [])
    .config(["$provide", function ($provide) {
        $provide.value("apiRoot", $("#linkApiRoot").attr("href"));
    }]);

... et ensuite l'injecter dans un service comme celui-ci :

angular.module("app.services").factory("myAdminSvc", ["apiRoot", function (apiRoot) {
    var apiAdminRoot = apiRoot + "admin/";
    ...

Ce n'est que mon opinion. Faites la chose la moins complexe pour votre application.

28voto

jvandemo Points 2470

Je suggère de définir un module contenant une configuration globale que vous pouvez ensuite faire circuler dans votre application :

// Module specific configuration
angular.module('app.config')
  .value('app.config', {
    basePath: '/' // Set your base path here
  });

Vous pouvez ensuite y accéder de n'importe où dans votre application grâce à l'injection de dépendances d'AngularJS :

// Make sure your config is included in your module
angular.module('app', ['app.config']);

// Access your config e.g. in a controller
angular.module('app')
  .controller('TestCtrl', ['$scope','app.config', function($scope, config){

    // Use config base path to assemble url
    $scope.url = config.basePath + 'GetUserList';
    ...
  }]);

Lorsque le chemin de base change (par exemple, lorsque vous changez de serveur ou d'hôte), il vous suffit de le modifier dans votre configuration globale et le tour est joué.

13voto

Endless Points 1188

Je n'ai pas pu utiliser <base> puisque mon application a été créée dans une fenêtre popup de façon dynamique à partir d'une autre origine. J'ai envisagé l'autre option dans ce fil de discussion d'utiliser quelque chose comme une variable basePath et de l'utiliser dans chaque balise $http, ng-src, templateUrl etc.

Mais c'était un peu surchargé, j'ai construit un intercepteur qui change chaque url avant qu'une xhr soit faite.

var app = angular.module("myApp", []);

app.config(["$httpProvider", function($httpProvider) {
    $httpProvider.interceptors.push('middleware');
}]);

app.factory('middleware', function() {
    return {
        request: function(config) {
            // need more controlling when there is more than 1 domain involved
            config.url = "//mydomain.com/api/" + config.url
            return config;
        }
    };
});

app.controller("Ctrl", ["$http", function($http) {
    $http.get("books"); // actually requestUrl = http://example.com/api/books
}])

Et le html aussi

<div ng-include src="'view'">
    <!-- actually src = http://example.com/api/view -->
</div>

Mais je recommande d'utiliser <base> à moins que vous n'utilisiez window.popup().

4voto

Tiago Roldão Points 4567

Utilisez le service $location - il retournera votre chemin, le hachage, l'adresse du serveur Tout ce dont vous avez besoin ! Votre appel serait le suivant $location.path()+"/GetUserList" ou quelque chose de similaire.

Voir ici : http://docs.angularjs.org/guide/dev_guide.services.$location

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X