How should I reference services in my controller functions without using scope?

♀尐吖头ヾ 提交于 2019-12-10 18:02:50

问题


After reading several articles on avoiding scope soup and referencing the Google Guidelines for building controllers I have been left with one burning question. How should I reference my injected dependencies within my controller?

My approach thus far is to put the services on my object but I'm not exactly happy with that as now my services are exposed to the outside world (the template markup). What is the correct approach to build a controller without directly referencing $scope, and have my injected dependencies available to the controller but not exposed publicly.

As you can see below my work around is to put $http on 'this' and then reference it in my prototyped functions. Not my ideal choice for the aforementioned reasons.

http://plnkr.co/edit/Tn6Jkk06Zdu92uTM0UdU?p=preview

DOCTYPE html>
<html>

<head>
<script data-require="angular.js@*" data-semver="1.3.0-rc2" src="https://code.angularjs.org/1.3.0-rc.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />

</head>

<body ng-controller="textController as txtCtrl">

<h1>{{txtCtrl.greeting}}</h1>
<button ng-click="txtCtrl.getData()">Get Names</button>
<hr>
{{txtCtrl.names | json}}
<script>

  var textController = function($http){
    this.greeting="Hello World";
    this.$http = $http;
  }

  textController.prototype.alert = function(){
    alert(this.greeting);
  }

  /*retrieve test data from //filltext.com*/
  textController.prototype.getData = function(){
    var that = this;

    this.$http({
      method: 'GET', 
      url: 'http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}'

    })
    .success(function(data){
      that.names=data;
    })
    .error();
  }

  angular.module("app",[])
  .controller("textController",textController);

  angular.bootstrap(document,["app"]);

</script>


回答1:


One way you could do is to create a closure variable using IIFE and keep reference of http service outside the controller, and use it in the controller.

  (function(){
      var _$http; //<-- Here a private  variable

     ......

      /*retrieve test data from //filltext.com*/
      textController.prototype.getData = function(){
        var that = this;

       _$http({ //<-- Use it
          method: 'GET', 
          url: 'http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}' })...
         //...
      }

      angular.module("app").controller("textController",textController);

 })();

Plnkr

Or add a property to the constructor instead of its instance.

(function(){

    var textController = function($http){
        this.greeting="Hello World";
        textController._$http = $http; //<-- Here set it
      }

      //....

      /*retrieve test data from //filltext.com*/
      textController.prototype.getData = function(){
        var that = this;

        textController._$http({ //<-- Use it
          method: 'GET', 
          url: 'http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}'})...
         //...
      }
     //...
     angular.module("app").controller("textController",textController);
})();

Plnkr

Here is how you can explicitly annotate your dependencies (unless you use ng-annotate which will take of it while minification)

 angular.module("app").controller("textController",['$http', 'blah', textController]);

Or

 textController.$inject = ['$http', 'blah'];

However i would just leave the responsibility of making ajax calls and any data mapping to a service:-

Example:-

  angular.module("app").service('UserService', ['$http', function($http){
       this.getUsers = function(searchObj){ //Get the input and set your url
        return $http({
          method: 'GET', 
          url: 'http://www.filltext.com/?rows=10',
          params: searchObj  //<-- Pass params
        });

       }
   }]);

And just inject userService in the controller.

 var textController = function(userSvc){
    this.greeting="Hello World";
    this.userSvc = userSvc;
  }

....

  /*retrieve test data from //filltext.com*/
  textController.prototype.getData = function(){
    var that = this;
     //Call service with argument
    this.userSvc.getUsers({firstName:$scope.fn, lastName:$scope.ln}).success(function(data){
      that.names=data;
    })...;
  }

 ....
  angular.module("app").controller("textController",['UserService', textController]);

Plnk3




回答2:


I think you may be thinking too hard about this. If getData() needs to be accessible from our ( view ) html then it should be attached to the scope.




回答3:


In your use case I would use the injector manual to keep a reference to $http in a closure.

 var $http = angular.injector(['ng']).get('$http');

Here is an updated plunk. This way you can keep the private things inside your controller.

EDIT: just noticed that is way similar to @PSL solution. Sorry, I didn't notice his first solution. However, I'm bringing the manual injector, so I'm keeping this answer if that's ok by you! EDITEDIT: Updated the plunker to be a bit more testable.



来源:https://stackoverflow.com/questions/26260444/how-should-i-reference-services-in-my-controller-functions-without-using-scope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!