【问题标题】:AngularJS - ForEach not loopingAngularJS - ForEach 不循环
【发布时间】:2016-06-03 00:48:29
【问题描述】:

问题


我有一个 AngularJS 应用程序,由于某种原因,我的 forEach 循环之一无法正常工作。当按钮上的功能单击但在初始加载时它不起作用时,循环似乎工作。

代码


所以我为页面正确设置了我的控制器。我在我的服务中调用一个函数,它触发我的 API 并返回一个数组:

控制器

var holidaysnew = getUserEventsById.getUserEventsById();

服务

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

this.getUserEventsById = function () {
    var holidays = [];


    $http.get("http://localhost:9847/AceTracker.svc/GetAllEventsByUser?user_id=1").success(function (data) {
        for (var key in data.GetAllEventsByUserResult) {
            if (data.GetAllEventsByUserResult.hasOwnProperty(key)) {
                holidays.push(data.GetAllEventsByUserResult[key])
            }
        }
    });
    return holidays;
};
});

所以在初始页面加载时,holidaysnew 被成功命中,并且是一个假期数组。该行下方是我的forEach 循环所在的位置,我想循环通过holidaysnew,但它似乎没有进入循环。

循环代码如下:

holidaysnew.forEach(function (hol) {
    $scope.eventSources[0].events.push({
        end: $filter('dateFilter')(hol.HOLIDAY_END),
        start: $filter('dateFilter')(hol.HOLIDAY_START),
        title: hol.HOLIDAY_TITLE,
        color: $filter('colorEventFilter')(hol.HOLIDAY_EVENT_STATE_ID)
    });
});

我有 console.logholidaysnew 数组,它肯定会被填充。任何人都可以看到这个问题吗?

编辑:

