LoginSignup
21
19

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-11-06

はじめに

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カレンダーっぽいものを作ってみたいです。
また、大変そうだなぁ。

21
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19