AngularJS a jednoduchá TODO aplikace

6. 9. 2012 | #tutorial #angular-js #javascript #frontend #nette

Poslední dobou se rozmáhají všelijaké javascriptové frameworky na bází MVC a tak jsem se rozhodl, že by nebylo od věci, některý z nich vyzkoušet. V různých diskusích a článcích jsem neustále narážel na AngularJS a Backbone.js, A jelikož mi přišel z těchto dvou na první pohled Angular sympatičtější, zkusil jsem si v něm s využitím různých externích zdrojů napsat jednoduchou todo aplikaci, o kterou bych se chtěl podělit.

AngularJS todo aplikace

Ale prvně, než začnu se samotnou aplikací. Co to vlastně ten AngularJS je, pro ty, kteří o něm slyšeli poprvé.

AngularJS je otevřený framework vyvíjený Googlem a komunitou. Je postaven na architektuře MVC, která je v dnešní době velice populární. A tak jako je snaha zpřehlednit vývoj aplikací psaných v PHP prostřednictvím různých frameworků, které se snaží programátorovi vnutit správný návyk, je snaha i u javascriptových aplikací jít tímto směrem. Navíc, obecně tyto frameworky, ale i Angular, se snaží spoustu úloh vyřešit za vás. Nemusíte třeba zdlouhavě řešit, jak budete aktualizovat informace v šablonách nebo jak budete muset problematicky měnit stavy prvků v závislosti na tom, jak se budou měnit data.

Pokud o Angularu chcete vědět více, určitě se podívejte na jeho stránky, kde najdete nejen spoustu tutoriálů, ale i podrobnou a dobře zpracovanou dokumentaci.

Ale teď se vraťme ke zmíněné todo aplikaci. Předesílám, že sám jsem začátečník, takže se někde mohu mýlit nebo být nepřesný.

Todo list

Jedná se o jednoduchý úkolníček, kde jste schopni přidávat záznamy, editovat je a případně mazat. U každého záznamu také nechybí možnost jej zaškrtnout, což indikuje, zda je úkol již dokončen. V případě, že jsou některé úkoly dokončeny, je možné je smazat hromadně.

Obrazek

Architektura

Zde je k dispozici přehledná tabulka, co naleznete v každém souboru.

Soubor Popis
index.html šablona aplikace
css/screen,css kaskádové styly aplikace
js/app.js obsahuje definici základního modulu
js/todoCtrl.js obsahuje definici controlleru aplikace
js/todoStorage.js obsahuje službu, která poskytuje rozhraní k ukládání úkolů do localStorage
js/angular.min..js minifikovaná verze AngularJS

screen.css

CSS aplikace není třeba dále komentovat.

app.js

'use strict';

// definice modulu
var todoapp = angular.module('todoapp', []);

todoStorage.js

'use strict';

// tovarna vytvori sluzbu, ktera zajistuje persistenci todos prostrednoctvim localStorage
todoapp.factory('todoStorage', function () {
    var STORAGE_ID = 'todos-angularjs';

    return {
        // vrati kolekci todos v JSON
        get:function () {
            return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
        },

        // aktualizuje todos
        put:function (todos) {
            localStorage.setItem(STORAGE_ID, JSON.stringify(todos));
        }
    };
});

Zde se vytváří služba, která poskytuje rozhraní pro práci s localStorage. Jedná se o jednoduché operace get a put, kde první vrací data ve formátu JSON a druhá naopak tyto data ukládá. Prostor, kam jsou data v localStorage uloženy je definován identifikátorem STORAGE_ID.

todoCtrl.js

'use strict';

// definice controlleru
todoapp.controller('TodoCtrl', function TodoCtrl($scope, todoStorage, filterFilter) {

    // ziskame todos ze storage
    var todos = $scope.todos = todoStorage.get();


    $scope.newTodo = "";
    $scope.editedTodo = null;

    // pri detekci zmeny v todos, dojde k volani funkce, ktera prepocita remainingCount a aktualizuje todos ve storage
    $scope.$watch('todos', function () {
        $scope.remainingCount = filterFilter(todos, {completed:false}).length;
        todoStorage.put(todos);
    }, true);

    // funkce pro pridani noveho zaznamu
    $scope.addTodo = function () {
        if (!$scope.newTodo.length) {
            return;
        }

        todos.push({
            title:$scope.newTodo,
            completed:false
        });

        $scope.newTodo = '';
    };

    // vyvola se pri editaci zaznamu
    $scope.editTodo = function (todo) {
        $scope.editedTodo = todo;
    };

    // vyvola se pri ulozeni editovaneho zaznamu
    $scope.doneEditing = function (todo) {
        $scope.editedTodo = null;
        if (!todo.title) {
            $scope.removeTodo(todo);
        }
    };

    // smaze zaznam
    $scope.removeTodo = function (todo) {
        todos.splice(todos.indexOf(todo), 1);
    };

    // odstrani vsechny zaznamy, ktere jsou dokonceny
    $scope.clearDoneTodos = function () {
        $scope.todos = todos = todos.filter(function (val) {
            return !val.completed;
        });
    };

});

V této části je definován controller. Je mu poskytnutý #scope, což je de facto takový operativní prostor/rámec aplikace, z kterého čerpá informace i šablona. Dále je mu poskytnuta námi definovaná služba todoStorage a nakonec i filterFilter.

V těle controlleru získáme data z uložiště, nadefinujeme, které informace se mají aktualizovat při změně stavu (třeba když přidáme nový todo, smažeme apod.). Dále pak definujeme funkce, které voláme ze šablony a které manipulují s úkoly. Snažil jsem se patřičně okomentovat příslušné bloky kódu, aby bylo jasné, k čemu daná část slouží, pakliže by to nebylo zřejmé.

index.html

<!doctype html>
<html lang="en" ng-app="todoapp">
<head>
    <meta charset="utf-8">
    <title>Todo list AngularJS</title>
    <link rel="stylesheet" href="css/screen.css">
</head>
<body>
<section id="todo-app" ng-controller="TodoCtrl">
    <header>
        <h1>Todo list</h1>

        <form ng-submit="addTodo()">
            <input id="new-todo" placeholder="New todo" ng-model="newTodo" autofocus>
        </form>
    </header>
    <section id="main" ng-show="todos.length" ng-cloak>
        <table id="todo-list">
            <tr ng-repeat="todo in todos" ng-class="{completed: todo.completed, editing: todo == editedTodo}">
                <td>
                    <input type="checkbox" ng-model="todo.completed">
                </td>
                <td>
                    <div class="body">
                        <span ng-dblclick="editTodo(todo)">{{todo.title}}</span>
                    </div>
                    <form ng-submit="doneEditing(todo)">
                        <input class="edit" ng-model="todo.title">
                    </form>
                </td>
                <td>
                    <a ng-click="removeTodo(todo)">Delete</a>

                </td>
            </tr>
            <tr class="last">
                <td>
                </td>
                <td>
                    <span>{{remainingCount}} open items</span>
                </td>
                <td>
                    <a ng-click="clearDoneTodos()">Delete completed</a>
                </td>
            </tr>
        </table>
    </section>
    <footer>
        <p>Double-click or enter to save/edit a todo.</p>
    </footer>
</section>

<script src="js/angular.min.js"></script>
<script src="js/app.js"></script>
<script src="js/todoCtrl.js"></script>
<script src="js/todoStorage.js"></script>
</body>
</html>

V této šabloně lze nalézt u některých tagů atributy začínající ng-, které Angular čte a podle nichž se šablonou operuje.

Na začátku u tagu section si lze všimnout této definice ng-controller=“To­doCtrl”, která říká, že zde začíná prostor, který přísluší todo controlleru.

Dále si lze u formuláře odvodit, že ng-submit=“addTodo()” znamená, že odeslaná data budou směřována k funkci addTodo() definované v todo controlleru, přičemž input ve formuláři disponuje označením ng-model=“newTodo”, který je pak přístupný ze $scope.

Dále za zmínku stojí tyto další atributy:

Atribut Popis
ng-show zobrazí prvek, pakliže obsah atributu je vyhodnocen jako pravdivý
ng-repeat jedná se o cyklus, který listuje kolekcí dat
ng-class přidruží příslušnou třídu k prvku, pakliže je podmínka vyhodnocena kladně (zápis odpovídá tvaru {třída:podmínka} – klasický JSON)
ng-click spustí akci při vyvolání události kliku
ng-dblclick spustí akci při vyvolání události dvojkliku

Dále stojí také za zmínku {{remainingCou­nt}}, který vypisuje počet nedokončených úloh. V controlleru se přepočítává vždy při nějaké změně a je definován v tělu vstupní funkce $watch.

Závěr

V budoucnu bych rád na této aplikaci ukázal i některé jiné konstrukce, kterýma AngularJS disponuje. Ale to někdy příště.

Celý projekt je možné prohlédnout a stáhnout na Githubu.

Diskuse

comments powered by Disqus

Tento web používá k poskytování služeb, personalizaci reklam a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte. Další informace