嵌套回调范围和rootScope AngularJS

时间:2021-10-31 19:27:12

I have the following controller in Angular that reads some records from DB and then outputs them into a calendar. The problem is that the events array comes back as empty. I have tried using $rootScope.events as a substitute, but that gives an error "concat is not a function of undefined." What am I doing wrong? Is there some trickery with nested scopes?

我在Angular中有以下控制器,它从DB读取一些记录,然后将它们输出到日历中。问题是events数组返回为空。我已经尝试使用$ rootScope.events作为替代,但是这会产生错误“concat不是undefined的函数。”我究竟做错了什么?嵌套作用域有一些技巧吗?

I also just realized that eachActivity variable is undefined in the inner callback, as well. I assume this is a part of a general knowledge I am lacking.

我也刚刚意识到每个活动变量在内部回调中也是未定义的。我认为这是我缺乏的一般知识的一部分。

app.controller('Calendar', ['$scope','$rootScope','$resource','moment', function($scope, $rootScope, $resource ,moment) {

    var Activities = $resource('/api/activities');
        Activities.query(function(activities){
            $rootScope.activities = activities;
            //console.log($rootScope.activities);   
        });

    //console.log($rootScope.activities);

     var vm = this;
     var events = [];

    //define the calendar on rootScope, so it has access to the Events data from the other controllers
    $rootScope.calendar = new moment();

    angular.forEach($rootScope.activities, function(eachActivity){
        //console.log(eachActivity.events);
        if (eachActivity.events.length > 0){
            angular.forEach(eachActivity.events, function(eachEvent, eachActivity){
            console.log(eachEvent);    
            var entry = {
                    title: eachActivity.title,
                    type: "warning",
                    startsAt: eachEvent.startDate,
                    endsAt: eachEvent.endDate,
                    incrementBadgeTotal: true
                }

            events.concat(entry);

            }); 
        }
    });

    vm.events = events;
    console.log(vm.events);

    vm.calendarView = 'month';

    vm.viewDate = moment().startOf('month').toDate();
    vm.isCellOpen = true;

}]);

2 个解决方案

#1


0  

To solve your immediate problem, change

要解决您的直接问题,请进行更改

angular.forEach(eachActivity.events, function(eachEvent, eachActivity)

to

angular.forEach(eachActivity.events, function(eachEvent)

The second argument is not necessary as eachActivity has already been defined in the outer loop.

第二个参数不是必需的,因为eachActivity已经在外部循环中定义。

Also change events.concat(entry); to events.push(entry);

也改变events.concat(entry); to events.push(entry);

In addition, instead of defining calendar on $rootScope, create a calendar factory instead and inject that into the controllers where you need to access calendar data. There are a number of reasons why this is better but the simplest is that $scopes are not meant for sharing data between controllers. They are primarily meant to act as a view model to bind data between your views and controllers.

此外,不是在$ rootScope上定义日历,而是创建一个日历工厂,并将其注入您需要访问日历数据的控制器中。有许多原因可以解释为什么这样做更好,但最简单的是$ scope不适合在控制器之间共享数据。它们主要用作视图模型,用于在视图和控制器之间绑定数据。

EDIT (more details on creating a factory)

编辑(关于创建工厂的更多细节)

You can define a factory like so

您可以像这样定义工厂

app.factory('CalendarService', [function(){
    var calendarEvents = [];  // or {} or even null depending on how you want to use the variable
    return {
        calendarEvents : calendarEvents
    };
}]);

In your controller,

在你的控制器中,

app.controller('Calendar', ['$scope','$rootScope','$resource','moment', 'CalendarService', function($scope, $rootScope, $resource ,moment, CalendarService) {
    ...
    // instead of $rootScope.calendar = new moment (and I don't understand why you are assigning this to a moment but that's another conversation
    CalendarService.calendarEvents = events;
}]);

All you need to do is inject CalendarService into every controller where you need to use the events data and it will be available in the calendarEvents field.

您需要做的就是将CalendarService注入您需要使用事件数据的每个控制器,它将在calendarEvents字段中可用。

#2


0  

There are a few things going on here:

这里有一些事情:

1) The concat() method returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments. You'll need to assign the vaues: events = events.concat(entry) for them to persist for the next iteration.

1)concat()方法返回一个新数组,该数组由调用它的数组组成,并与作为参数提供的数组和/或值连接。您需要分配vaues:events = events.concat(条目),以便它们在下一次迭代中保留。

2) You have nested Angular Loops. Often necessary, but be careful with your naming conventions.

2)您已嵌套Angular循环。通常是必要的,但要小心你的命名约定。

