Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript AngularJS-将控制器重构为服务-了解self/this和scope_Javascript_Angularjs - Fatal编程技术网

Javascript AngularJS-将控制器重构为服务-了解self/this和scope

Javascript AngularJS-将控制器重构为服务-了解self/this和scope,javascript,angularjs,Javascript,Angularjs,我是AngularJS的新手,我现在的JavaScript知识还不太丰富,所以当我系着白腰带暴露我的无知时,我会提前道歉 我很难将下面的控制器重构成一个服务,主要是为了分离关注点,将逻辑进一步向下推,让我的控制器再次变瘦 airBnbClone.controller('SpacesCtrl', ['$http', '$location', function( $http, $location) { var self = this; self.spaces = []; self.cur

我是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='spacescocontroller.getSpaces()'
,其中
My ng controller='SpacesCtrl as spacescocontroller'
拉入了我的空间列表。当我点击一个特定的空间时,它会按照预期显示该特定的空间

现在,对于我的重构代码,我的默认视图没有显示任何内容,当我创建一个空间时,它似乎无法更新位于控制器中的原始
self.spaces
数组

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


既然我的代码不再呈现视图,为什么会出现这种情况?我很抱歉,如果我的问题是循环的,我已经在这几天了,尽管咨询了许多不同的来源,我开始感到非常困惑

您需要一种方法将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);
            });
        };
    }]);

您需要一种将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);
            });
        };
    }]);

service
service的使用假定注入了一个保持其自身状态的新对象实例。它的典型用法是模型类的实例(“model”类似于MVC模型)

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

因此,可以从具有

spacescontroller.spacesService.getSpaces()

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

使用
service
service时,假定注入了一个保持其自身状态的新对象实例。它的典型用法是模型类的实例(“model”类似于MVC模型)

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

因此,可以从具有

spacescontroller.spacesService.getSpaces()

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

考虑从您的服务中返回承诺

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);
        });
    };
};

有关使用承诺的好处的更多信息,请参见考虑从您的服务中返回承诺

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);
        });
    };
};

有关使用承诺的好处的更多信息,请参见

您的任何服务方法都不会返回任何结果。建议您学习一些有关服务工作原理的教程。您的服务方法都不会返回任何结果。建议您学习一些有关服务工作原理的教程谢谢。关于
getSpaces()
方法,修改我的视图以包含实际的服务名称是否是一种好的做法?这是否违反了德米特定律?@ggwc对此有不止一个答案。这主要取决于模型本身。如果它通过其公共方法所做的一切都应该在视图中可用(就像在您的案例中),那么是的,没有理由不这样做,并且您可以自由地不将它链接到服务名称并给它另一个名称(
空格
模型
)。或者甚至为
spacesService
创建一个代理服务,如果它的API在某个时候被修改了,那么您就不必在视图中更改任何内容。谢谢。关于
getSpaces()
方法,修改我的视图以包含实际的服务名称是否是一种好的做法?这是否违反了德米特定律?@ggwc对此有不止一个答案。这主要取决于模型本身。如果它通过其公共方法所做的一切都应该在视图中可用(就像在您的案例中),那么是的,没有理由不这样做,并且您可以自由地不将它链接到服务名称并给它另一个名称(
空格
模型
)。或者甚至为
spacesService
创建一个代理服务,如果它的API在某个时候被修改了,那么您不必在视图中更改任何内容。