Intro to AngularJS

GDI Philly



Alexandra Hoefinger

@ahoefinger

Wifi: PromptWorks-Guest

Password: handcrafted



ahoef.co/gdi-angular/slides

ahoef.co/gdi-angular/demo-files.zip

Welcome!

Girl Develop It is here to provide affordable and accessible programs to learn software through mentorship and hands-on instruction.

Some "rules"

  • We are here for you!
  • Every question is important
  • Help each other
  • Have fun

Welcome!


Agenda — Day 1


  • Introductions
  • Overview of MVC patterns
  • Overview of a basic Angular app
  • Built-in Directives and Expressions

Welcome!


Agenda — Day 2


  • Controllers & $scope
  • Dependency Injection
  • Beyond the Basics
  • Angular 2.0

Welcome!

Tell us about yourself.

  • Who are you?
  • What do you hope to get out of the class?
  • Which of your web projects are you most proud of?

What is AngularJS?


  • A client-side JavaScript framework for extending HTML in small → large apps
  • Initially released in 2009 by Google
  • Used in production by Google, Virgin America, HBO, msnbc, Nike, Urban Outfitters, & more
  • Known for data-binding, directives, dependency injection, & more
  • Falls within the family of MV* frameworks, and is often compared to Ember.js, Backbone.js, & React

What is a MV* framework?


  • A variation of an MVC (Model View Controller)
  • Model — a type of data to model, like a user, account, photo, or note
  • View — the markup & templates for the UI
  • Controller — handles input & updates state of model
  • MVC, MVVM, MVVMCS, ...

What is a MV* framework?


What is a MV* framework?


What type of MV* is Angular?


  • There's much debate on what exactly Angular is
  • This is mainly because of how it's evolved since release, and how developers have implemented Angular apps
  • Many agree that it is an MVW (Model View Whatever)

Why Use Angular?


  • Easy to get up and running
  • Code organization
  • Speedy websites
  • Unit testing
  • Many, many resources

An example Angular App


A basic todo list app: ahoef.co/todo-list


The app's markup: github.com/ahoef/angular-todo-list-app/blob/master/index.html


  • You'll notice {{ }} and attributes beginning with ng-
  • Those are the key components of an Angular View!

Including Angular


<script src="js/angular.min.js"><script>

OR


  • Use a content distribution network for a cached file
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>

Built-In Directives


The Angular library looks for these attribute in your markup to know it should render Angular code



<body ng-app>
    <h1>Hello World!</h1>
</body>
				

ng-app is a required directive used to identify the root element and determine scope

Expressions


A way to insert data into html via a JavaScript string, number, object, or array



<body ng-app>
    <p>I have {{ 1 + 2 }} apples</p>
    <p>Our President is {{ "Barack " + "Obama" }}</p>
</body>
                

Exercise


  • Open exercises/hello-world/hello-world.html in your text editor
  • Import the Angular library
  • Assign your root element with ng-app
  • Include html with a few string & number expressions

Two-Way Data Binding


The ng-model directive binds the value of an input, select, or textarea to an object that can be used in an expression



<body ng-app>
    <label>Name:</label>
    <input type="text" ng-model="yourName">
    <hr>
    <h1>Hello {{yourName}}!</h1>
</body >
                

Two-Way Data Binding


Expressions can be inserted as the value html attributes as well as text within html tags



<body ng-app>
    <label>Name:</label>
    <input type="text" ng-model="user.status">
    <hr>
    <h1 class="status-text-{{user.status}}">Your status is: 
    {{user.status}}!</h1>
</body >
                

Exercise


  • In hello-world.html, within your ng-app, add the markup for a form input field
  • Also add the markup for a heading
  • Bind the value of the input to text within your heading tags by using ng-model
  • Try to add a few more data-bindings with ng-model!

More Built-In Directives:
ng-repeat


ng-repeat is Angular's way of looping



<body ng-app>
    <ul>
        <li ng-repeat="item in ['Sal', 'Jo', 'Amir', 'Maria']">
            {{item}} is my friend.
        </li>
    </ul>
</body >
                

More Built-In Directives:
ng-if


ng-if is Angular's if statement



<body ng-app>
    <p ng-if="'Sal' === 'Sal'">True!</p>
    <p ng-if="'Sal' === 'Jo'">False!</p>
</body >
                

More Built-In Directives:
ng-show/ng-hide


ng-show & ng-hide toggle an element's display based on value



<body ng-app>
    <p ng-show="5 > 2">Five is greater than two.</p>
    <p ng-show="2 > 5">Two is greater than five.</p>
</body >
                

Note: if the value of ng-show evaluates to false, the element will still live in the DOM

Exercise


  • In hello-world.html, within your ng-app, use ng-repeat to loop through an array of your favorite TV shows, and display each one on the page
  • Use ng-show/ng-hide or ng-if to conditionally display an image of your favorite celebrity

