Help us understand the problem. What is going on with this article?

AngularJSに挑戦!入門 その6 カレンダーを作ろう

More than 5 years have passed since last update.

はじめに

AngularJSにすこしずつ慣れてきたような気がします。
まだまだですが、がんばります。

さて、入門編として、ToDoを作成しました。次は、カレンダーを作りたいと思います。
完成すれば、ToDo機能をカレンダーに組み込んで、カレンダーアプリにしたいと思います。
まぁ、Googleカレンダーを使ったほうが便利ですが。。。

カレンダーの作成

まず、カレンダーデータの作成を行います。

calendarSample.js
var MyApp = angular.module('calendarApp', []);

MyApp.service('CalendarService', [function () {

    this.header = function() {
        return ["月", "火", "水", "木", "金", "土", "日"];
    }

    this.calendar = function() {
        var date = new Date();              // 現在日付を取得
        var week = [6, 0, 1, 2, 3, 4, 5];   // 月曜始まりにするための変換テーブル
        var monthdays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        var year = date.getFullYear();
        // うるう年の計算
        if (((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0){
            monthdays[1] = 29;
        }

        // 月を取得
        var month = date.getMonth();
        // 今日の日を取得
        var today = date.getDate();

        // 一日を取得
        date.setDate(1);
        var startDay = date.getDay();

        var carendar = [];                  // カレンダーデータ
        var day;                            // ループ用
        var index = 1;                      // 日付


        for(var i = 0; i < 6; i++) {
            var tableLine = [];             // 1週間分のデータ
            var d = 0;                      // ループ用

            do {
                date.setDate(index);
                day = date.getDay();

                // 1段目: 前月の分を空白にする
                if (i == 0 && day > d) {
                    tableLine[d] = {dd: "", color: "none"};
                }
                // 6段目: 次の月の分を空白にする
                else if(i == 6 &&  monthdays[month] < day) {
                    tableLine[week[day]] = {dd: "", color: "none"};
                    index++;
                }
                // 最終日の段: 次の月の分を空白にする
                else if (index > monthdays[month]) {
                    tableLine[week[day]] = {dd: "", color: "none"};
                    index++;
                }
                // 日にちを設定する
                else {
                    tableLine[week[day]] = {dd: date.getDate(), color: date.getDate() == today ? "today" : "none"};
                    index++;
                }
                d++;
            // 月曜日開始のカレンダーにするため、土曜日になるまでループする
            } while (week[day] != 6)

            carendar.push(tableLine);
        }
        return carendar;
    }
}]);


MyApp.controller('CalendarCtrl', ['$scope', 'CalendarService', function ($scope, CalendarService) {

    $scope.header = function() {
        return CalendarService.header();
    }
    $scope.calendar = function() {
        return CalendarService.calendar();
    }
}]);

行っていることは、カレンダーを1週間分の配列を6つ格納したcalendar変数を作成することです。
dd:には日付が入っていて、color:には、今日の場合だけtodayが設定されます。
将来、休日などのデータを格納するのに使えると思います。

カレンダービュー

calendarSample.html
<html>
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
    <link rel="stylesheet" href="calendarSample.css">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <script type="text/javascript" src="calendarSample.js"></script>
    <title>calendarSample</title>
</head>
<body ng-app="calendarApp">
    <div class="container">
        <div class="jumbotron">
            <h2>calendarSample!</h2>
        </div>
        <div ng-controller="CalendarCtrl" ng-Init="calendar = calendar()">
            <table class="table table-striped">
                <th ng-repeat="head in header()">{{head}}</th>
                <tr ng-repeat="week in calendar">
                    <td ng-repeat="day in week" class="today-{{day.color}}">{{day.dd}}</td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

今回新しいキーワードが出てきました。ng-Init="calendar = calendar()"です。
簡単に言えば、初期化です。テンプレートが実行される前に行う処理を記述します。

calendarSample.css
.today-today {
    background: skyblue;
}

td {
    height: 50px;
}

以外に簡単?いや、そうでもなかった

こうやって見ると、簡単にできたように思います。
でも実際にはそうでもありませんでした。
StackOverflowで質問をして解決できた状態でした。

問題は、ng-Initを行わないと無限ループに陥る可能性があるため、
AngularJSのエラーが発生しました。

        <div ng-controller="CalendarCtrl" ng-Init="calendar = calendar()">
            <table class="table table-striped">
                <th ng-repeat="head in header()">{{head}}</th>
                <tr ng-repeat="week in calendar">

この部分を以下に変えてみるとわかります。

        <div ng-controller="CalendarCtrl">
1.            <table class="table table-striped">
                <th ng-repeat="head in header()">{{head}}</th>
2.                <tr ng-repeat="week in calendar()">

初期化せずにng-repeatに関数を呼び出すと、Error: [$rootScope:infdig]になります。
ネスト構造の配列を使用する場合は、ng-Init="list = list()"のように初期化時に
値を取得して、ループ数を確定させる必要があります。

おわりに

今回は、だいぶ勉強になりました。
GitHub - AngularJS_Canendarにソースをアップしています。
次は、Googleカレンダーっぽいものを作ってみたいです。
また、大変そうだなぁ。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした