Angular Simple Todo app is a tiny Task manager, which allows you to add a new task, provide a note to it, edit a task and delete it once done. In this tutorial we will see how we can build a simple Todo App using AngularJS.
If you are new to AngularJS and want to start from basics i would prefer you to check out the following tutorials before jumping in to this:
http://techiedreams.com/category/angularjs/
Hope you are familiar with the basic concepts of AngularJS. Here will learn how to write a simple Todo app using AngularJS. Before that i would like list the concepts and features of Angular we will be using for this todo App:
- Two way binding
- Routes
- Controllers
- Factories
- Angular form validation
- Filters
You can fork this project on GIT hub here.
Setting up the project:
Here are the basic features which we are adding to our simple Todo app:
- Listing all Todo’s
- Add new Todo
- View Details of a Todo
- Update a Todo
- Delete a Todo
We got a picture of what our App is doing.
Refer below link for setting up a basic Angular project:
http://techiedreams.com/downloads/AngularJSBeanProject.zip
Add partials:
Once the basic project setup is done, now we need to add different html’s to handle your features. In Angular we call these html’s as partials.
We will create two partials one to list all the todo’s and other to display and edit a todo:
todo_list.html:
<!DOCTYPE html> <h2>TODO List</h2> <div> <h3>- You have <span ng-init='totalTodos = 0' ng-bind='totalTodos'></span> todo's</h3> <button ng-click="goTo('/AddTodo/0')">Add todo</button> </div> <div> <div ng-repeat="todo in todos track by $index" ng-click="goTo('/AddTodo/' + todo.id)"> <span ng-bind="todo.title"></span> <span ng-bind="todo.date | date:'dd/MMM/yyyy hh:mma'"></span> </div> </div>
todo_add.html:
<!DOCTYPE html> <h2>Add new todo</h2> <div> <form name="todoForm" novalidate> <div> <span>Title</span> <input type="text" name="title" ng-model="todo.title" ng-maxlength="20" required> <div ng-show="todoForm.title.$dirty && todoForm.title.$invalid"> <span ng-show="todoForm.title.$error.required">Title is a mandatory field.</span> <span ng-show="todoForm.title.$error.maxlength">Title too long.</span> </div> </div> <div> <span>Notes</span> <textarea name="notes" ng-model="todo.notes" ng-maxlength="100"></textarea> <div ng-show="todoForm.notes.$dirty && todoForm.notes.$invalid"> <span ng-show="todoForm.notes.$error.maxlength">Notes too long.</span> </div> </div> </form> <button ng-disabled="todoForm.$invalid" ng-click="saveTodo(todo)"> <span ng-show="isSave">Save</span> <span ng-hide="isSave">Update</span> todo </button> <button ng-hide="isSave" ng-click="deleteTodo(todo.id)">Delete todo</button> </div>
Configure routes:
Once we setup our partials we need to now setup the routes for the app:
Note: Comments are added to the code which needs explanation. If any further doubts put them in comments below.
var serviceApp = angular.module('serviceApp', ['ngRoute', 'serviceApp.controllers', 'serviceApp.services']); serviceApp.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/TodoList', { templateUrl: 'partials/todo_list.html', controller: 'todoListController' }). // AddTodo will take an url parameter as 'id'. // Since we will re-use same route for Edit we use this additional parameter. // We treat 'id' if 0: new todo, else: we are editing some todo. when('/AddTodo/:id', { templateUrl: 'partials/todo_add.html', controller: 'todoAddController' }). otherwise({ redirectTo: '/TodoList' }); }]);
Services:
Next we need to setup our services for the App which will handle all the CRUD(Create Retrieve Update Delete) operations:
/* * services.js */ var serviceModule = angular.module('serviceApp.services', []); var allTodos; var newTodo = {"id": 0, "title": "", "date": "", "notes": ""}; // Maintaing a unique id for session, as it is not using any real services var currentUniqueItemId = 0; serviceModule.factory('todoFactory', ['$http', '$q', function($http, $q) { return { // get all todos getAllTodos: function() { var deferred = $q.defer(); if (!allTodos) { $http.get('data/myTodos.json').success(function(data) { console.log('todoFactory - getAllTodos SUCCESS: ' + angular.toJson(data)); allTodos = data; currentUniqueItemId = allTodos.length; deferred.resolve(allTodos); }).error(function(error) { console.log('todoFactory - getAllTodos ERROR: ' + angular.toJson(error)); deferred.reject(error); }); } else { deferred.resolve(allTodos); } return deferred.promise; }, // get new todo getNewTodo: function() { return angular.copy(newTodo); }, // get todo of id getTodoOfId: function(id) { var selectedItem; angular.forEach(allTodos, function(item) { if (item.id === id) { selectedItem = item; } }); return selectedItem; }, // Add new todo addNewTodo: function(todo) { todo.date = new Date().getTime(); // incrementing the unique id currentUniqueItemId = currentUniqueItemId + 1; todo.id = currentUniqueItemId; allTodos.splice(0, 0, todo); }, // Update todo updateTodo: function(todo) { angular.forEach(allTodos, function(item, index) { if (item.id === todo.id) { allTodos.splice(index, 1, todo); } }); }, // Delete todo deleteTodo: function(id) { angular.forEach(allTodos, function(item, index) { if (item.id === id) { allTodos.splice(index, 1); } }); } }; }]);
Controllers:
Once we have our services ready to consume, will setup our controllers
/* * mainController.js */ var controllerModule = angular.module('serviceApp.controllers', []); // Todo list controller controllerModule.controller('todoListController', ['$scope', 'todoFactory', function($scope, todoFactory) { // set todo list todoFactory.getAllTodos().then(function(data) { // alert("data: " + JSON.stringify(data)); $scope.todos = data; $scope.totalTodos = data.length; }, function(error) { console.log('Error get all todos: ' + error); }); }]); // Todo add controller controllerModule.controller('todoAddController', ['$scope', '$routeParams', '$rootScope', 'todoFactory', function($scope, $routeParams, $rootScope, todoFactory) { // get url paramter - id var id = +$routeParams.id; // '+' will convert string to integer // init the view if (id === 0) { // Create new todo $scope.todo = todoFactory.getNewTodo(); $scope.isSave = true; } else { // Edit todo $scope.todo = todoFactory.getTodoOfId(id); $scope.isSave = false; } // Save /Update todo $scope.saveTodo = function(todo) { if (id === 0) { todoFactory.addNewTodo(todo); } else { todoFactory.updateTodo(todo); } $rootScope.goBack(); }; // Delete todo $scope.deleteTodo = function(id) { todoFactory.deleteTodo(id); $rootScope.goBack(); }; }]);
Misc:
Also to handle the redirection to a path and back functionality we wrote two functions in the mainController on the App. Here is how we defined our controller in ‘index.html’:
<!DOCTYPE html> <html ng-app="serviceApp"> <head> <title>Simple TODO App - using AngularJS</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="js/libs/angular.js"></script> <script src="js/libs/angular-route.js"></script> <script src="js/mainApp.js"></script> <script src="js/controllers/controller.js"></script> <script src="js/services/services.js"></script> </head> <body ng-controller="mainController"> <!-- VIEW PLACE HOLDER --> <div ng-view></div> </body> </html>
And here is the implementation of the mainController in ‘mainApp.js’:
// Main controller: function mainController($rootScope, $location, $window) { // Handle redirection to relative path $rootScope.goTo = function(link) { $location.path(link); }; // Handle history back $rootScope.goBack = function() { $window.history.back(); }; }
Done!! we now have a basic Todo app up and running. I used Netbeans for my development, i would prefer the same as it runs the project on a local server. Find below the download link and optionally you can try the app and edit it online via Plunker:
In the upcoming tutorials will continue with enhancing this Todo app.
Subscribe, like and stay tuned!
You may also like
The post Simple Todo App using AngularJS appeared first on Techie Dreams.