More Built-In Directives:
ng-init

ng-init sets an initial value

<head>
    <!-- add icon font library -->
    <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
</head>

<body ng-app>
    <nav ng-init="isOpen = false" class="mobile-nav">
        <button><i class="fa fa-bars"></i></button>
        <ul ng-show="isOpen">
            <li>Home</li>
            <li>About</li>
            <li>Blog</li>
        </ul>
    </nav>
</body >
                

More Built-In Directives:
ng-click

Angular's click listener


<body ng-app>
    <nav ng-init="isOpen = false" class="mobile-nav">
        <button ng-click="isOpen = !isOpen">
            <i class="fa fa-bars"></i>
        </button>
        <ul ng-show="isOpen">
            <li>Home</li>
            <li>About</li>
            <li>Blog</li>
        </ul>
    </nav>
</body >
                

More Built-In Directives:
ng-class

ng-class conditionally adds a class based on value


<body ng-app>
    <nav ng-init="isOpen = false" class="mobile-nav">

        <p ng-class="{'highlight': isOpen}">My Menu</p>

        <button ng-click="isOpen = !isOpen">
            <i class="fa fa-bars"></i>
        </button>
        <ul ng-show="isOpen">
            <li>Home</li>
            <li>About</li>
            <li>Blog</li>
        </ul>
    </nav>
</body >
                

More Built-In Directives:
ng-class

Here's another example:

<body ng-app>
    <nav ng-init="isOpen = false" class="mobile-nav">
        <button ng-click="isOpen = !isOpen">

            <i class="fa" ng-class="{
                'fa-caret-square-o-down': !isOpen, 
                'fa-caret-square-o-up': isOpen,}">
            </i>

        </button>
        <ul ng-show="isOpen">
            <li>Home</li>
            <li>About</li>
            <li>Blog</li>
        </ul>
    </nav>
</body >

Exercise


  • In hello-world.html, within your ng-app, add a new section or div where you set a value to true or false with ng-init
  • Within that section/div, add a button with an ng-click directive that toggles the ng-init value
  • Use ng-show or ng-hide to show/hide an image of your pet (or your favorite animal) on click of your button

Note!


It's good to know how ng-init works, but usually you'll use a controller for that purpose


Before we talk about controllers, let's talk about modules!

Modules

  • Where we write pieces of the app and define dependencies
  • Module names are bound to ng-app directives


(function(){
    angular.module('myApp', []);
})();
                

<body ng-app="myApp">
    <p>I have {{ 1 + 2 }} apples</p>
    <p>Our President is {{ "Barack " + "Obama" }}</p>
</body>

Controllers


  • They're where most of the app's functionality comes from
  • They control the data that passes through
  • They're regular JavaScript Objects
  • There can be more than one controller in an app

Controllers

in app.js

(function(){

    angular
        .module('myApp', [])

        .controller('MainController', function(){
            this.cat = cat;
        });

    var cat = {
        name: 'Ms. Whiskers',
        age: 9,
        eyes: 'blue'
    };

})();
                

Controllers


in index.html

<body ng-app="myApp">

    <section ng-controller="MainController as mainCtrl">
        <p>My cat's name is {{mainCtrl.cat.name}}</p>
        <p>She has {{mainCtrl.cat.eyes}} eyes and she's 
        {{mainCtrl.cat.age}} years old.</p>
    </section>

</body>


The scope of the controller is only within the section element!

Exercise — Part 1

  • In recipe-app/app.js, within the closure, create a module called 'recipeApp', a controller called 'RecipeController', and a variable called 'recipe'
  • Set the recipe var as an object with a few different properties, like 'name', 'ingredients', 'prepTime', 'cookTime', and 'directions'
    • Try to set one of these properties (like 'ingredients') as an array
    • Add two or three new properties as booleans, like 'isVegan', 'isGlutenFree', or 'isPaleo'
  • Set the recipe object as a property of the controller, using the 'this' keyword

Exercise — Part 2

  • In recipe-app/index.html, add an ng-app directive with the value of "recipeApp", and an ng-controller directive with the value of "RecipeController as recipeCtrl"
  • Include a few expressions referencing properties of the recipe object
  • Use ng-repeat to iterate over one of your array properties in the recipe object
  • Use ng-if or ng-show to conditionally display your boolean properties

Controllers

Often your data will be stored in an array, rather than a single object like we've seen so far


(function(){
    angular
        .module('myApp', [])

        .controller('MainController', function(){
            this.cats = cats;
        });

    var cats = [
        {
            name: 'Ms. Whiskers',
            age: 9,
            eyes: 'blue'
        },
        {
            name: 'Melvin',
            age: 1,
            eyes: 'green'
        },
        {
            name: 'Tootsie',
            age: 3,
            eyes: 'grey'
        }
    ];
})();
                

