app.config에 서비스 삽입


168

컨트롤러를 호출하기 전에 데이터를 검색 할 수 있도록 app.config에 서비스를 삽입하고 싶습니다. 나는 이것을 이렇게 시도했다 :

서비스:

app.service('dbService', function() {
    return {
        getData: function($q, $http) {
            var defer = $q.defer();
            $http.get('db.php/score/getData').success(function(data) {
                defer.resolve(data);            
            });
            return defer.promise;
        }
    };
});

구성 :

app.config(function ($routeProvider, dbService) {
    $routeProvider
        .when('/',
        {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                data: dbService.getData(),
            }
        })
});

하지만이 오류가 발생합니다.

오류 : 알 수없는 공급자 : EditorApp의 dbService

설정을 수정하고이 서비스를 주입하는 방법은 무엇입니까?


3
이미 본 것을에도 불구하고, 거기 이다 당신의 의도를 달성 할 수있는 방법, 그리고 AngularJS와는 이러한 유형의 기능을 가능하게 많은 시간을 보냈다. 이것을 달성하는 방법에 대한 내 대답을 검토하십시오.
— Brian Vanderbusch

답변:


131

Alex는 당신이하려는 일을 할 수없는 올바른 이유를 제공했습니다. + 1. 그러나 디자인을 잘 사용하지 않아서이 문제가 발생합니다.

resolve서비스 문자열 또는 주입 할 값을 반환하는 함수를받습니다. 후자를하고 있기 때문에 실제 기능을 전달해야합니다.

resolve: {
  data: function (dbService) {
    return dbService.getData();
  }
}

프레임 워크가 해결 data되면 dbService자유롭게 사용할 수 있도록 함수에 삽입 합니다. 이를 위해 config블록에 전혀 주입 할 필요가 없습니다 .

많이 드세요!


2
감사! 그러나이 작업을 수행하면 다음과 같은 결과가 나타납니다. 오류 : 'undefined'는 서비스에서 객체 ( '$ q.defer'평가)가 아닙니다.
— dndr

1
주사제로 전달 최상위 함수 발생 .service하므로 이동 $q하고 $http있다.
— Josh David Miller

1
@XMLilley resolve의 문자열은 실제로 서비스 이름이며 서비스의 특정 기능은 아닙니다. 예제를 사용하면 할 수 pageData: 'myData'있지만 pageData.overview컨트롤러에서 호출 해야합니다. 문자열 메소드는 서비스 팩토리가 API 대신 약속을 리턴 한 경우에만 유용합니다. 따라서 현재하고있는 방식이 아마도 가장 좋은 방법 일 것입니다.
— 조쉬 데이비드 밀러

2
@BrianVanderbusch 정확히 동의하지 않는 부분에 대한 혼란을 인정해야합니다. 실제OP가 직면 한 문제 는 서비스를 구성 블록에 주입했기 때문에 수행 할 수 없었습니다 . 해결책은 해결에 서비스를 주입하는 것 입니다. 귀하의 답변이 서비스 구성에 대해 많은 세부 정보를 제공했지만 OP가 발생한 오류와 어떻게 관련이 있는지 알 수 없으며 OP 문제에 대한 솔루션이 정확히 동일합니다 . 결제 기능에 서비스를 주입하고 구성 기능이 아닙니다 . 우리가 여기서 동의하지 않는 부분을 자세히 설명해 주시겠습니까?
— Josh David Miller 1

1
@JoshDavidMiller 앞서 설명한 방법을 사용하면 상태 활성화 전에 서비스를 구성하여 구성 단계에서 오류를 처리 / 처리하여 응용 프로그램 부트 스트랩 전에 다른 구성 값을 인스턴스화하는 방법을 변경할 수 있습니다. 예를 들어, 응용 프로그램이 올바른 기능을 컴파일하도록하기 위해 사용자의 역할을 결정합니다.
— Brian Vanderbusch

140

서비스를 사용자 정의 AngularJS 제공자로 설정

허용 대답의 말씀에도 불구하고, 당신은 실제로 CAN 당신이하고자 한 일을하지만 먼저, 당신을 변경 ..이 구성 단계에서 서비스로 사용할 수 그래서, 구성 공급자로 설정해야합니다 Service공급자에 아래 그림과 같이. 여기서 중요한 차이점은의 값 defer을 설정 한 defer.promise후이 속성을 다음이 반환 한 promise 객체로 설정 한다는 것입니다 $http.get.

제공자 서비스 : (제공자 : 서비스 레시피)

app.provider('dbService', function dbServiceProvider() {

  //the provider recipe for services require you specify a $get function
  this.$get= ['dbhost',function dbServiceFactory(dbhost){
     // return the factory as a provider
     // that is available during the configuration phase
     return new DbService(dbhost);  
  }]

});

