2

我已经使用带有 Angular UI 的 FullCalendar 设置了一个日历。它工作正常,我可以很好地切换事件类别,但是每次更新 eventSource 时,日历视图都会设置为当前日期。

我已经尝试使用该gotoDate方法,我可以看到它可以工作(它也可以从控制台工作),但几乎是在日历恢复到当前日期之后立即进行的。由于我是 AngularJS 的新手,我可能把它gotoDate放在了错误的地方。但我无能为力把它放在别处。

我正在使用一个服务,它返回一堆事件对象并将它们推送到eventSources日历元素的 ng-model 中。没什么特别的,在控制器中我有:

$scope.eventSources = [];
var promise = UserCalendarEvents.get(groupName);
promise.then(
    function(events) {
        $scope.eventSources.push(events);
        $('#events-calendar').fullCalendar('gotoDate', 2012, 11);
    },
    function(reason) {
        console.log('Error: ' + reason);
    }
);

在这种情况下,将获取并$scope.eventSources填充事件。然后将日历视图设置为 2012 年 12 月,之后,几乎立即,视图切换到当前日期。是否是某种 ng-model 的手表重新渲染了 fullcalender,如果是这样,我该如何设置选择的日期?

更新:我结束了使用 joshkurz 修复,但是在一个修改版本中,尊重所选视图,即如果用户选择了 basicWeek 并更改源数据,则视图不应更改为例如月视图。这就是我的用户所需要的。

    function update() {
        scope.calendar = elm.html('');
        var view = scope.calendar.fullCalendar('getView');
        var m;
        var xtraOptions = {};
        //calendar object exposed on scope
        if(view){
          var viewDate = new Date(view.start);
          if(m !== 'Invalid Date'){
            y = viewDate.getFullYear();
            m = viewDate.getMonth();
            d = viewDate.getDate();
            if(!isNaN(y) && !isNaN(m) && !isNaN(d)){
              xtraOptions = {
                year: y,
                month: m,
                date: d
              };
            }
          }
          view = view.name; //setting the default view to be whatever the current view is. This can be overwritten.
        }
        /* If the calendar has options added then render them */
        var expression, 
            options = { defaultView : view, eventSources: sources };
        if (attrs.uiCalendar) {
            expression = scope.$eval(attrs.uiCalendar);
            // Override defaultView if is set in ui-calendar attribute - OK? 
            if (expression.defaultView) {
                expression.defaultView = view;
            }     
        } else {
            expression = {};
        }
        angular.extend(options, uiConfig.uiCalendar, expression, xtraOptions);
        scope.calendar.fullCalendar(options);

      }
4

3 回答 3

3

这是日历的错误。你是第一个在 StackOverflow 上发表任何评论的人。荣誉。

有几种方法可以解决这个问题。它是在 github https://github.com/angular-ui/angular-ui/pull/520上提出的,我们取消了指令如何在手表被触发时重新创建自身,这将阻止这种行为。我相信,如果我们能让这种方法在生产中发挥作用,那将是最好的解决方案。

在那之前,解决方法是从 view.start 字段创建的日期对象中获取当前月份。本月应添加到用于呈现日历的选项中。

下面是新更新函数在 calendar 指令中应该是什么样子的片段。

/* update the calendar with the correct options */
        function update() {
          scope.calendar = elm.html('');
          var view = scope.calendar.fullCalendar('getView');
          var m;
          var xtraOptions = {};
          //calendar object exposed on scope
          if(view){
            var d = new Date(view.start);
            m = new Date(view.start);
            if(m !== 'Invalid Date'){
              m = m.getMonth();
              if(!isNaN(m)){
                xtraOptions = {
                  month: m
                };
              }
            }
            view = view.name; //setting the default view to be whatever the current view is. This can be overwritten.
          }
         // console.log(m)
          /* If the calendar has options added then render them */
          var expression,
            options = {
              defaultView : view,
              eventSources: sources
            };
          if (attrs.exCalendar) {
            expression = scope.$eval(attrs.exCalendar);
          } else {
            expression = {};
          }
          angular.extend(options, uiConfig.exCalendar, expression, xtraOptions);
          scope.calendar.fullCalendar(options);
        }

这尚未在 angular-ui CI 服务器上进行适当测试,但它工作正常,因为我目前在生产中使用它。

于 2013-03-29T14:28:25.217 回答
0

使用 AngularUI 将 FullCalendar 包装在一个指令中,可以通过 $scope.calendar 访问日历对象。“AngularJS 方式”是为了避免控制器中的直接 DOM 操作。

在您的特定情况下,您将改为:

$scope.calendar.fullCalendar('gotoDate', 2012, 11);

AngularUI 确实对 eventSource 和 event 进行了监视,每次更改的长度都会调用更新函数。您可以在此处查看源代码:

https://github.com/angular-ui/angular-ui/blob/master/modules/directives/calendar/calendar.js

您可以看到,每次事件模型更改时,都会使用一组新事件重新创建 $scope.calendar 中的日历对象。这就是您的日期更改没有通过的原因 - 正在添加事件,触发更新,您的日期更改进入,整个日历被更改并且您的日期更改丢失。

在不更改 AngularUI 代码的情况下,我会弹出两件事(不是最好的):

  1. 您可以使用 AngularJS 的 $timeout 服务并在加载事件后等待一段时间,日历完成更新,然后调用您的日期更改。

  2. 您可以在每次日历对象更改时触发日期更改的范围上添加 $watch:

    http://plnkr.co/edit/Ww08VX?p=preview

我在上面创建了那个例子。在 test() 方法中,我只是通过承诺将一些假数据加载到事件中(它们将在 2013 年 3 月添加)然后将日期更改为 2012 年 12 月。我正在观看 $scope.calendar 并且每次它发生变化(指令中触发更新)我重新发送 date 命令。你应该在没有看到新事件进入的情况下被送到 2012 年 12 月,但如果你回到 2013 年 3 月,它们应该在那里。我把手表放在另一个 .then 假设您将使用返回的一些值来动态设置日期。

于 2013-03-29T02:11:34.883 回答
0

在不更改 Angular-UI 源的情况下解决问题的另一种方法是像这样声明日历:

<div ui-calendar="{viewDisplay:viewDisplayHandler,month:monthVal,year:yearVal}" ng-model="eventsArr"></div>

viewDisplayHandler在范围内设置monthValyearVal设置适当的值的功能,以便在整个日历重新创建之后设置日历上的日期:

$scope.viewDisplayHandler = function(view) {
    var viewStart = view.start;
    $scope.yearVal = viewStart.getFullYear();
    $scope.monthVal = viewStart.getMonth();
}

这就是我在 GitHub 上发出拉取请求之前解决它的方法;我猜这不是最佳方法,但我已经在生产中使用它一段时间了,它似乎没问题,不需要更改 Angular-UI 的代码。

于 2013-03-30T10:07:12.343 回答