Controllers

If your data is stored in an array, you'll need to loop through it or access specific items by index number


<body ng-app="myApp">

    <section ng-controller="MainController as mainCtrl">
        <article ng-repeat="cat in mainCtrl.cats">
            <p>My cat's name is {{cat.name}}</p>
            <p>She has {{cat.eyes}} eyes and she's 
            {{cat.age}} years old.</p>
        </article>
    </section>

</body>
                

Exercise — Part 3

  • In recipe-app/app.js, change your recipe object to an array of multiple objects and update the var name from 'recipe' to 'recipes'
  • In recipe-app/index.html, use ng-repeat to loop through your recipes array and display each one on the page

Controllers

Functions can also be stored as properties


//app.js                  
angular
    .module('todoApp', [])
    .controller('TodoListController', function() {
        var todoList = this;

        todoList.todos = [
          {text:'learn angular', done:true},
          {text:'build an angular app', done:false}
        ];

        todoList.logArg = function(arg) {
            console.log(arg);
        };
    };
});
                

Controllers

And they can be called by events!



<!-- index.html -->

<body ng-app="todoApp">
    <section ng-controller="TodoListController as todoListCtrl">
        <button ng-click="todoListCtrl.logArg('hi!')">
            Log me!
        </button>
    </section>
</body >

Exercise


  • Let's look at the todo-list/todo.js & todo-list/todo-list.html
  • What are the functions in todo.js doing?
  • Which new directive in todo-list.html haven't we seen yet?

Dependency Injection


  • Dependencies are standalone modules that can be pulled into your project for different uses
  • They can be included as external files in script tags, or if you're using grunt/gulp, usually they can be included as node modules
  • Angular Local Storage is a popular module that uses the browser's local storage to persist your data without saving it to a database

Dependency Injection

                 
angular.module('todoApp', ['LocalStorageModule'])
    .controller('TodoListController', function(localStorageService) {
        var todoList = this;

        // todoList.todos = [
        //   {text:'learn angular', done:true},
        //   {text:'build an angular app', done:false}];

        var todosInStore = localStorageService.get('myTodos');
        todoList.todos = todosInStore || [];

        todoList.addTodo = function() {
          todoList.todos.push({text:todoList.todoText, done:false});
          localStorageService.set('myTodos', todoList.todos);
          todoList.todoText = '';
        };

        [...]

    });
                

Exercise

  • Include a script tag in todo-list/todo-list.html to reference localstorage.js
  • In todo-list/todo.js, include 'LocalStorageModule' as a dependency and localStorageService as an argument in your controller callback function
  • Set a var called todosInStore with the value of localStorageService.get('myTodos')

Exercise... continued

  • Comment out the array of todoList.todos, and set todoList.todos to: todosInStore || []
  • Within your addTodo function, before the line that sets an empty string, add a function to set local storage with the array of todos as its updated (localStorageService.set('myTodos', todoList.todos);)

$scope


  • Angular scope is an object that refers to the application model
  • In this workshop so far, we've been avoiding using $scope in favor of using this in our controllers to reference the application model
  • That's mainly because the $scope object is being phased out of Angular, and using this with 'controller as' syntax is now considered best practice

$scope


  • That said, at this point, we do still need to use the $scope object if we want to use some of the cool Angular features that come with it
  • For example, $watch is an API that watches/listens for changes in user input, and can run callback functions when changes occur
  • We can use $scope.$watch to save our checked off todo list items to local storage

$scope.$watch

                 
angular.module('todoApp', ['LocalStorageModule'])
    .controller('TodoListController', function($scope, localStorageService) {
        var todoList = this;

        var todosInStore = localStorageService.get('myTodos');
        todoList.todos = todosInStore || [];

        $scope.$watch('todoList.todos', function () {
          localStorageService.set('myTodos', todoList.todos);
        }, true);

        todoList.addTodo = function() {
          todoList.todos.push({text:todoList.todoText, done:false});
          //localStorageService.set('myTodos', todoList.todos);
          todoList.todoText = '';
        };

        [...]

    });
                

From here onward...


There are many more things you can do with Angular!


Angular 2.0

  • Sometime within the next year, Angular 2.0 will be released
  • It will be a rewrite largely based on ES6
  • The global $scope object & jqLite will be removed
  • The implementation of directives and controllers will change
  • But don't worry! The fundamentals you've learned in this workshop will live on!
  • Preparing for the Future of AngularJS

Next Steps

Next Steps


  • Build Something!
    • FAQ list, gallery, quiz, calculator, or whatever else you can cook up!

Questions?

?

Thank You!



http://goo.gl/forms/gsAlUKdqfS


@ahoefinger

alexandra.hoefinger@gmail.com