<!doctype html>
<html lang="en" ng-app="todo">
<head>
    <title>AngularJs TodoList</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.angularjs.org/1.3.0-rc.2/angular.js"></script>
    <script src="angular-local-storage.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="app.js"></script>
</head>
<body ng-controller="TodoCtrl" ng-init="init()">
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">AngulaJs TodoList with LocalStorage - Open in fullscreen for better user experience</a>
            </div>
        </div>
    </div>
    <div class="container" ng-controller="TodoCtrl" id="playground">
        <div class="row">
            <div class="col-sm-7">
                <form name="createForm" class="form" novalidate>
                    <div class="row">
                        <div class="col-sm-10">
                            <input class="form-control" type="text" data-ng-model="newTodo.Name" placeholder="What needs to be done?" required />
                        </div>
                        <div class="col-sm-2">
                            <button class="btn btn-default" ng-click="addTodo(newTodo)" data-ng-disabled="createForm.$invalid">Add</button>
                        </div>
                    </div>
                </form>
            </div>
            <div class="col-sm-3 col-sm-push-2">
                <div class="inner-addon left-addon">
                    <i class="glyphicon glyphicon-search"></i>
                    <input type="text" class="form-control" data-ng-model="todoSearch.name" placeholder="Search..." />
                </div>

            </div>
        </div>
        <hr />
        <div class="row">
            <div class="col-sm-6 col-sm-push-3">
                <h2 class="text-center">Things to Do</h2>
            </div>
        </div>
        <div class="row">
            <div class="col-sm-2">
                <div class="row">
                    <div class="col-sm-6">
                        <button class="btn btn-primary" data-ng-disabled="!doneCount()>0" data-ng-click="clearCompleted()">Clear {{doneCount()}} completed item</button>
                    </div>
                </div><br />
                <div class="row">
                    <div class="col-sm-6">
                        <button class="btn btn-primary" data-ng-click="markAllDone()" data-ng-disabled="!almostOneNotDone()">Check all done</button>
                        <br /><br />
                        <button class="btn btn-primary" data-ng-click="uncheckAllDone()" data-ng-disabled="!doneCount()>0">Uncheck all done</button>
                        <br /><br />
                        <button class="btn btn-primary" data-ng-click="deleteAll()" data-ng-disabled="!todos.length">Delete all</button>
                    </div>
                </div>
            </div>
            <div class="col-sm-6 col-sm-push-1">
                <div class="panel panel-primary">
                    <div class="panel-heading">
                        <div class="row">
                            <div class="col-md-6">
                                <span data-ng-if="todos.length-doneCount()==0">No </span><span>Items left <span class="badge" data-ng-if="todos.length-doneCount()!=0">{{todos.length-doneCount()}}</span></span>
                            </div>
                            <div class="col-sm-6">
                                <div class="text-right">Today is {{getDate()}}</div>
                            </div>
                        </div>
                    </div>
                    <div class="panel-body panel-padding-20">
                        <ul class="list-unstyled">
                            <li ng-hide="todos.length">
                                <div class="row todoItem">
                                    <div class="col-sm-12 todoNameDiv">
                                        <span class="todoName text-center">Nothing to do now...</span>
                                    </div>
                                </div>
                            </li>
                            <li class="todoTask" ng-repeat="todo in todos | filter:todoSearch.name">
                                <div class="row todoItem" ng-class="{'todoItem-done': todo.isDone, 'todoItem-toDo': !todo.isDone}">
                                    <div class="col-sm-2">
                                        <input class="form-control" ng-model="todo.isDone" type="checkbox">
                                    </div>
                                    <div class="col-sm-8 todoNameDiv">
                                        <span class="todoName" data-ng-class="{'toDoLineDone': todo.isDone}" data-ng-bind="todo.Name"></span>
                                    </div>
                                    <div class="col-sm-2">
                                        <button type="button" class="close pull-right bigSize" aria-hidden="true" ng-click="deleteTodo($index)">&times;</button>
                                    </div>
                                </div>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-sm-6 col-sm-push-3">
                <p class="text-center">
                    <span class="text-info"><em>Try to create your Todo List and refresh the page... </em></span> <br /><br />
                    <span class="text-info"> Feel free to fork the code and play a little!</span> <br />
                </p>
            </div>
        </div>
        <!--<div class="row">
            <div class="debug">
                <p class="text-info">{{ todos | json}}</p>
            </div>
        </div>-->
    </div>
</body>
</html>
#playground{
	margin-top: 75px;
}