angular.forEach($rootScope.activities, function(eachActivity){
        angular.forEach(eachActivity.events, function(eachEvent, eachActivity)

Here your loops share identical argument names. This is highly discouraged because it can really create headaches for the developer trying to understand the scope of the object being iterated over. I'd suggest ensuring that your names are always unique and explicit to the scope.

这里你的循环共享相同的参数名称。这是非常不鼓励的,因为它确实会让开发人员试图理解被迭代的对象的范围。我建议确保您的名字始终是唯一且明确的范围。

3) Because you are overriding your argument names, your call to title: eachActivity.title is going to be looking at the inner loops second argument, which in this case is the KEY of the event within the forEach loop eachActivity.events object. Keys do not have properties, they are always strings - because of this your eachActivity variable is defined, yet it has no properties.

3)因为你要覆盖你的参数名称,你对标题的调用:eachActivity.title将查看内部循环第二个参数,在这种情况下,它是forEach循环中的事件的key eachActivity.events对象。键没有属性,它们总是字符串 - 因此定义了eachActivity变量,但它没有属性。

I'd suggest altering these few things and then editing your post with any progress made.

我建议改变这些事情然后编辑你的帖子,取得任何进展。

#1


0  

To solve your immediate problem, change

要解决您的直接问题,请进行更改

angular.forEach(eachActivity.events, function(eachEvent, eachActivity)

to

angular.forEach(eachActivity.events, function(eachEvent)

The second argument is not necessary as eachActivity has already been defined in the outer loop.

第二个参数不是必需的,因为eachActivity已经在外部循环中定义。

Also change events.concat(entry); to events.push(entry);

也改变events.concat(entry); to events.push(entry);

In addition, instead of defining calendar on $rootScope, create a calendar factory instead and inject that into the controllers where you need to access calendar data. There are a number of reasons why this is better but the simplest is that $scopes are not meant for sharing data between controllers. They are primarily meant to act as a view model to bind data between your views and controllers.

此外,不是在$ rootScope上定义日历,而是创建一个日历工厂,并将其注入您需要访问日历数据的控制器中。有许多原因可以解释为什么这样做更好,但最简单的是$ scope不适合在控制器之间共享数据。它们主要用作视图模型,用于在视图和控制器之间绑定数据。

EDIT (more details on creating a factory)

编辑(关于创建工厂的更多细节)

You can define a factory like so

您可以像这样定义工厂

app.factory('CalendarService', [function(){
    var calendarEvents = [];  // or {} or even null depending on how you want to use the variable
    return {
        calendarEvents : calendarEvents
    };
}]);

In your controller,

在你的控制器中,

app.controller('Calendar', ['$scope','$rootScope','$resource','moment', 'CalendarService', function($scope, $rootScope, $resource ,moment, CalendarService) {
    ...
    // instead of $rootScope.calendar = new moment (and I don't understand why you are assigning this to a moment but that's another conversation
    CalendarService.calendarEvents = events;
}]);

All you need to do is inject CalendarService into every controller where you need to use the events data and it will be available in the calendarEvents field.

您需要做的就是将CalendarService注入您需要使用事件数据的每个控制器,它将在calendarEvents字段中可用。

#2


0  

There are a few things going on here:

这里有一些事情:

1) The concat() method returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments. You'll need to assign the vaues: events = events.concat(entry) for them to persist for the next iteration.

1)concat()方法返回一个新数组,该数组由调用它的数组组成,并与作为参数提供的数组和/或值连接。您需要分配vaues:events = events.concat(条目),以便它们在下一次迭代中保留。

2) You have nested Angular Loops. Often necessary, but be careful with your naming conventions.

2)您已嵌套Angular循环。通常是必要的,但要小心你的命名约定。

angular.forEach($rootScope.activities, function(eachActivity){
        angular.forEach(eachActivity.events, function(eachEvent, eachActivity)

Here your loops share identical argument names. This is highly discouraged because it can really create headaches for the developer trying to understand the scope of the object being iterated over. I'd suggest ensuring that your names are always unique and explicit to the scope.

这里你的循环共享相同的参数名称。这是非常不鼓励的,因为它确实会让开发人员试图理解被迭代的对象的范围。我建议确保您的名字始终是唯一且明确的范围。

3) Because you are overriding your argument names, your call to title: eachActivity.title is going to be looking at the inner loops second argument, which in this case is the KEY of the event within the forEach loop eachActivity.events object. Keys do not have properties, they are always strings - because of this your eachActivity variable is defined, yet it has no properties.

3)因为你要覆盖你的参数名称,你对标题的调用:eachActivity.title将查看内部循环第二个参数,在这种情况下,它是forEach循环中的事件的key eachActivity.events对象。键没有属性,它们总是字符串 - 因此定义了eachActivity变量,但它没有属性。

I'd suggest altering these few things and then editing your post with any progress made.

我建议改变这些事情然后编辑你的帖子,取得任何进展。