experience with various programming languages like C#,. JavaScript ... time on the development of AngularJS .... Each an
Introduction to
All Rights Reserved © CodeValue
Shay Friedman Shay Friedman is a Co-Founder of CodeValue and Leader of its Web division. He is a Microsoft C# MVP and the author of IronRuby Unleashed. Shay started his way with computers at the age of 8 and since the age of 16 he’s been working professionally. He has experience with various programming languages like C#, JavaScript and Ruby as well as various technologies like HTML5, AngularJS, ASP.NET MVC, Ruby on Rails, Windows Azure and more. Shay has been working as a consultant and a trainer at CodeValue and has spoken in numerous international conferences like TechEd, NDC, Oredev, RubyKaigi and others.
[email protected] | @ironshay http://IronShay.com | http://CodeValue.com
Agenda • • • • •
AngularJS Overview Better HTML Services Angular for Applications Best Practices
Module 1: AngularJS Overview
Traditional Web Applications (1) Request (2) Runs logics (3) Generates HTML Web server
(4) Response
Pros: • Everything is handled in the server • Most code is written in a single programming language
Cons: • • • •
Server works very hard UI is generated on the server Major performance hit for users Not a smooth user experience
Single Page Applications (1) Request (2) Runs logics (3) Generates JSON
(5) Generates UI API web server
(4) Response
• Pros: – Full separation of concerns – Smooth and performant user experience – Less load on the server
• Cons: – More programming languages to master – Usually requires modern browsers
Single Page Applications • Also known as “SPA” • The goal is to make the web work as smooth as desktop applications • Web sites are just like any other client-server applications: – UI is responsible for itself – State! – Calls to the server are done via services, not postbacks
Overview • Started in 2009 by Misko Hevery and Adam Abrons • Abrons left the project and Hevery, who works at Google, continued with fellow Googlers • Currently 10 employees at Google work full time on the development of AngularJS • Latest stable version is 1.2.27, AKA “primefactorization” + 1.3.4, AKA “highfalutinpetroglyph”
Overview (Cont.) • Main ideas: – The MVC design pattern – Using custom HTML attributes to decouple logics from view – Dependency injection
First Example AngularJS First Example You entered: {{ txt }}
MVC Model
View
Controller
MVC • Model – the object that represents the ng-model="user.firstName">
ng-repeat • Used to loop over an array • Each iteration has its own nested scope – Includes special properties: $index, $first, $middle, $last, $even, $odd
• Supports filters $scope.arr = [{name: 'John', age: 5}, {name: 'Foo', age: 42}];
- {{ item.name }} (age {{ item.age }})
ng-click • Used to respond to clicks on DOM elements • Can contain any javascript expression • Similar attributes: ng-change, ng-dblclick, ngmousedown, ng-mouseover… $scope.do = function() { console.log("handling click!"); }; Click me!
Exercise To Do App #1
1. Create a To Do app: 1. Allow the user to manage tasks. Each task has content (text input field) and state (in progress, completed). 2. Tasks can be viewed, added and marked as completed.
ng-if, ng-show, ng-hide • Used to control the visibility of DOM elements • ng-if will remove or add an element from the DOM based on a conditional statement – Each time the element is removed from the DOM, its scope is destroyed. – Once it is added again, any direct changes to the element (via jQuery, for example) will disappear.
• ng-show and ng-hide show or hide an element based on a conditional statement
ng-if, ng-show, ng-hide $scope.type = 2;
Type is 1!
Yay! Nay!
ng-switch • ng-switch is the HTML equivalent of switchcase statements • ng-switch is used to set the expression to watch the value of. ng-switch-when is used to define the value to match. • Content of non matching “when” elements is removed from the DOM
ng-switch $scope.type = 2;
Type is 1 Type is 2 Type is unknown
ng-src, ng-href • Used to prevent strange links behavior before angular has had a chance to update the element $scope.model = {blog: 'http://ironshay.com', myImage: '../smiley.png'}; Blog
Exercise To Do App #2
1. Enhance your To Do app: 1. Add a radio button for selecting task display layouts. Possible layouts:
Checkbox layout
Box layout
ng-cloak • Prevents presenting angular expressions which haven’t been compiled yet {{ name }}
ng-options • Used on select elements to populate the option collection • When an option is selected, ng-model will be set with the option’s value • A “not selected” option can be added manually • Possible expressions for ng-options: – c.name for c in countries – c.name for c in countries track by c.id – c.name + ' (' + c.continent + ')' as c.name for c in countries – c.name group by c.continent for c in countries
ng-options $scope.countries = [ {id: 1, continent: {id: 2, continent: {id: 3, continent: {id: 4, continent: {id: 5, continent: {id: 6, continent: ];
'Europe', name: 'Israel'}, 'Europe', name: 'England'}, 'Europe', name: 'Norway'}, 'America', name: 'USA'}, 'America', name: 'Canada'}, 'Asia', name: 'China'}
ng-class • Dynamically sets CSS class to an element • Classes will be added only once $scope.showBig = true; Change Text Size …Text…
ng-include • Retrieves, compiles and includes an external HTML file • The HTML file URL must be on the same domain and protocol • Attribute onload can be used to run code when the HTML file is loaded
Exercise To Do App #3
1. Enhance your To Do app: 1. When a task is marked as completed, its background color should be light green.
Filters • Filters are used for transforming > var appModule = angular.module("myGreatApp", []);
• To retrieve an existing module: var appModule = angular.module("myGreatApp");
Angular Modules (Cont.) • It is recommended to divide the application to various modules. var controllers = angular.module("myGreatApp.controllers", []); controllers.controller("SampleController", ["$scope", "$rootScope", function($scope, $rootScope) { ... }]);
var myGreatAppModule = angular.module("myGreatApp", ["myGreatApp.controllers"]);
Angular Modules - Bootstrapping • Using a main angular module provides a way to have a function similar to Main methods in other development platforms • The function will run when the injector finishes loading all the modules var myGreatAppModule = angular.module("myGreatApp", ["myGreatApp.controllers"]); myGreatAppModule.run(function() { console.log("I'm loading!"); });
Forms • AngularJS has the capability to do form validation on the client side • Validation is done only on input fields with ngmodel • By default, angular validates input fields according to their type or attributes (required, email, maxlength…) • This does not replace server validation!
Forms CSS Classes • Angular automatically sets CSS classes to input elements according to their state: – ng-valid – the value is valid – ng-invalid – the value is invalid – ng-pristine – the value hasn’t changed – ng-dirty – the value has changed
• Form’s element is also affected
Forms CSS Classes Example Name:
E-mail:
Gender: Male Female
Save
Binding to Form and Control State • In order to display more information about validation errors to the users, it is possible to bind to the form or control state • Binding is done via the name attribute on the form and control elements • Available properties: – $dirty – a boolean value indicating the form/control has changed – $pristine – a boolean value indicating the form/control hasn’t changed – $valid – a boolean value indicating the form/control is valid – $invalid - a boolean value indicating the form/control is invalid – $error/s – an object hash with error names as keys (for example, required, max, maxlength…)
Forms State Binding Example E-mail:
Invalid:
Email is required Email is invalid Save
Exercise To Do App #7
1. Enhance your To Do app: 1. Make the task content field required 2. When the field is invalid, display an error message to the user 3. The “Add Task” button will be disabled when the form is invalid
Exception Handling • Angular has a special service that gets called whenever an unhandled exception is raised • By default it will write the exception to the console • It is possible to override this behavior by implementing the $exceptionHandler service
Exception Handling Example module.factory("$exceptionHandler", function(){ return function(exception, cause) { alert(exception + "\r\n" + cause); }; });
Localization • Angular has limited support for localization (aka i18n or l10n) • By providing a special settings file, the datetime, number and currency filters will change to the country’s ones • Built-in localization files can be found under the angular directory/i18n • Using one of these files is done by including them in the page right after angular:
Directives • “Directives are a way to teach HTML new tricks” • It is the angular way of creating reusable components • It serves as a “marker” on a DOM element to attach behavior to
Creating a New Directive • Done via module.directive • It retrieves the directive name and a factory function • The factory function contains the configuration, view details and behavior of the directive
Creating a New Directive - Name • The directive name must start with a lowercase letter • Uppercase letters will transform to dash (‘-’) and lowercase letter in the DOM: – helloWorld hello-world – thisIsMyDirective this-is-my-directive
• Best practice: start the directive name with a special prefix to prevent overlapping with 3rd party components. For example, cvDatePicker
Creating a New Directive - Template • A directive can have an HTML template attached to it • It can be set within the configuration object via the template property, or be placed in a separate file and referenced via the templateUrl property • Once the directive is compiled for the first time, angular loads the template to its template cache and uses it from there ever after
Directives – Example 1 var mainModule = angular.module("myApp", []); // Inline template mainModule.directive("smiley", function() { return { template: '' } }]);
// External template mainModule.directive("smiley", function() { return { templateUrl: 'smiley.html' } }]);
Creating a New Directive - restrict • The restrict configuration property defines where the directive is declared • Available values: – E – element name – A – attribute (default) – C – class – M – comment var mainModule = angular.module("myApp", []); mainModule.directive("smiley", function() { return { restrict: 'AECM', template: '' } }]);
Creating a New Directive - replace • When the template should entirely replace the directive element, set replace to true • If set to false (the default), the directive will be inserted inside the directive element
Creating a New Directive - scope • Every directive can have a child scope or an isolated scope • For regular child scope: scope: false • For isolated scope: – scope: true – scope: {}
Creating a New Directive - scope • The scope object hash contains info about caption="Click Here, {{fullName}}" button-click="onButtonClick()">
module.controller("MainController", function($scope, $window) { $scope.fullName = "John"; $scope.onButtonClick= function() { $window.alert($scope.fullName); }; }); module.directive("textbox", function() { return { restrict: 'E', replace: true, scope: { name: '=', caption: '@', buttonClick: '&' }, template: '' + '' + '{{caption}}' + '' }; });
Exercise To Do App #9
1. Enhance your To Do app: 1. Convert the new task textbox and button into a directive
Creating a New Directive - transclude • When you need to include arbitrary content in your directive, set transclude: true • This indicates to angular to compile the content of the directive element • Accompanied by ng-transclude which indicates the location of the content in the directive template • Important! The scope of the transcluded content is the one from outside the directive
Directives – Example 4 Hello {{ fullName }}
module.controller("MainController", function($scope, $window) { $scope.fullName = "John"; }); module.directive("panel", function() { return { restrict: 'E', replace: true, transclude: true, template: '' + '' }; });
Creating a New Directive – Defining Behavior • To define the behavior of the directive, set watches, manipulate the DOM, etc. we declare a function via the link property (aka the post-link function) • This function will be called after the template has been cloned • The function retrieves three parameters – Scope – the directive scope object – Element – the parent element of the directive. This is a jqLite object. If jQuery is included, it will be a jquery object – Attributes – an object hash of the attributes and their values. Attribute values will not be ready when the link function is called
Directives – Example 5 var mainModule = angular.module("myApp", []); mainModule.directive("showCurrentTime", ["$timeout", function($timeout) { return { link: function(scope, element, attrs) { function updateTime() { element.text(new Date()); } function setWorkInterval() { $timeout(function() { updateTime(); setWorkInterval(); }, 1000); } setWorkInterval(); }; }; }]);
Directives – Example 6 {{name}} var mainModule = angular.module("myApp", []);
mainModule.directive("blinkOnChange",[function() { return { restrict: 'E', transclude: true, replace: true, template: '', scope: { watch: '=' }, link: function(scope, element, attrs) { scope.$watch('watch', function() { $(element).fadeOut(500, function() { $(element).fadeIn(500); }); }); } }; }]);
Creating a New Directive – Cleaning up • If the directive binds itself to DOM events, create new internal scopes, etc. it needs to clean up before removal • This is done by registering to the scope $destroy event: scope.$on("$destroy", function() { // … cleanup … });
Module 5: Best Practices
AngularJS Best Practices • Modules – Create modules only when needed. For example reusable components, open source libraries, noncore features. – Have a parent module name and make the rest as nested names. For example, myApp, myApp.feature1 and myApp.feature2 – Rule of thumb – if you have a module (except for the core one) which will break your application when you remove it, you’re doing it wrong
AngularJS Best Practices • Folder Structure – /css – /images – /js • setup.js • /directives – /my-directive » my-directive.js » my-directive.html » my-directive.css
• /partials – /my-partial » my-partial.js » my-partial.html » my-partial.css
• /filters • /services
AngularJS Best Practices • Views – Prefer ng-href and ng-src when interpolating their values – Use filters to transform model data for the view – Beware of using filter and orderBy on very large collections
AngularJS Best Practices • Controllers – Controllers are not the place for DOM manipulation or data manipulation – They are strictly for scope declaration and viewrelated logic – Keep controllers simple – Rule of thumb: If you find yourself writing $(element) in a controller, you need a directive
AngularJS Best Practices • Scopes – Don’t put anything on the scope that the view does not need – Think before you $watch – Beware of scope inheritance and isolated scopes – Use $scope.$apply only when required
AngularJS Best Practices • Services – Always remember that services are singletons – Use services for business logic or communicating with the server – In extreme situations, can interact with the view (for example, for opening a dialog box)
AngularJS Best Practices • Directives – Use a prefix for your directive names – Clean up whenever needed – Prefer data-binding over $emit/$broadcast/$on – Wrap 3rd party components like jquery-ui, kendoUI and others with directives
Summary • • • • •
AngularJS Overview Better HTML Services Angular for Applications Best Practices
Thank You!