.debug{
	width: 600px;
	margin: 0 auto;
	margin-top: 30px;
}

.todoItem{
    padding:15px 15px 15px 15px;
    border:1px solid #eee;
    margin-bottom:5px;
}

.todoItem-done{
    border-left:3px solid green;
}

.todoItem-toDo{
    border-left:3px solid red;
}

.todoName{
    font-size:20px;
}

.todoNameDiv{
    margin-top:5px;
    overflow:hidden;
    text-overflow: ellipsis;
}

.toDoLineDone{
    text-decoration: line-through;
}

.bigSize{
    font-size:38px;
}

/* enable absolute positioning */.inner-addon { 
    position: relative; 
}

/* style icon */.inner-addon .glyphicon {
  position: absolute;
  padding: 10px;
  pointer-events: none;}

/* align icon */.left-addon .glyphicon  { left:  0px;}.right-addon .glyphicon { right: 0px;}

/* add padding  */.left-addon input  { padding-left:  30px; }.right-addon input { padding-right: 30px; }

.panel-padding-20{
    padding:25px;
}
#AngularJS ToDo List

Author: Giuseppe Pace

Follow me [@giuseppepace89]([https://twitter.com/giuseppepace89)
var App = angular.module("todo", ["LocalStorageModule"]);

App.controller("TodoCtrl", function ($scope, localStorageService) {

    $scope.init = function () {
        $scope.newTodo = {};
        $scope.todos = [];

        if (!localStorageService.get("todoList")) {
            $scope.todos = [
                {Name:"Fixing bug #9239 on test project", isDone:false},
                { Name: "Pay internet bills", isDone: false },
                { Name: "Defrag local drive", isDone: true },
                { Name: "Write blog post", isDone: false }
            ];
        }else{
            $scope.todos = localStorageService.get("todoList");
        }
    };

    $scope.getDate = function () {
        var today = new Date();
        var mm = today.getMonth() + 1;
        var dd = today.getDate();
        var yyyy = today.getFullYear();

        var date = dd + "/" + mm + "/" + yyyy;

        return date;
    };

    $scope.addTodo = function  (todoItem) {
        todoItem.isDone = false;
        $scope.todos.push(todoItem);
        $scope.newTodo = {};
    };

    $scope.deleteTodo = function  (index) {
        $scope.todos.splice(index, 1);
    };

    $scope.markAllDone = function () {
        $scope.todos.forEach(function (todo) {
            todo.isDone = true;
        });
    };

    $scope.uncheckAllDone = function () {
        $scope.todos.forEach(function (todo) {
            todo.isDone = false;
        });
    };

    $scope.doneCount = function () {
        var todoDone = 0;
        $scope.todos.forEach(function (todo) {
            if (todo.isDone === true) {
                todoDone += 1;
            }
        });
        return todoDone;
    };

    $scope.clearCompleted = function () {
        var kill = [];
        for (var i = 0; i < $scope.todos.length; i++) {
            if ($scope.todos[i].isDone)
                kill.push(i);
        }

        for (var i = 0; i < kill.length; i++)
            $scope.todos.splice(kill[i] - i, 1);
    };

    $scope.almostOneNotDone = function () {
        var todoDone = $scope.doneCount();
        if (todoDone < $scope.todos.length) {
            return true;
        } else
            return false;
    };

    $scope.deleteAll = function () {
        $scope.todos = [];
    };

	$scope.$watch("todos",function  (newVal,oldVal) {
	    if (newVal !== null && angular.isDefined(newVal) && newVal!==oldVal) {
	        localStorageService.add("todoList",angular.toJson(newVal));
	    }
	},true);

});
(function(){var a=angular.module("LocalStorageModule",[]);a.provider("localStorageService",function(){this.prefix="ls";this.cookie={expiry:30,path:"/"};this.notify={setItem:true,removeItem:false};this.setPrefix=function(b){this.prefix=b};this.setStorageCookie=function(c,b){this.cookie={expiry:c,path:b}};this.setNotify=function(b,c){this.notify={setItem:b,removeItem:c}};this.$get=["$rootScope",function(m){var h=this.prefix;var c=this.cookie;var p=this.notify;if(h.substr(-1)!=="."){h=!!h?h+".":""}var e=(function(){try{var q=("localStorage" in window&&window.localStorage!==null);var r=h+"__"+Math.round(Math.random()*10000000);if(q){localStorage.setItem(r,"");localStorage.removeItem(r)}return true}catch(s){m.$broadcast("LocalStorageModule.notification.error",s.message);return false}}());var i=function(q,r){if(!e){m.$broadcast("LocalStorageModule.notification.warning","LOCAL_STORAGE_NOT_SUPPORTED");if(p.setItem){m.$broadcast("LocalStorageModule.notification.setitem",{key:q,newvalue:r,storageType:"cookie"})}return j(q,r)}if(typeof r==="undefined"){r=null}try{if(angular.isObject(r)||angular.isArray(r)){r=angular.toJson(r)}localStorage.setItem(h+q,r);if(p.setItem){m.$broadcast("LocalStorageModule.notification.setitem",{key:q,newvalue:r,storageType:"localStorage"})}}catch(s){m.$broadcast("LocalStorageModule.notification.error",s.message);return j(q,r)}return true};var l=function(q){if(!e){m.$broadcast("LocalStorageModule.notification.warning","LOCAL_STORAGE_NOT_SUPPORTED");return f(q)}var r=localStorage.getItem(h+q);if(!r||r==="null"){return null}if(r.charAt(0)==="{"||r.charAt(0)==="["){return angular.fromJson(r)}return r};var g=function(q){if(!e){m.$broadcast("LocalStorageModule.notification.warning","LOCAL_STORAGE_NOT_SUPPORTED");if(p.removeItem){m.$broadcast("LocalStorageModule.notification.removeitem",{key:q,storageType:"cookie"})}return n(q)}try{localStorage.removeItem(h+q);if(p.removeItem){m.$broadcast("LocalStorageModule.notification.removeitem",{key:q,storageType:"localStorage"})}}catch(r){m.$broadcast("LocalStorageModule.notification.error",r.message);return n(q)}return true};var k=function(){if(!e){m.$broadcast("LocalStorageModule.notification.warning","LOCAL_STORAGE_NOT_SUPPORTED");return false}var q=h.length;var s=[];for(var r in localStorage){if(r.substr(0,q)===h){try{s.push(r.substr(q))}catch(t){m.$broadcast("LocalStorageModule.notification.error",t.Description);return[]}}}return s};var b=function(q){var q=q||"";var v=h.slice(0,-1)+".";var t=RegExp(v+q);if(!e){m.$broadcast("LocalStorageModule.notification.warning","LOCAL_STORAGE_NOT_SUPPORTED");return d()}var r=h.length;for(var s in localStorage){if(t.test(s)){try{g(s.substr(r))}catch(u){m.$broadcast("LocalStorageModule.notification.error",u.message);return d()}}}return true};var o=function(){try{return navigator.cookieEnabled||("cookie" in document&&(document.cookie.length>0||(document.cookie="test").indexOf.call(document.cookie,"test")>-1))}catch(q){m.$broadcast("LocalStorageModule.notification.error",q.message);return false}};var j=function(s,t){if(typeof t==="undefined"){return false}if(!o()){m.$broadcast("LocalStorageModule.notification.error","COOKIES_NOT_SUPPORTED");return false}try{var r="",q=new Date();if(t===null){q.setTime(q.getTime()+(-1*24*60*60*1000));r="; expires="+q.toGMTString();t=""}else{if(c.expiry!==0){q.setTime(q.getTime()+(c.expiry*24*60*60*1000));r="; expires="+q.toGMTString()}}if(!!s){document.cookie=h+s+"="+encodeURIComponent(t)+r+"; path="+c.path}}catch(u){m.$broadcast("LocalStorageModule.notification.error",u.message);return false}return true};var f=function(s){if(!o()){m.$broadcast("LocalStorageModule.notification.error","COOKIES_NOT_SUPPORTED");return false}var t=document.cookie.split(";");for(var r=0;r<t.length;r++){var q=t[r];while(q.charAt(0)===" "){q=q.substring(1,q.length)}if(q.indexOf(h+s+"=")===0){return decodeURIComponent(q.substring(h.length+s.length+1,q.length))}}return null};var n=function(q){j(q,null)};var d=function(){var r=null,u=null;var q=h.length;var v=document.cookie.split(";");for(var t=0;t<v.length;t++){r=v[t];while(r.charAt(0)===" "){r=r.substring(1,r.length)}var s=r.substring(q,r.indexOf("="));n(s)}};return{isSupported:e,set:i,add:i,get:l,keys:k,remove:g,clearAll:b,cookie:{set:j,add:j,get:f,remove:n,clearAll:d}}}]})}).call(this);