AngularJS - 将控制器重构为服务 - 理解self / this和范围

时间:2016-03-20 21:09:55

标签: javascript angularjs

我是AngularJS的新手,我现在的JavaScript知识并不强大,所以当我戴上白色腰带并露出我的无知时,我提前道歉。

我很难将以下控制器重构为服务,主要是为了分离关注点并将逻辑推进堆栈,并让我的控制器再次变瘦。

airBnbClone.controller('SpacesCtrl', ['$http', '$location', function( $http, $location) {
  var self = this;
  self.spaces = [];
  self.currentspace;

  self.create = function(space) {
    $http.post('http://localhost:3000/api/spaces', space).success(function(data) {
      self.spaces.push(data);
      self.showSpace(data.space);
    });
  };

  self.getSpaces = function(){
    $http.get('http://localhost:3000/api/spaces.json').then(function(response){
      self.spaces = response.data.reverse();
    });
  };

  self.showSpace = function(space){
    $http.get('http://localhost:3000/api/spaces/' + space.id).then(function(response){
      self.currentspace = response.data;
      $location.path('/spaces/' + space.id)
    });
  };
}]);

经过一些重构后,我的代码现在看起来像这样:

airBnbClone.controller('SpacesCtrl', ['$http', '$location', 'spacesService', function( $http, $location, spacesService) {
  var self = this;

  self.create = function(space) {
    spacesService.createSpace(space);
  };

  self.getSpaces = function(){
    spacesService.getSpaces();
  };

  self.showSpace = function(space){
    spacesService.showSpace(space);
  };
}])
.service('spacesService', ['$http', '$location', function($http, $location){
  var self = this;
  self.spaces = [];
  self.currentspace;

  this.createSpace = function(space){
    $http.post('http://localhost:3000/api/spaces', space).success(function(data) {
      self.spaces.push(data);
      self.showSpace(data.space);
    });
  }

  this.getSpaces = function(){
    $http.get('http://localhost:3000/api/spaces.json').then(function(response){
      self.spaces = response.data.reverse();
    });
  };

  this.showSpace = function(space){
    $http.get('http://localhost:3000/api/spaces/' + space.id).then(function(response){
      self.currentspace = response.data;
      $location.path('/spaces/' + space.id)
    });
  };
}]);

在我重构之前,我的代码按预期工作。我的主视图有ng-init='spacescontroller.getSpaces()'my ng-controller='SpacesCtrl as spacescontroller'拉入我的空格列表。当我点击某个特定空间时,它会按预期显示该特定空间。

现在,使用我重构的代码,我的默认视图根本不显示任何内容,当我创建空格时,似乎无法更新控制器中的原始self.spaces数组。

基本上,我不确定如何将这些方法重构为服务。我的self.spacesself.currentspace对象应该保留在控制器中,还是成为注入服务的属性?在这种情况下,哪个是存储状态的首选方法,为什么?

由于我的代码不再呈现视图,为什么会出现这种情况?如果我的问题非常循环,我会道歉,尽管我咨询了许多不同的消息来源,但我已经开始感到非常困惑了。

3 个答案:

答案 0 :(得分:2)

您需要一种方法将GET请求的结果从服务带到控制器。

我将逻辑留在控制器中并将所有HTTP请求移动到服务中。我添加了一个回调函数,当结果准备好让控制器使用结果时,它将触发。

airBnbClone.controller('SpacesCtrl', ['$http', '$location', 'spacesService', function($http, $location, spacesService) {
        var self = this;
        self.spaces = [];
  self.currentspace;
        self.create = function(space) {
            spacesService.createSpace(space, function(data) {
                self.spaces.push(data);
                self.showSpace(data.space);
            });
        };

        self.getSpaces = function() {
            spacesService.getSpaces(function(spaces) {
                self.spaces = spaces;
            });
        };

        self.showSpace = function(space) {
            spacesService.showSpace(space, function(currentspace) {
                self.currentspace = currentspace;
                $location.path('/spaces/' + space.id)
            });
        };
    }])
    .service('spacesService', ['$http', function($http) {
        var self = this;


        this.createSpace = function(space, cb) {


            $http.post('http://localhost:3000/api/spaces', space).success(function(data) {
                cb(data);
            });
        }

        this.getSpaces = function(cb) {
            $http.get('http://localhost:3000/api/spaces.json').then(function(response) {
                var spaces = response.data.reverse();
                cb(spaces);
            });
        };

        this.showSpace = function(space, cb) {
            $http.get('http://localhost:3000/api/spaces/' + space.id).then(function(response) {
                var currentspace = response.data;
                cb(currentspace);
            });
        };
    }]);

答案 1 :(得分:2)

service服务的使用假定注入了一个保持自己状态的新对象实例。典型的用途是模型类的实例(像MVC模型中的“模型”)。

重构是在正确的轨道上。考虑到spacesService是一个模型,它可以只分配给控制器(而不是每个模型方法的多个包装器):

this.spacesService = spacesService;
// or any readable property name, e.g.
// this.spaces = spacesService;

所以可以从

的视图中找到它
spacescontroller.spacesService.getSpaces()

这里的例外是showSpace方法。 $location.path的部分与模型状态无关,并且它执行某些路由这一事实表明它属于控制器,不应从中提取。因此,它可以在控制器中分为spacesService.getSpace(id)showSpace

答案 2 :(得分:2)

从服务中考虑返回承诺。

app.service('spacesService', function($http) {

    this.getSpaces = function(){
        var url = 'http://localhost:3000/api/spaces.json';
        var promise = $http.get(url)
            .then(function(response){
                //return for chaining
                return response.data.reverse();
        });
        return promise;
     });
});

返回承诺的一个好处是它们保留了错误信息。

在您的控制器中:

airBnbClone.controller('SpacesCtrl', function($http, $location, spacesService) {
    var self = this;
    self.spaces = [];

    self.getSpaces = function() {
        var promise = spacesService.getSpaces();

        promise.then(function onFulfilled(spaces) {
            self.spaces = spaces;
        }).catch(function onRejected(response) {
            console.log(response.status);
        });
    };
};

有关使用promises的优势的更多信息,请参阅Why are Callbacks from Promise .then Methods an Anti-Pattern?.