Before running your app make sure you your rest api(backend) is running on http://localhost:8000/api, if that's not the case you can always change your backend url in the app/app.js file under the constant baseUrl.
Also make sure you have the nessesary database and tables for this app for more information on the database and backend go to scriptjumper-api-laravel.
Use the following command to clone repository (if you have git cli):
$ git clone https://github.com/scriptjumper/angularjs-todo-app.git alternatively you can download the zipped files.
Then, change directory in your terminal to the project directory:
$ cd angularjs-todo-app/ Firstly you need to make sure you have node and npm installed if not please go here and follow the installation process to setup you machine.
Run the command below to install all the necessary packages:
$ npm ci Run the command below:
$ npm run dev Firstly you need to make sure you have node and npm installed if not please go here and follow the installation process to setup you machine.
Let’s first create main directory:
$ mkdir angularjs-todo-app && cd angularjs-todo-app For this project we will install the packages we need via npm instead of using the cdn links that is imported in the html file
Firstly, we need to initialise our package.json file, we do that by running this command:
$ npm init -y Now we can install the packages we need to setup the AngularJS app.
We will be using the following packages:
- angular
- angular-route
- bootstrap
- prettier
- angular-cookies
- jQuery
Update the dependencies in the package.json with the following code:
... "dependencies": { "@angular/router": "^0.2.0", "angular": "1.5.6", "angular-cookies": "1.5.6", "angular-font-awesome": "^3.1.2", "angular-resource": "1.5.6", "angular-route": "1.5.6", "bootstrap": "^4.4.1", "font-awesome": "^4.7.0", "jquery": "3.3.x", "prettier": "^2.0.4" } then we running the command below:
$ npm i Once that’s done installing, let’s run the command below to create files for our prettier package and a gitignore file to handle files we do not want to add to github:
$ touch .prettierrc .gitignore Open the .prettierrc file and update add the code below:
{ "singleQuote": true, "printWidth": 160, "jsxBracketSameLine": true, "semi": false, "tabWidth": 2, "trailingComma": "none", "bracketSpacing": true } Open the .gitignore file and add the code below:
# Logs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history For the code I use in my .gitignore file I get the code from executeautomation.
Let’s first create our main file:
index.html, which will be linked to our external files and will serve as the primary template for our application.
In the main directory create index.html and add the code below:
In the head tag:
<html lang="en" ng-app="TodoApp"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Todo App</title> <link rel="stylesheet" type="text/css" href="node_modules/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" type="text/css" href="node_modules/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="node_modules/font-awesome/css/font-awesome.css" /> <link rel="stylesheet" type="text/css" href="app.css" /> <base href="/" /> </head> ... In the body:
... <body> <app></app> <script type="module" src="dist/dependencies.js"></script> </body> </html> To test that all our imports is working we need to run our app. For this app I am using lite-server, to install lite-server we run this command:
$ npm install lite-server --save-dev ...and add a "script" entry within your project's package.json file:
# Inside package.json... "scripts": { "dev": "lite-server" }, With the above script entry, you can then start lite-server via:
$ npm run dev Once the above command is running, in your browser of choice go to http://localhost:3000 (by default lite-server will open a new tab in your default browser that is opened to http://localhost:3000).
In the app/components/app/ directory, we will be creating app.js file with the code below:
;(function () { angular.module('todoApp', ['ngComponentRouter']) })() Since we will be using lite-server to run the app, we add the code below beneath angular.module in app.js:
... .config(function($locationProvider) { $locationProvider.html5Mode(true); }) ... Configure the top level routed App Component.
... .value('$routerRootComponent', 'app') ... Finally we can add our component:
... .component('app', { template: '<h1>Hello World!</h1>' }); ... Add a <base> element to the head of our index.html. Remember that we have chosen to use HTML5 mode for the $location service.
... <base href="/"> </head> ... Bootstrap with AngularJS.
<body ng-app="app"> <h1 class="title">Component Router</h1> <app></app> </body> ....
We'll start in the app.js, add the code below to setup the login route:
{ path: '/login', component: 'login', name: 'Login' } Next, we create the login.html view file in app/routes/login/ with a basic login form code:
<div class="container"> ... <form name="form" role="form"> <div class="form-group"> <input type="email" name="email" id="email" class="form-control" placeholder="Email" required /> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control" placeholder="Password" required /> </div> <div class="text-center"> <button type="submit" class="btn btn-block send-button tx-tfm">Login</button> </div> <p class="small mt-3">Are you new? why don't you create an account <a href="#" class="ps-hero__content__link">here</a>.</p> </form> ... In the app/routes/login/ directory, we will be creating login.js file with the code below:
;(function () { angular.module('app.login', []).component('login', { templateUrl: 'app/routes/login/login.html', controllerAs: '$ctrl', controller: [function() {} ... In the main directory we create our custom styles, create the app.css file. Code is available here
We do the same the process
In the html file for the register view, we add 2 extra inputs:
... <div class="form-group"> <input type="text" name="firstName" id="firstName" class="form-control" ng-model="$ctrl.registerFormDetails.firstName" placeholder="First Name" /> </div> <div class="form-group"> <input type="text" name="lastName" id="lastName" class="form-control" ng-model="$ctrl.registerFormDetails.lastName" placeholder="Last Name" /> </div> ... In the main directory we create a file to contain all our scripts called dist/dependencies.js
// Libs import '../../node_modules/jquery/dist/jquery.min.js' import '../../node_modules/angular/angular.js' import '../../node_modules/angular-route/angular-route.js' import '../../node_modules/angular-cookies/angular-cookies.js' import '../../node_modules/bootstrap/dist/js/bootstrap.js' import '../../node_modules/@angular/router/angular1/angular_1_router.js' ... Then, in the index.html we import that dependency file
<script type="module" src="dist/dependencies.js"></script> make sure you add the type="module" in the script link tag.
We will create a service to handle all our requests to the backend.
First we create the follow folders called services/ and AuthenticationService/ in our app/ directory. Then we create our AuthenticationService.js file in the app/services/AuthenticationService/ directory with basic service code:
;(function () { angular.module('TodoApp').factory('AuthenticationService', [ function () { var AuthenticationService = {} return AuthenticationService } ]) })() In our app.js with add a .run() that will contain the url address to our backend url, after the .component() method close we add the follow:
... .run([ '$rootScope', function ($rootScope) { $rootScope.backendUrl = 'http://localhost:8000/api' ... Firstly, we need in inject our constant, we do this in our app/services/AuthenticationService/AuthenticationService.js file:
... '$cookieStore', '$rootScope', '$timeout', 'baseUrl', function ($http, $cookieStore, $rootScope, $timeout, baseUrl) { var AuthenticationService = {} ... Then, we scrap all our functions in app/services/AuthenticationService/AuthenticationService.js and create methods that is going to send a request to our backend.
AuthenticationService.Login = function (user) { $http .post(baseUrl + '/login', user) .success(function() { ... }) .error(function() { ... }) } ... } We will be the way we are getting data from our view and handling the requestion in the controller, by doing the following:
In auth.html,: add the ng-submit attribute
<form name="form" ng-submit="submit()" role="form"> ... In AuthCtrl.js:
AuthenticationService.Login($scope.userFormDetails) For the registeration process we will be doing a similar procedure to the login request.
In AuthCtrl.js:
AuthenticationService.Register($scope.userFormDetails) In authService.js:
AuthenticationService.Register = function (user) { $http .post(baseUrl + '/register', user) .success(function() { ... }) .error(function() { ... }) } Firstly, we create our todoTasks.html file in the app/routes/tasks/ directory with code below:
<div class="col-md-12 mt-md-2"> <ul class="list-group"> <ul class="list-group list-group-flush"> <li class="list-group-item text-center"> <span class="float-left"> <button type="button" class="btn btn-success"><span class="fa fa-check"> </span></button> </span> <span>My first todo task</span> <span class="float-right"> <a href="#/" class="btn btn-primary"><span class="fa fa-pencil"></span></a> <button type="button" class="btn btn-danger"> <span class="fa fa-trash"> </span> </button> </span> </li> </ul> </ul> </div> Finally, we create our form file called app/routes/tasks/todoTaskForm.html with code below:
<form name="todoTaskForm"> <div class="form-group"> <input type="text" class="form-control" name="title" placeholder="Task Title" required /> </div> <div class="form-group"> <button type="button" class="btn btn-success btn-lg btn-block"><span class="fa fa-save"></span> Save</button> </div> <div class="form-group"> <a href="#/" class="btn btn-default btn-lg btn-block"><span class="fa fa-remove"></span> Cancel</a> </div> </form> In the app.js add the following:
... { path: '/tasks/...', component: 'tasks', name: 'Tasks' } ... In our app/routes/tasks/ directory we create our TaskCtrl.js file with the following code:
;(function () { angular .module('app.tasks', []) .component('tasks', { ... In our app/services/ directory we create a service file to handle all our todo task requests:
app/services/taskService.js:
;(function () { angular.module('TodoApp').factory('TodoTaskService', [ function () { var TodoTaskService = {} TodoTaskService.FetchAllTodoTasks = function () {} TodoTaskService.SaveTodoTask = function (data) {} TodoTaskService.UpdateTodoTask = function (data) {} TodoTaskService.DeleteTodoTask = function (data) {} return TodoTaskService } ]) })() Linking task service with controller:
// app/routes/tasks/TaskCtrl.js .... 'TodoTaskService', function (TodoTaskService) { .... Importing file in our dependencies.js:
// dist/dependencies.js ... // Services import '../app/services/authenticationService/authenticationService.js' import '../app/services/taskService/taskService.js' We create our form file called app/directives/navbarDirective.js with code below:
;(function () { ;(function () { angular.module('app.navbar', []).component('navBar', { template: '<nav class="navbar navbar-light bg-light">'+ ' <a class="navbar-brand" href="#">Navbar</a>'+ '</nav>', ... })() For more template or how to create a navbar using bootstrap go here
Firstly, we create an update service method with the follow code:
// app/service/authService.js ... service.UpdateCurrentUsersDetails = function (data) { $http.put($rootScope.backendUrl + '/user/update', user, ) .success(function (response, status) { ... }) .error(function (err) { ... }) } ... In app/routes/profile/ we create a file profileCtrl.js and add the follow code to it:
... $ctrl.addImage = function () { var f = document.getElementById('file').files[0], r = new FileReader() $ctrl.newAvatar = true $rootScope.$apply() r.onloadend = function (e) { $ctrl.dataimg = 'data:image/jpeg;base64,' + btoa(e.target.result) var img = document.getElementById('newAvatar') img.src = $ctrl.dataimg } r.readAsBinaryString(f) } ... Then, add the link to the directive in our dist/dependencies.js under our other directives:
// Routes import '../app/routes/profile/profileCtrl.js' We can now change our view to display our existing avatar image and also change our avatar.
Add the code below at top of userProfile.html:
<!-- views/userProfile.html --> ... <!-- show image --> <div class="row row-no-margin" style="margin-bottom: 1em;"> <div class="col-xs-12 col-sm-12 col-no-padding" ng-show="filepreview == null"> <img ng-src="{{userDetails.avatar}}" alt="" style="height: 200px; width: 200px;" class="thumbnail img-responsive rounded mx-auto d-block" /> </div> </div> <!-- input type file for selecting file to upload as an avatar image --> <div class="custom-file" id="customFile" lang="es"> <div class="col-md-12"> <input type="file" fileinput="file" class="custom-file-input" filepreview="filepreview" /> <label class="custom-file-label" for="exampleInputFile"> Select image file... </label> </div> </div> ... Then we add our functions to cancel upload and upload image in our ProfileCtrl.js:
... $scope.handleAvatarUpload = function () { AuthenticationService.changeUserAvatar($scope.filepreview) .then( function(res) { ... }, function(err) { ... }) } $scope.cancelAvatarUpload = function () { // clear all binding variable here to rest file input } ... Finally, we can create our request in our service file and change avatar images from our app:
// app/service/authService.js ... service.changeUserAvatar = function (data) { $http .post($rootScope.backendUrl + '/user/avatar/new', data) .success(function (response, status) { ... }) .error(function (err) { ... }) } ...