【问题标题】:Can't access variable inside angular.js controller无法访问 angular.js 控制器中的变量
【发布时间】:2015-07-23 21:23:58
【问题描述】:

这是我的控制器:

app.controller("PlaceController", ['$http', function($http){

    this.places = shops;
    var hotels = this;
    hotels.objects = [];
    this.spots = new Array;

    this.newPlace = {};

    this.city = new String();

    this.addPlace = function() {
        this.places.push(this.newPlace);
        this.newPlace = {};

        var request = *some query syntax, sorry for hiding*

        $http.get(request).success(function(data) {
            hotels.objects = data;
            console.log(hotels.objects.elements);
        });

        for (each in hotels.objects.elements) {
          this.spots.push(each.tags.name);
        };

        console.log(this.spots);

}}] );

当我将this.spots 登录到控制台时,我得到一个空数组。 http 请求等工作完美,因为console.log(hotels.objects.elements) 语句工作完美。

由于这个问题,我也无法将其输出到我的 HTML 中。我该怎么办?

【问题讨论】:

  • $http.get 是异步的,所以当你这样做时 for 循环 hotels.objects 是空数组
  • this.spots = new Array; 应该是this.spots = new Array();
  • @DreadBoy 不,这没关系 - 试试吧

标签: javascript angularjs scope


【解决方案1】:

您正在发出一个异步请求来获取这些点,但您在它们完成之前记录它们。

更改 this.addPlace 以记录/作用于 promise 回调中的点数组:

this.addPlace = function() {
    this.places.push(this.newPlace);
    this.newPlace = {};

    var request = *some query syntax, sorry for hiding*

    $http.get(request).success(function(data) {
        hotels.objects = data;
        console.log(hotels.objects.elements);

        for (each in hotels.objects.elements) {
          this.spots.push(each.tags.name);
        };

        console.log(this.spots);
    });

【讨论】:

  • 您确定“this.spots”在 http 请求函数中仍然有效吗?控制台给我一个错误说“TypeError:无法读取未定义的属性'push'”,有没有办法解决这个问题?
  • this 不是指回调中的同一个项目,在这种情况下应该是hotels
  • @Sosdoc 甚至将“this”替换为“hotels”在这里也不起作用。之前它无法读取属性“push”,现在它无法读取“name”。如果我将“this.spots”更改为“hotels.spots”,为什么会出现相同的错误但针对不同的属性?
  • @AMANAGARWAL 这与我在回答中讨论的问题相同,您使用 for-in 的方式是错误的,因为它正在迭代属性名称,each 不是指项目,而只是名字。
【解决方案2】:

您在 ajax 请求完成之前添加到 spots 数组,将您的调用移动到回调内部推送:

$http.get(request).success(function(data) {
        hotels.objects = data;
        console.log(hotels.objects.elements);
        angular.forEach(hotels.objects.elements, function(value) {
                hotels.spots.push(value.tags.name);
        });
});

另外,你真的应该使用$scope 而不是对this 的引用。这会稍微简化您的代码,而无需将 this 重命名为 hotels

使用$scope的完整控制器代码

app.controller("PlaceController", ['$scope', '$http', function($scope, $http){
    $scope.places = shops;    
    $scope.objects = [];
    $scope.spots = new Array;
    $scope.newPlace = {};
    $scope.city = new String();

    $scope.addPlace = function() {
        $scope.places.push($scope.newPlace);
        $scope.newPlace = {};

        var request = *some query syntax, sorry for hiding*

        $http.get(request).success(function(data) {
            $scope.objects = data;
            console.log($scope.objects.elements);

            angular.forEach($scope.objects.elements, function(value, key) {
                $scope.spots.push(value.tags.name);
            });
            // spots is ready, log it, do whatever
            console.log($scope.spots);
        });       
}}] );

注意:使用$scope 意味着您无需从html 调用this 来引用控制器中定义的对象和函数。

一个例子:

<div ng-controller="PlaceController">
    <!-- no need to call places.city, if you use $scope just write city -->
    {{city}}
</div>

编辑:您可能不应该使用 JavaScript 的 for-in,它的问题是它会迭代对象/数组的名称或索引

一个例子:

var someArray = ['a', 'b', 'c'];
for (i in someArray) {
   console.log(i); // prints 0, 1, 2
   console.log(someArray[i]); // prints 'a', 'b', 'c'
}

这不同于其他流行语言中的任何 for-in/for-each 实现。

无论如何,在这种情况下,我已经编辑了上面的代码以使用 Angular 的 forEach,这是一个更合适的解决方案(许多库实现自定义 for-each 函数来修复 JS 的怪异 for-in) 你可以在Angular's docs阅读更多内容

plain javascript 中的另一个选项是,如果$scope.objects.elements 是一个数组,则使用map() function,如下所示:

$scope.spots = $scope.objects.elements.map(function(value) {
    return value.tags.name; // value is an item in object.elements
});

【讨论】:

  • 在 angular2 中不使用 scope 并且对于迁移建议使用 controller as 语法
  • Angular2 还没有发布,考虑到它无论如何都会不兼容,无论你是否使用 $scope,我都没有看到这个问题。
  • angular2 目前处于开发者预览阶段,基于它的生产代码是没有意义的,甚至更喜欢现在就使用它
  • 嗨 Sosdoc,我试过了!但这又引发了另一个问题。我收到一条错误消息,指出无法在“$scope.spots.push(each.tags.name)”行中访问“name”属性。我在原始代码中没有收到该错误,我做错了什么?谢谢
  • @AMANAGARWAL 我已经编辑了答案,修复了一些可能错误的问题。如果这不起作用,您应该显示console.log($scope.objects.elements); 的输出
【解决方案3】:

试试这个..

由于您的异步调用,您需要在成功中执行任务

$http.get(request).success(function(data) {
        hotels.objects = data;
        console.log(hotels.objects.elements);

         for (each in hotels.objects.elements) {
              hotels.spots.push(each.tags.name);
          };

        console.log(this.spots);
    });

【讨论】:

  • 由于您的异步调用,您需要在成功中执行任务
  • 所以在你的答案中添加解释:-)
  • 现在开心吗?那个时候我很着急:D
  • 没有任何解释,您的代码只是复制了其他答案的一部分,因此最好删除它而不是添加,如果我没记错的话,您的答案的第一个版本是错误的。
猜你喜欢
  • 2015-12-05
  • 2014-05-16
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 1970-01-01
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多