服务似乎很好,并按预期返回数组(见下文

但是当$scope.eventSources[0].events = holidayEvents; 代码运行时,它实际上似乎并没有设置事件。

holidayEvents 是一个数组吗?

编辑2:

以下是返回给服务的 JSON 示例:

{"GetAllEventsByUserResult":[{"HOLIDAY_END":"\/Date(1456358400000+0000)\/","HOLIDAY_EVENT_ID":1,"HOLIDAY_EVENT_STATE_ID":1,"HOLIDAY_START":"\/Date(1455926400000+0000)\/","HOLIDAY_TITLE":"Spain     ","USER_ID":1},{"HOLIDAY_END":"\/Date(1454371200000+0000)\/","HOLIDAY_EVENT_ID":2,"HOLIDAY_EVENT_STATE_ID":2,"HOLIDAY_START":"\/Date(1454284800000+0000)\/","HOLIDAY_TITLE":"Italy     ","USER_ID":1},{"HOLIDAY_END":"\/Date(1458000000000+0000)\/","HOLIDAY_EVENT_ID":3,"HOLIDAY_EVENT_STATE_ID":1,"HOLIDAY_START":"\/Date(1457568000000+0000)\/","HOLIDAY_TITLE":"Germany   ","USER_ID":1},{"HOLIDAY_END":"\/Date(1481068800000+0000)\/","HOLIDAY_EVENT_ID":4,"HOLIDAY_EVENT_STATE_ID":3,"HOLIDAY_START":"\/Date(1480896000000+0000)\/","HOLIDAY_TITLE":"England   ","USER_ID":1}]}

【问题讨论】:

  • $http 是异步的……在返回的数组被填充之前,您不能循环遍历它

标签: javascript jquery arrays angularjs foreach


【解决方案1】:

这看起来像是处理您的 REST 响应时出现的错误。数组的填充发生在 return 语句之后,因为 REST 调用是异步的。尝试将不起作用的循环移动到它自己的函数中,然后在 REST 成功回调中调用该函数,或者返回一个 Promise 并在成功回调中解决它。

返回一个承诺:

app.service('getUserEventsById', function ($http, $q) {  

    this.getUserEventsById = function () {
        var deferred = $q.defer();
        var holidays = [];


        $http.get("http://localhost:9847/AceTracker.svc/GetAllEventsByUser?user_id=1").then(function (data) {
            for (var key in data.GetAllEventsByUserResult) {
                if (data.GetAllEventsByUserResult.hasOwnProperty(key)) {
                    holidays.push(data.GetAllEventsByUserResult[key])
                }
            }
            deferred.resolve(holidays);
        });
        return deferred.promise;
    };
});

循环执行承诺:

holidaysnew.then(function(holidays) {
    holidays.forEach(function (hol) {
        $scope.eventSources[0].events.push({
            end: $filter('dateFilter')(hol.HOLIDAY_END),
            start: $filter('dateFilter')(hol.HOLIDAY_START),
            title: hol.HOLIDAY_TITLE,
            color: $filter('colorEventFilter')(hol.HOLIDAY_EVENT_STATE_ID)
        });
    });
});

【讨论】:

  • 服务中没有$scope...为此使用promise
  • 啊,当然——我已经把它改成使用回调,但是promise可能更好
  • 是肯定更好,需要考虑如果请求失败会发生什么控制器完全断开连接,无法捕捉到该故障。
  • 我添加了一个返回承诺的版本。虽然未经测试,所以如果您发现任何明显的错误,请告诉我,我会修复!
  • 不幸的是,这是一种反模式。 $http 本身返回一个承诺,success 已被弃用(请参阅文档)以支持使用 then() 承诺链
【解决方案2】:

更改服务以返回 $http 承诺,但还要在服务本身中执行您需要的所有数据操作,以创建日历事件并返回这些事件。

success 已弃用,取而代之的是使用 then() 承诺链回调

更传统的方法如下所示:

app.service('getUserEventsById', function($http, $q) {

  this.getUserEventsById = function() {

    var requestPromise = $http.get("url")
      .then(function(response) {
        var holidays = [];
        var results = response.data.GetAllEventsByUserResult
        for (var key in results) {
          if (results.hasOwnProperty(key)) {
            holidays.push(results[key])
          }
        }
        // return holidays array to next `then()`
        return holidays;
      }).then(function(holidays) {
        var holidayEvents = holidays.map(function(hol) {
          // make sure to inject `$filter` in service
          return {
            end: $filter('dateFilter')(hol.HOLIDAY_END),
            start: $filter('dateFilter')(hol.HOLIDAY_START),
            title: hol.HOLIDAY_TITLE,
            color: $filter('colorEventFilter')(hol.HOLIDAY_EVENT_STATE_ID)
          }

        });
        // return the events array to next `then()`
        return holidayEvents;

      });
    // return the `$http` promise to controller
    return requestPromise;

  };
});

那么在控制器中你所需要的就是

getUserEventsById.getUserEventsById().then(function(holidayEvents){
    $scope.eventSources[0].events = holidayEvents;
}).catch(function(){

   // do something if promise chain has a rejection
})

【讨论】:

  • 它在服务中进行数据操作的反模式......这个服务调用变得过时了,因为你不能在其他需要不同数据而不是在这里操作的地方使用它......只是我的想法...
  • @Thalaivar 如果是这样,那么使用可以在服务中组合的更多方法很容易设置服务。大多数风格指南会告诉您保持控制器精简并在服务中进行处理
  • @charlietfl 抱歉回复晚了。感谢您回答我的问题,我的服务似乎出错了。 holidayEvents 数组没有被填充?
  • @charlietfl 我刚刚修复了一些格式错误。控制台中没有错误,但事件根本没有加载到日历中?我在控制器中有console.loggedholidayEvents,一切似乎都很好?
  • 所以数据正在发送到控制器?并采用预期的格式?
【解决方案3】:

更好的解决方案/方法是从resolve 拨打您的api 电话。

angular
    .module('app')
    .config(config);

function config($routeProvider) {
    $routeProvider
        .when('/', {
            templateUrl: 'yourTemp.html',
            controller: 'Main',
            controllerAs: 'vm',
            resolve: {
                getUserEventsById: function(getUserEventsById){
                    return getUserEventsById.getUserEventsById()
                }
            }
        });
}

angular
    .module('app')
    .controller('Main', Main);

Main.$inject = ['getUserEventsById'];
function Main(getUserEventsById) {
      var vm = this;
      vm.yourdata = getUserEventsById.data;
}

现在您可以在vm.yourdata 上运行您的forEach 循环,它会运行良好。

【讨论】:

  • 想法不错,但仍不能保证服务请求会完成,或者可能失败。解析仍然返回空数组,因为无论请求是否成功,这都是服务返回的内容......不是承诺
  • @charlietfl:如果你有一个失败的承诺,控制器将不会被实例化,路由被拒绝......否则你的视图被加载并且一切都按预期工作......解决返回一个承诺。 ..如果我错了,请纠正我...
  • 没有失败的承诺才是重点。 OP 不返回 promise ,只返回一个空数组 return holidays; 。因此,无论$http 是否成功,都会返回。 resolve 永远不会被拒绝。此外,如果 $http 需要 2 秒,则空数组仍将出现在控制器中
猜你喜欢
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
相关资源
最近更新 更多