function DbService(dbhost){
    var status;

    this.setUrl = function(url){
        dbhost = url;
    }

    this.getData = function($http) {
        return $http.get(dbhost+'db.php/score/getData')
            .success(function(data){
                 // handle any special stuff here, I would suggest the following:
                 status = 'ok';
                 status.data = data;
             })
             .error(function(message){
                 status = 'error';
                 status.message = message;
             })
             .then(function(){
                 // now we return an object with data or information about error 
                 // for special handling inside your application configuration
                 return status;
             })
    }    
}

이제 구성 가능한 사용자 지정 공급자가 있으므로 주입하기 만하면됩니다. 여기서 중요한 차이점은 누락 된 "주사기에 제공자"라는 점입니다.

구성 :

app.config(function ($routeProvider) { 
    $routeProvider
        .when('/', {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                dbData: function(DbService, $http) {
                     /*
                     *dbServiceProvider returns a dbService instance to your app whenever
                     * needed, and this instance is setup internally with a promise, 
                     * so you don't need to worry about $q and all that
                     */
                    return DbService('http://dbhost.com').getData();
                }
            }
        })
});

당신의 해결 된 데이터를 사용 appCtrl

app.controller('appCtrl',function(dbData, DbService){
     $scope.dbData = dbData;

     // You can also create and use another instance of the dbService here...
     // to do whatever you programmed it to do, by adding functions inside the 
     // constructor DbService(), the following assumes you added 
     // a rmUser(userObj) function in the factory
     $scope.removeDbUser = function(user){
         DbService.rmUser(user);
     }

})

가능한 대안

다음 대안은 비슷한 접근 방식이지만 정의가 .config서비스 내에서 발생 하여 앱의 컨텍스트에서 특정 모듈 내로 서비스를 캡슐화 할 수 있습니다. 자신에게 맞는 방법을 선택하십시오. 또한 이러한 모든 것들을 익히는 데 도움이되는 세 번째 대안 및 유용한 링크에 대한 메모는 아래를 참조하십시오.

app.config(function($routeProvider, $provide) {
    $provide.service('dbService',function(){})
    //set up your service inside the module's config.

    $routeProvider
        .when('/', {
            templateUrl: "partials/editor.html",
            controller: "AppCtrl",
            resolve: {
                data: 
            }
        })
});

유용한 자료

  • 존 린드 퀴 스트 (John Lindquist)는 egghead.io 에서 훌륭한 5 분 설명 및 데모 를 제공하며 무료 레슨 중 하나입니다! 기본적 $http으로이 요청의 맥락에서 구체적으로 설명하여 데모를 수정했습니다.
  • 제공자 에 대한 AngularJS 개발자 안내서보기
  • factory/ service/ 에 대한 훌륭한 설명도 있습니다.provider clevertech.biz에서가 .

프로 바이더는 .service메소드에 대해 약간 더 많은 구성을 제공하여 애플리케이션 레벨 프로 바이더로서 더 나아지지만 다음 $provide과 같이 구성 에 주입하여 구성 오브젝트 자체 내에이를 캡슐화 할 수도 있습니다 .


2
고마워, 나는 그런 예를 찾고 있었다. 자세한 답변과 훌륭한 링크!
— cnlevy 2016 년

1
문제 없어요! 이것은 내가 가장 좋아하는 대답입니다. 나는 현재 받아 들여진 답변이 이미 답변되었고 18 표를 얻었을 때 이것에 답변했습니다. 몇 가지 배지에 좋습니다!
— Brian Vanderbusch

