1

I have a JSON list of the days in a month.

Like so:

{
    date: "2016-08-01T00:00:00",
    weekday: 1,
},
{
    date: "2016-08-02T00:00:00",
    weekday: 2,
},
...

Where weekday: 1 means Monday, weekday: 2 is Tuesday.

So, I know how many days are in the month and I know what day the month starts on.

Using Angular to fetch the JSON and then create a view, I want to display the above JSON as a standard calendar, that is in rows of seven days.

As in:

    <table>
        <tr>
            <td>sun</td>
            <td>mon</td>
            <td>tue</td>
            <td>wed</td>
            <td>thr</td>
            <td>fri</td>
            <td>sat</td>
        </tr>
        <tr>
            <td>day 1</td>
            <td>day 2</td>
            <td>day 3</td>
            <td>day 4</td>
            <td>day 5</td>
            <td>day 6</td>
            <td>day 7</td>
        </tr>
        ....
    </table>

Two broad solutions seem likely:

1) Use some really fancy view logic. Lots of ng-repeats and ng-init for counters. This seems difficult and ugly, if it's even possible.

2) Create an array and then use nested ng-repeats to display the data.

var calendar = function(){
    var firstDay = data[0].weekday;
    vm.month = [];
    var week = [];
    for(var i=0; i < data.length; i++){
        var day = data[i];
        if(i===0){
            while(firstDay > 0){
                week.push(null);
                firstDay --;
            }
        }
        if(week.length === 7){
            vm.month.push(week);
            week = [];
        }
        week.push(day);
    }

    console.log(vm.month);
}

Works great. The calendar array contains week arrays that contain the day information. To display it, all I need are a couple of ng-repeats:

<table>
    <tr ng-repeat="week in vm.month">
        <td ng-repeat="day in week">
            {{day}}
        </td>
    </tr>
</table>

Except no. I get the following error:

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.

I suspect I need turn my array into a JSON object, but I don't know how to do that.

Or maybe there's a way to use the array as-is with the nested ng-repeats?

If there's any other information that would help, please let me know.

crowhill
  • 2,398
  • 3
  • 26
  • 55

2 Answers2

0

Obvious answer, you can't have duplicate keys. Angular uses the value to track by default so I think that having the double repeat in there is going to explode when you get to the second week and you hit Sunday again.

https://docs.angularjs.org/error/ngRepeat/dupes

You'll want to add a track by clause which specifies both the day and week together. See if this works for you.

<table>
    <tr ng-repeat="week in vm.month">
        <td ng-repeat="day in week track by day+week">
            {{day}}
        </td>
    </tr>
</table>

Edit: Might be relevant ng-repeat with track by over multiple properties

Community
  • 1
  • 1
dwbartz
  • 886
  • 10
  • 13
  • Doesn't work. Created many more instances of the same error, but I'll have a look at the links. Thanks. – crowhill Aug 30 '16 at 22:34
0

Okay, so the answer turned out to be fairly simple (thanks to comments and the answers below).

The code as written above works, with just this minor change:

<table class="ru-calendar">
    <tr ng-repeat="week in vm.month">
        <td ng-repeat="day in week track by $index">
            {{day.date | date:'d' }}
        </td>
    </tr>
</table>

See track by $index? That's it. Three word change. Now I don't know why it works, but I'm off to Google that. Thanks all.

crowhill
  • 2,398
  • 3
  • 26
  • 55