Angular is known for rapid dev cycles and one page apps that are responsive.
Why Angular?
What is it and how does it work?
Browser - referred to as client.
Angular apps lives 100% on the client. When the user makes a request, the entire app comes back. Made up entirely in JavaScript. Unlike things like Django and Express...
Makes additional calls via Ajax, but only for the data. Most of the time, it is JSON.
Angular is referred to as a Client Side Application Framework. App can even send data back to the server.
Other examples: Backbone, Ember.
Four main concepts:
<directives>
manipulate data (can create custom)eg.
myApplicationTemplate.html
<my-awesome-directive></my-awesome-directive>
QUESTIONS
A: False
CDN for Angular: <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
Otherwise, download from Angular website.
First thing to do is use angular module method.
// in app.js angular.module('todoListApp', []); //array defines the dependencies // in index.html `<body ng-app="todoListApp">`; //tells angular where to bootstrap
in the Angular set up so far...
(from top level) index.html scripts (directory) - scripts/app.js styles - styles/main.css - styles/hello-world.js
vendor - vendor/angular.js
// in vendor/hello-world.js angular.module('todoListApp') //no second param, since no new module. It will then look for it. .directive('helloWorld', function() { return { template: "This is the hello world directive!"; }; }); // now can include <hello-world></hello-world> //changes from camelcase to lowercase tags // template is then injected into the tags! How to do as attributes of tags? Change the tag into a div: <div hello-world></div> // in vendor/hello-world.js angular.module('todoListApp') //no second param, since no new module. It will then look for it. .directive('helloWorld', function() { return { template: "This is the hello world directive!"; restrict: "E" //only use as an element or only as an element attribute -> elements being the <hello-world></hello-world> }; });
The glue that hold the apps together
To create the controller, we use the controller method in app.js
//scripts/app.js
angular.module('todoListApp', []).controller('mainCtrl', function($scope) { //to us controller, you need to inject with ng-controller in html $scope.helloWorld = function() { console.log( 'Hello there! This is the Hello World Controller function in the mainCtrl!', ); }; }); //in index.html <div ng-controller="mainCtrl" class="list"> ... //all within the scope <a href="" ng-click="helloWorld()"> Save </a> //fires the ctrl function ... </div>;
"Injecting a controller": Use the controller here.
2 Angular Chrome Plugins
ng-inspector AngularJS Batarang
Scope works with prototypical inheritance
After creating hello world in both hello world ctrl and coolctrl... helloWorld() now is defined by the closest scope! Ctrl only inherits if it is not defined within itself.
Only flows from parent to child. Sibling controllers do not have access to other scopes.
Helps a lot out of the box.
Data-binding is the key concept of this video.
Data-binding is where applications data and variables come together.
Example: The data field.
Using the ng-model directive.
//in index.html <input ng-model="todo" ... />
Once we start typing, the todo variable is initialised. Changes dynamically.
This is the two-way data binding at work.
<input ng-model="todo.name" ... /> <!-- Checkbox... --> <input ng-model="todo.completed" ... /> //becomes true when checked/unchecked <!-- Inside label... --> <label ...>{{todo.name}}</label>
<input>
ng-click="editing = !editing" //can be used with any elements as an attribute
ng-hide="editing" //in the appropriate element ng-show="editing"
//index.html
<!doctype html> <html lang="en"> <head> <title></title> <link href='https://fonts.googleapis.com/css?family=Varela+Round' rel='stylesheet' type='text/css'> </head> <body ng-app="todoListApp"> <h1 ng-click="helloConsole()">My TODOs!</h1> <div class="list" ng-controller="mainCtrl"> <input type="checkbox" ng-model="todo.completed"> <label ng-hide="editing">{{todo.name}}</label> <input ng-show="editing" class="editing-label" type="text" ng-model="todo.name"> <div class="actions"> <a href="" ng-click="editing = !editing">Edit</a> <a href="" ng-click="helloConsole()">Save</a> <a href="" class="delete">Delete</a> </div> </div> <script src="vendor/angular.js"></script> <script src="scripts/app.js"></script> </body> </html>
Paste array and check if within scope.
<div ng-repeat="todo in todos"> ... </div>
Each item makes each unique item from repeat. The directives and controller data also repeats with new scopes.
NG-BLUR
in the input...
<input ng-blur="editing = false;" ng-show="editing" ng-model="todo.name" class="editing-label" type="text"/> //false because it only goes one way
NG-CLASS
ng-class="{'editing-item': editing}" //class is editing-item
//fires any time the value of the input changes
ng-change="learningNgChange()" //scope function // in the controller... $scope.learningNgChange = function() { console.log("Input change"); }; //making the directive useful ng-change="todo.edited = true"
CHALLENGE
<!doctype html> <html lang="en"> <head> <title></title> <link href='https://fonts.googleapis.com/css?family=Varela+Round' rel='stylesheet' type='text/css'> </head> <body ng-app="todoListApp"> <h1 ng-click="helloConsole()">My TODOs!</h1> <div class="list" ng-controller="mainCtrl"> <div class="item" ng-class="{'editing-item': editing, 'edited': todo.edited}" ng-repeat="todo in todos"> <input type="checkbox" ng-model="todo.completed"> <label ng-hide="editing">{{todo.name}}</label> <input ng-show="editing" ng-blur="editing = false" class="editing-label" type="text" ng-change="todo.edited = true" ng-model="todo.name"> <div class="actions"> <a href="" ng-click="editing = !editing">Edit</a> <a href="" ng-click="helloConsole()">Save</a> <a href="" class="delete">Delete</a> </div> </div> </div> <script src="vendor/angular.js"></script> <script src="scripts/app.js"></script> </body> </html>
Services used for dependency injection.
Multiple controllers can use the service is declared as a dependency.
Useful for many things eg. REST API etc
//in app.js .service("dataService", function() { this.helloConsole = function() { console.log("Hello String!"); } }); //in the .controller func from above - data service is now the second parameter .controller("mainCtrl", function($scope, dataService) { $scope.helloConsole = dataService.helloConsole; ... //info });
Request fake data from a server.
//in app.js .controller("mainCtrl", function($scope, dataService) { ... //info dataService.getTodos(function(response) { $scope.todos = response.data; }); }); .service("dataService", function($http) { this.helloConsole = function() { console.log("Hello String!"); } //built ins are called providers this.getTodos = function(callback) { $http.get('mock/todos.json') .then(callback) //first arg takes url } });
//in app.js .controller("mainCtrl", function($scope, dataService) { ... //info dataService.getTodos(function(response) { $scope.todos = response.data; }); $scope.deleteTodo = function(todo, $index) { dataService.deleteTodo(todo); //then add to html using ng-click="deleteTodo(todo, $index)" $scope.todos.splice($index, 1); } $scope.saveTodo = function(todo) { dataService.saveTodo(todo); //use ng-click="saveTodo(todo)" } }); .service("dataService", function($http) { this.helloConsole = function() { console.log("Hello String!"); } //built ins are called providers this.getTodos = function(callback) { $http.get('mock/todos.json') .then(callback) //first arg takes url } this.deleteTodo = function(todo) { console.log("Todo Deleted"); //simulate communicated with database //other logic }; this.saveTodo = function(todo) { console.log("Todo saved"); //other logic }; });
//in index/html <div class="add"> <a href="">Add a New Task</a> </div>
//in app.js .controller("mainCtrl", function($scope, dataService) { ... //info $scope.addTodo = function() { var.todo = {name: "This is a new todo."}; $scope.todos.push(todo); }; dataService.getTodos(function(response) { $scope.todos = response.data; }); $scope.deleteTodo = function(todo, $index) { dataService.deleteTodo(todo); //then add to html using ng-click="deleteTodo(todo, $index)" $scope.todos.splice($index, 1); } $scope.saveTodo = function(todo) { dataService.saveTodo(todo); //use ng-click="saveTodo(todo)" } }); .service("dataService", function($http) { this.helloConsole = function() { console.log("Hello String!"); } //built ins are called providers this.getTodos = function(callback) { $http.get('mock/todos.json') .then(callback) //first arg takes url } this.deleteTodo = function(todo) { console.log("Todo Deleted"); //simulate communicated with database //other logic }; this.saveTodo = function(todo) { console.log("Todo saved"); //other logic }; }); CHALLENGE Create a service which logs a callback. angular.module('foobar', []) .service("myService", function() { this.testingMyService = function() { console.log("This is my service!"); } });
For managing, we scaffold:
main.js //controllers folder -> main controller 'use strict'; //interpreted in strict mode //add in .controller angular.module("todoListApp") //don't provide dependencies parameter this time .controller(...) Make sure you load the scripts! //repeat process for data service //data.js 'use strict'; angular.module("todoListApp") .service(...)
App.js may appear empty
ng-repeat saves a ton of time, but we need complete UI states etc.
Adds complete class when todo.completed = true ng-class="{..., "complete": todo.completed} //to move to the bottom ng-repeat="todo in todos | orderBy: 'completed'" //sets or using the pipe ng-repeat="todo in todos | orderBy: 'completed' : true" ng-init="todo.completed = false" //only used with ng-repeat
Need to also make sure that in the controller, we have unshift instead of push for the array.
Remove todos and create custom directive
Create templates/todos.html
Create scripts/directives/todos.js
angular.module("todoListApp") .directive('todos' function() { return { templateUrl: 'templates/todos.html', controller: 'mainCtrl' //can define the controller too, replace: true } });
To get rid of directive tags, use the replace key.
for the save in main.js...
.controller(... function() { ... $scope.saveTodos = function() { var filteredTodos = $scope.todos.filter(function(todo) { if (todo.edited) { return todo; }; }) dataService.saveTodos(filteredTodos); } })
QUESTIONS
A: 'templateUrl'
['foo', 'bar', 'yes', 'no'].someMethod(callback)
.A: filter
A: 'controller'
directive
method is **__**.A: The name of the directive