코드 펜 샘플이 작동하면 정말 유용합니다. 예를 들어 $ provide.service ( 'dbService', function () {에는 $ http가 삽입되어 있지 않지만 본문에 사용됩니다. 시작할 때 Angular 프로그램의 제거 파일에서 구성 데이터를로드하기가 너무 어렵습니다.
— Bernard

@Alkaline이 게시물 이후로 한두 가지를 배웠습니다. 이론적으로는 정답이지만 수정해야 할 1 또는 2 가지 (1 지적한 것)가 있습니다. 의견 주셔서 감사합니다. 답변을 검토하고 업데이트하겠습니다. 현재 코드 펜을 삭제했습니다 ... 완료 할 기회가 없었습니다.
— Brian Vanderbusch

5
여기에 제공 한 정보가 잘못되었다고 생각합니다. 공급자를 사용할 수 있지만 구성 단계에서는 $get통화 결과로 작업하지 않습니다 . 대신 공급자 인스턴스에 메서드를 추가하고를 this호출하면 반환 됩니다 $get. 실제로 귀하의 예에서는 서비스를 사용할 수 있습니다 ... 제공자에서는 같은 서비스를 주입 할 수 없습니다 $http. 그리고 이것은 //return the factory as a provider, that is available during the configuration phase잘못
— 되거나

21

짧은 대답 : 당신은 할 수 없습니다. AngularJS는 서비스가 올바르게로드되었는지 확인할 수 없으므로 구성에 서비스를 주입 할 수 없습니다.

이 질문과 답변을보십시오 : module.config 내부의 AngularJS 의존성 주입

모듈은 부트 스트랩 프로세스 동안 응용 프로그램에 적용되는 구성 및 실행 블록 모음입니다. 가장 간단한 형태로 모듈은 두 종류의 블록으로 구성됩니다.

구성 블록 -공급자 등록 및 구성 단계에서 실행됩니다. 공급자와 상수 만 구성 블록에 주입 할 수 있습니다. 이는 서비스가 완전히 구성되기 전에 실수로 서비스가 인스턴스화되는 것을 방지하기위한 것입니다.


2
실제로 이것은 가능합니다. 짧은 설명을 제공합니다.
— Brian Vanderbusch

5

나는 당신이 이것을 할 수 있다고 생각하지 않지만, config블록에 서비스를 성공적으로 주입했습니다 . (AngularJS v1.0.7)

angular.module('dogmaService', [])
    .factory('dogmaCacheBuster', [
        function() {
            return function(path) {
                return path + '?_=' + Date.now();
            };
        }
    ]);

angular.module('touch', [
        'dogmaForm',
        'dogmaValidate',
        'dogmaPresentation',
        'dogmaController',
        'dogmaService',
    ])
    .config([
        '$routeProvider',
        'dogmaCacheBusterProvider',
        function($routeProvider, cacheBuster) {
            var bust = cacheBuster.$get[0]();

            $routeProvider
                .when('/', {
                    templateUrl: bust('touch/customer'),
                    controller: 'CustomerCtrl'
                })
                .when('/screen2', {
                    templateUrl: bust('touch/screen2'),
                    controller: 'Screen2Ctrl'
                })
                .otherwise({
                    redirectTo: bust('/')
                });
        }
    ]);

angular.module('dogmaController', [])
    .controller('CustomerCtrl', [
        '$scope',
        '$http',
        '$location',
        'dogmaCacheBuster',
        function($scope, $http, $location, cacheBuster) {

            $scope.submit = function() {
                $.ajax({
                    url: cacheBuster('/customers'),  //server script to process data
                    type: 'POST',
                    //Ajax events
                    // Form data
                    data: formData,
                    //Options to tell JQuery not to process data or worry about content-type
                    cache: false,
                    contentType: false,
                    processData: false,
                    success: function() {
                        $location
                            .path('/screen2');

                        $scope.$$phase || $scope.$apply();
                    }
                });
            };
        }
    ]);

서비스 메서드의 이름입니다 dogmaCacheBuster 만에 .config당신이 작성한 캐시 버스터 (이 질문에 아무 곳이나 정의되지 않은) 및 dogmaCacheBusterProvider (더 사용되지 않는다). 이것에 대해 명확하게 설명 하시겠습니까?
— diEcho

@ pro.mean 구성 블록에 서비스를 삽입하기 위해 내가 사용한 기술을 시연한다고 생각하지만 시간이 오래 걸렸습니다. cacheBuster구성 기능의 매개 변수로 정의됩니다. 와 관련하여 dogmaCacheBusterProviderAngular가 명명 규칙을 사용하여 오랫동안 잊어 버린 영리한 작업입니다. 이렇게하면 stackoverflow.com/a/20881705/110010에 더 가까이 갈 수 있습니다 .
— kim3er

이 다른 참조에. 나는 우리가 레시피 에서 정의한 것을 공급자 에게 추가한다는 것을 알게 되었습니다 .provider(). 내가 .factory('ServiceName')또는 .service('ServiceName')레시피로 무언가를 정의하고 .config block 에서 해당 메소드 중 하나를 사용 하려면 매개 변수를 ServiceNameProvider 로 설정 하지만 응용 프로그램이 중지됩니다.
— diEcho

5

$ inject service를 사용하여 구성에 서비스를 주입 할 수 있습니다

app.config (function ($ provide) {

    $ provide.decorator ( "$ exceptionHandler", 함수 ($ delegate, $ injector) {
        리턴 함수 (예외, 원인) {
            var $ rootScope = $ injector.get ( "$ rootScope");
            $ rootScope.addError ({message : "Exception", reason : exception});
            $ 대리인 (예외, 원인);
        };
    });

});

출처 : http://odetocode.com/blogs/scott/archive/2014/04/21/better-error-handling-in-angularjs.aspx


5

** angular.injector를 사용하여 다른 모듈에서 서비스를 명시 적으로 요청하십시오 **

kim3er의 답변 을 자세히 설명 하기 위해 다른 모듈에 포함되어있는 한 서비스, 공장 등을 공급자로 변경하지 않고 서비스를 제공 할 수 있습니다 ...

그러나 *Provider각도 지연이 모듈을로드 할 때 (서비스 또는 팩토리를 처리 한 후 내부적으로 각도로 만들어 짐) 항상 사용할 수 있는지 확실하지 않습니다 (먼저로드 된 항목에 따라 다름).

상수로 취급해야하는 값을 다시 주입하려면주의하십시오.

보다 명확하고 신뢰할 수있는 방법 + 작동하는 플런저가 있습니다.

var base = angular.module('myAppBaseModule', [])
base.factory('Foo', function() { 
  console.log("Foo");
  var Foo = function(name) { this.name = name; };
  Foo.prototype.hello = function() {
    return "Hello from factory instance " + this.name;
  }
  return Foo;
})
base.service('serviceFoo', function() {
  this.hello = function() {
    return "Service says hello";
  }
  return this;
});

var app = angular.module('appModule', []);
app.config(function($provide) {
  var base = angular.injector(['myAppBaseModule']);
  $provide.constant('Foo', base.get('Foo'));
  $provide.constant('serviceFoo', base.get('serviceFoo'));
});
app.controller('appCtrl', function($scope, Foo, serviceFoo) {
  $scope.appHello = (new Foo("app")).hello();
  $scope.serviceHello = serviceFoo.hello();
});

2

$ injector를 사용하여 구성에서 서비스 메소드 호출

위와 같이 $ injector 서비스를 사용하여 비슷한 문제가 발생하여 해결했습니다. 서비스를 직접 주입하려고 시도했지만 $ http에 대한 순환 종속성으로 끝났습니다. 이 서비스는 오류가있는 모달을 표시하며 $ https에 의존하는 ui-bootstrap 모달을 사용하고 있습니다.

    $httpProvider.interceptors.push(function($injector) {
    return {
        "responseError": function(response) {

            console.log("Error Response status: " + response.status);

            if (response.status === 0) {
                var myService= $injector.get("myService");
                myService.showError("An unexpected error occurred. Please refresh the page.")
            }
        }
    }

많은 도움이되었습니다
— Erez

2

매우 쉬운 솔루션

참고 : 구성 실행시 서비스가 초기화되지 않기 때문에 비동기 호출에만 해당됩니다.

run()방법 을 사용할 수 있습니다 . 예 :

  1. 귀하의 서비스를 "MyService"라고합니다
  2. 제공자 "MyProvider"에서 비동기 실행에 사용하려고합니다.

귀하의 코드 :

(function () { //To isolate code TO NEVER HAVE A GLOBAL VARIABLE!

    //Store your service into an internal variable
    //It's an internal variable because you have wrapped this code with a (function () { --- })();
    var theServiceToInject = null;

    //Declare your application
    var myApp = angular.module("MyApplication", []);

    //Set configuration
    myApp.config(['MyProvider', function (MyProvider) {
        MyProvider.callMyMethod(function () {
            theServiceToInject.methodOnService();
        });
    }]);

    //When application is initialized inject your service
    myApp.run(['MyService', function (MyService) {
        theServiceToInject = MyService;
    }]);
});

1

글쎄, 나는 이것으로 조금 어려움을 겪었지만 실제로 그것을했다.

각도가 약간 변경되어 답변이 구식인지는 모르겠지만 다음과 같이 할 수 있습니다.

이것은 당신의 서비스입니다 :

.factory('beerRetrievalService', function ($http, $q, $log) {
  return {
    getRandomBeer: function() {
      var deferred = $q.defer();
      var beer = {};

      $http.post('beer-detail', {})
      .then(function(response) {
        beer.beerDetail = response.data;
      },
      function(err) {
        $log.error('Error getting random beer', err);
        deferred.reject({});
      });

      return deferred.promise;
    }
  };
 });

그리고 이것은 구성입니다

.when('/beer-detail', {
  templateUrl : '/beer-detail',
  controller  : 'productDetailController',

  resolve: {
    beer: function(beerRetrievalService) {
      return beerRetrievalService.getRandomBeer();
    }
  }
})

0

가장 쉬운 방법: $injector = angular.element(document.body).injector()

그런 다음이를 사용하여 실행 invoke()하거나get()


이건 해킹이야! 불행히도 응용 프로그램이 DOM에 묶여 있지 않은 대부분의 단위 테스트에서는 작동하지 않습니다.
— rixo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.