Download Node.js, if necessary
I tried to upgrade to the latest version (7.7.4 with npm 4.1.2), but was then unable to install the Angular CLI (see below), so I downgraded to the LTS version (6.10.1 with npm 3.10.10). I was then able to install the CLI and create a new Angular app (see below). NOTE: I ran $ npm cache clean after each Node.js installation to make sure a package isn't loading anything from npm's cache. Not sure if that was necessary.
Install CLI tool and create new app
$ npm install -g @angular/cli
$ ng new app1 # 'app1' is the name of the new app
Build and serve it
$ ng serve
Visit http://localhost:4200 and you should see "app works!"
If you want to dive deeper into the CLI and learn more about its usage, have a look at its official documentation: https://github.com/angular/angular-cli/wiki
You encountered issues during the installation of the CLI or setup of a new Angular project?
A lot of problems are solved by making sure you're using the latest version of NodeJS, npm and the CLI itself.
Updating Node.js
Go to http://nodejs.org and download the latest version. May be good/necessary to uninstall older versions first (Google it).
Updating npm
$ npm install -g npm
(sudo may be required on Mac/Linux)
Updating the CLI
$ npm uninstall -g angular-cli @angular/cli
$ npm cache clean
$ npm install -g @angular/cli
Some common issues & solutions
-
EADDR error (Address already in use). You might already have another ng serve process running - make sure to quit that or use
$ ng serve --port ANOTHERPORTto serve your project on a new port -
Changes not reflected in browser (App is not compiling). Check if the window running
$ ng servedisplays an error. If that's not the case, make sure you're using the latest CLI version and try restarting your CLI
From inside the app1 folder:
$ npm i -S bootstrap
Edit the .angular-cli.json file to include Bootstrap:
"../node_modules/bootstrap/dist/css/bootstrap.min.css",Example: Generate servers component:
$ ng generate component servers
Same command using shorthand syntax:
$ ng g c servers
While I've used Sublime and experimented with WebStorm and VS Code, I'm currently using Atom. To format code, I'm currently using the prettier-atom package. Ctrl + Alt + F
You can select by element (e.g., <app-servers></app-servers>), attribute (e.g. <div app-servers></div>), or class (e.g., <div class="app-servers"></div>). You can't select by id. Typically use elements with/for components.
- Generated one with
$ ng g c SuccessAlertand one by hand. - Used
templateUrlandStyleUrlswith one andtemplateandstyles(i.e., 'inline') with the other. - Used applicable Bootstrap
alertclasses. See this video for style-by-hand example.
Videos
- String Interpolation uses
{{ someString }} - Property Binding uses
[someProperty] - Event Binding uses
(someEvent) - Combine 'Property' and 'Event' binding with
[(ngModel)]="someProperty"
Property Binding vs String Interpolation
Which Properties and Events can you bind to?
Pretty much all of them. Use console.log(foo) to see something properties and events.
Example: Binging a method to a click event:
<button class="btn btn-primary" (click)="doSomething()">Do Something</button>For Two-Way-Binding to work, you need to enable the ngModel directive. This is done by adding the FormsModule to the imports[] array in the AppModule. You then also need to add the import from @angular/forms in the app.module.ts file:
import { FormsModule } from '@angular/forms';Directives are instructions in the DOM (Components are a type of Directive with a template). Typically add directives with an Attribute selector (but can add with the other ways as well, if want/necessary).
ngIf Example
<p *ngIf="serverCreated">Server was created, server name is {{ serverName }}</p>The * is required because ngIf is a Structural Directive, which means it changes the structure of the DOM (in this case, it either adds the Element or it doesn't).
ngIf else Example
<p *ngIf="serverCreated; else noServer">Server was created, server name is {{ serverName }}</p>
<ng-template #noServer>
<p>Server has not been created yet</p>
</ng-template>The noServer is called a 'Local Reference.'
ngStyle
ngStyle is and Attribute Directive. Unlike Structural Directives, Attribute Directives don't add or remove elements. Instead, they change the element they are placed on.
ngClass
ngFor
A recipe book / shopping list app. See video clip.
Intro Videos
Project Setup
$ ng new proj1
$ cd proj1
$ ng serve
Install Bootstrap
$ npm i -S bootstrap
Edit .angular-cli.json to add "../node_modules/bootstrap/dist/css/bootstrap.min.css", line to styles array. Edit app.component.html to 'Hello World' Bootstrap.
$ ng serve
Create Components
- Create
headercomponent manually (for practice). - Create all other components with the CLI:
$ ng g c recipes --spec false
$ ng g c recipes/recipe-list --spec false
$ ng g c recipes/recipe-list/recipe-item --spec false
$ ng g c recipes/recipe-detail --spec false
$ ng g c shopping-list --spec false
$ ng g c shopping-list/shopping-edit --spec false
Place Components
Unix Command to Find and Remove Files
I used this to remove files ending in .orig after using resolving merge conflict:
$ find . -type f -name '*.orig' -delete
- Source (StackExchange Recursively delete all files with a given extension)
- More about the
findcommand (CyberCiti.biz FAQ)
Configure Navbar
Create Recipe Model
Design RecipeItem
Output List of Recipes With ngFor
Design RecipeDetail
Design ShoppingListComponent
Create Ingredient Model
Creating and Outputting the Shopping List
Design ShoppingEditComponent
Next Steps
- Angular Error Messages
- Debugging Code in the Browser Using Sourcemaps
- Using Augury to Dive into Angular Apps
- Intro
- Splitting Apps into Components
- Property & Event Binding Overview
- Binding to Custom Properties (good video to rewatch)
- Assigning an Alias to Custom Properties
- Binding to Custom Events (good video to rewatch)
- Assigning an Alias to Custom Events
- Custom Property and Event Binding Summary
- Understanding View Encapsulation
- More on View Encapsulation
- Using Local References in Templates (good video to rewatch)
- Getting Access to the Template & DOM with @ViewChild (good video to rewatch)
- Projecting Content into Components with ng-content (good video to rewatch)
- Understanding the Component Lifecycle, such as ngOnInit (good video to rewatch)
- Seeing Lifecycle Hooks in Action (good video to rewatch)
- Lifecycle Hooks and Template Access (good video to rewatch)
- Getting Access to ng-content with @ContentChild (good video to rewatch)
- Wrap Up
Great practice. See video and commits for details ($ git log --grep="Ass 4").
Videos
- Adding Navigation with Event Binding and ngIf
- Passing Recipe Data with Property Binding
- Passing Data with Event and Property Binding (Combined)
- Allowing the User to Add Ingredients to the Shopping List
Videos
- Module Introduction
- ngFor and ngIf Recap
- ngClass and ngStyle Recap
- Creating a Basic Attribute Directive
- Using the Renderer to build a Better Attribute Directive
$ ng g d better-highlight --spec false
- More about the Renderer
- Using HostListener to Listen to Host Events
- Using HostBinding to Bind to Host Properties
- Binding to Directive Properties
- What Happens behind the Scenes on Structural Directives
- Building a Structural Directive
- Understanding ngSwitch
Building and Using a Dropdown Directive video
Videos
- What Are Services
- Why would you Need Services?
- Creating a Logging Service
- Injecting the Logging Service into Components
- Creating a Data Service
- Understanding the Hierarchical Injector
- How many Instances of Service Should It Be?
- Injecting Services into Services
- Using Services for Cross-Component Communication
Practice
Videos
- Introduction
- Setting up the Services
- Managing Recipes in a Recipe Service
- Using a Service for Cross-Component Communication
- Adding the Shopping List Service
- Using Services for "Push Notifications"
- Adding Ingredients to Recipes
- Passing Ingredients from Recipes to the Shopping List (via a Service)
- Module Introduction
- Why do we need a Router?
- Understanding the Example Project
- Setting up and Loading Routes
- Navigating with Router Links
- Understanding Navigation Paths
- Styling Active Router Links
- Navigating Programmatically
- Using Relative Paths in Programmatic Navigation
- Passing Parameters to Routes
- Fetching Route Parameters
- Fetching Route Parameters Reactively
- An Important Note about Route Observables
- Passing Query Parameters and Fragments
- Retrieving Query Parameters and Fragments
- Practicing and some Common Gotchas
- Setting up Child (Nested) Routes
- Using Query Parameters - Practice
- Configuring the Handling of Query Parameters
- Redirecting and Wildcard Routes
- Important: Redirection Path Matching
- Outsourcing the Route Configuration
- An Introduction to Guards
- Protecting Routes with canActivate
- Protecting Child (Nested) Routes with canActivateChild
- Using a Fake Auth Service
- Controlling Navigation with canDeactivate (good video to rewatch)
- Passing Static Data to a Route(good video to rewatch)
- Resolving Dynamic Data with the Resolve Guard(good video to rewatch)
- Understanding Location Strategies
- Planning the General Structure
- Setting Up Routes
- Adding Navigation to the App
- Marking Active Routes
- Fixing Page Reload Issues
- Child Routes: Challenge
- Adding Child Routing Together
- Configuring Route Parameters
- Passing Dynamic Parameters to Links
- Styling Active Recipe Items
- Adding Editing Routes
- Retrieving Route Parameters
- Programmatic Navigation to the Edit Page
- One Note about Route Observables
- Project Cleanup
- Module Introduction
- Analyzing a Built-in Angular Observable
- Building & Using a First Simple Observable
- Building & Using a Custom Observable from Scratch
- Unsubscribe!
- Where to learn more
- Using Subjects to Pass AND Listen to Data
- Understanding Observable Operators
- Wrap Up
- Module Introduction
- Why do we Need Angular's Help?
- Template-Driven (TD) vs Reactive Approach
- An Example Form
- TD: Creating the Form and Registering the Controls
- TD: Submitting and Using the Form
- TD: Understanding Form State
- TD: Accessing the Form with @ViewChild
- TD: Adding Validation to check User Input
- Built-in Validators & Using HTML5 Validation
- For the Template-driven approach, you need the directives. Find their names by searching for "validator" here in the Angular docs. Everything marked with "D" is a directive and can be added to your template.
- For the Reactive approach, see the Angular docs Validators class
- You can also enable HTML5 validation (by default, Angular disables it) by adding the
ngNativeValidateto a control in your template.
- TD: Using the Form State
- TD: Outputting Validation Error Messages
- TD: Set Default Values with ngModel Property Binding
- TD: Using ngModel with Two-Way-Binding
- TD: Grouping Form Controls
- TD: Handling Radio Buttons
- TD: Setting and Patching Form Values
- TD: Using Form Data
- TD: Resetting Forms
- Assignment 6: Practicing Template-Driven Forms
- Assignment 6: Instructor Solution (good video to rewatch)
- Introduction to the Reactive Approach
- Reactive: Setup
- Reactive: Creating a Form in Code
- Reactive: Syncing HTML and Form
- Reactive: Submitting the Form
- Reactive: Adding Validation
- Reactive: Getting Access to Controls
- Reactive: Grouping Controls
- Reactive: Arrays of Form Controls (FormArray)
- Reactive: Creating Custom Validators
- Reactive: Using Error Codes
- Reactive: Creating a Custom Async Validator
- Reactive: Reacting to Status or Value Changes
- Reactive: Setting and Patching Values
- Assignment 7: Practicing Reactive Forms
- Assignment 7 Instructions
- Assignment 7 Solution (good video to rewatch)
Setting Default Option Selection
HTML (standard way, I think, to dynamically populate the options):
<form [formGroup]="signupForm" (ngSubmit)="onSaveProject()">
<div class="form-group">
<label for="status">Project Status:</label>
<select name="status" formControlName="status" [(ngModel)]="signupForm.statusChoices" class="form-control">
<option *ngFor="let choice of statusChoices" [value]="choice">{{ choice }}</option>
</select>
</div>
</form>TS (the setTimeout() is the thing that does the thing):
export class AppComponent implements OnInit {
signupForm: FormGroup;
statusChoices = ['Stable', 'Critical', 'Finished'];
defaultStatus = 'Critical';
ngOnInit() {
this.signupForm = new FormGroup({
projectname: new FormControl(
null,
[Validators.required, CustomValidators.invalidProjectName],
CustomValidators.asyncInvalidProjectName,
),
email: new FormControl(null, [Validators.required, Validators.email]),
status: new FormControl(null),
});
setTimeout(() => {
this.signupForm.controls['status'].patchValue(this.defaultStatus);
}, 0);
}
onSaveProject() {
console.log(this.signupForm);
}
}Source: how i can set default value ? #17
- Introduction
- TD: Adding the Shopping List Form
- Adding Validation to the Form
- Allowing the Selection of Items in the List (good video to rewatch)
- Loading the Shopping List Items into the Form
- Updating existing Items
- Resetting the Form
- Allowing the the User to Clear (Cancel) the Form
- Allowing the Deletion of Shopping List Items
- Creating the Template for the (Reactive) Recipe Edit Form
- Creating the Form For Editing Recipes
- Syncing HTML with the Form
- Adding Ingredient Controls to a Form Array
- Adding new Ingredient Controls
- Validating User Input
- Submitting the Recipe Edit Form
- Adding a Delete and Clear (Cancel) Functionality
- Redirecting the User (after Deleting a Recipe)
- Adding an Image Preview
- Providing the Recipe Service Correctly
- Deleting Ingredients and Some Finishing Touches
- Introduction & Why Pipes are Useful
- Using Pipes
- Parametrizing Pipes
- Where to learn more about Pipes
- Chaining Multiple Pipes
- Creating a Custom Pipe
- Parametrizing a Custom Pipe
- Example: Creating a Filter Pipe
$ ng g p filter - Pure and Impure Pipes (or: How to "fix" the Filter Pipe)
- Understanding the "async" Pipe
- Assignment 8: Practicing Pipes: Instructions
- Assignment 8: Practicing Pipes: Solution
- Introduction & How Http Requests Work in SPAs
- Example App & Backend Setup
- Sending Requests (Example: POST Request)
- Adjusting Request Headers
- Sending GET Requests
- Sending a PUT Request
- Transform Responses Easily with Observable Operators (map())
- Using the Returned Data
- Catching Http Errors
- Using the "async" Pipe with Http Requests
- Introduction
- Setting up Firebase as a Dummy Backend
- Sending PUT Requests to Save Data
- GETting Back the Recipes
- Transforming Response Data to Prevent Errors
- Module Introduction
- How Authentication Works in Single-Page-Applications
- More about JWT
- Creating a Signup Page and Route
- Setting up the Firebase SDK
$ npm i -S firebase - Signing Users Up
Troubleshooting:
Got this error which was fixed with:
$ npm install promise-polyfill --save-exact
$ npm i
- Signin Users In
- Requiring a Token (on the Backend)
- Sending the Token
- Checking and Using Authentication Status
- Adding a Logout Button
- Route Protection and Redirection Example
- Wrap Up
- Possible Improvements TODO:
- Check if a token is present at application startup (check the localStorage manually or use the Firebase SDK to do so - make sure to wait for the SDK to finish its initialization)
- Redirect the user if they want to access a protected route - inject the router and call this.router.navigate(...)
- Redirect the user on logout so that they're not able to stay on pages which are reserved for authenticated users - you can simply inject the router and call this.router.navigate(...) in the logout() method
- Module Introduction
- The Idea behind Modules
- Understanding the App Module
- Understanding Feature Modules
- Creating a Recipe Feature Module (good video to rewatch)
- Registering Routes in a Feature Module (good video to rewatch)
- Understanding Shared Modules
- Creating a Shared Module (good video to rewatch)
- Creating a Shopping List Feature Module
- Loading Components via Selectors vs Routing
- A Common Gotcha
- Creating the Auth Feature Module
- Understanding Lazy Loading
- Adding Lazy Loading to the Recipes Module
- Protecting Lazy Loaded Routes with canLoad
What if you want to use route protection (
canActivateto be precise) on lazily loaded routes?
You can add canActivate to the lazy loaded routes but that of course means, that you might load code which in the end can't get accessed anyways. It would be better to check that BEFORE loading the code.
You can enforce this behavior by adding the canLoad guard to the route which points to the lazily loaded module:
{ path: 'recipes', loadChildren: './recipes/recipes.module#RecipesModule', canLoad: [AuthGuard] }In this example, the AuthGuard should implement the CanLoad interface.
- How Modules and Services Work Together (good video to rewatch)
- Understanding the Core Module
- Creating a Basic Core Module
- Restructuring Services to use the Child Injector
- Using Ahead-of-Time Compilation
- How to use AoT Compilation with the CLI
$ ng build --prod --aot - Preloading Lazy Loaded Routes
- Wrap Up
- Module Introduction
- Deployment Preparations and Important Steps
- Example: Deploying to AWS S3 '$ ng build --prod --aot'
With the release of Angular 4, the general syntax of Angular Animations didn't change.
However, the animation functions were moved into their own package and you now also need to add a special module to your imports[] array in the AppModule.
Specifically, the following adjustments are required:
-
You probably need to install the new animations package (running the command never hurts):
$ npm install --save @angular/animations -
Add the
BrowserAnimationsModuleto yourimports[]array in AppModule -
This Module needs to be imported from @angular/platform-browser/animations' =>
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'(in the AppModule!) -
You then import
trigger,state,styleetc from@angular/animationsinstead of@angular/core
- About this Section
- Introduction
- Why Unit Tests?
- Analyzing the Testing Setup (as created by the CLI)
- Running Tests (with the CLI)
$ ng test - Adding a Component and some fitting Tests
- Testing Dependencies: Components and Services
- Simulating Async Tasks
- Using "fakeAsync" and "tick"
- Isolated vs Non-Isolated Tests
- Further Resources & Where to Go Next
- Official Docs: https://angular.io/docs/ts/latest/guide/testing.html
- Article: https://semaphoreci.com/community/tutorials/testing-components-in-angular-2-with-jasmine
- More Information on how to run Tests with the CLI:
- Introduction
- Initializing the Project
- Setting up the Basic Project Files
- Installing the Core Dependencies
- Filling the Project Files with Some Life
- index.html & Polyfills
- Installing Development Dependencies
- Setting up a Development Workflow
- Finishing & Using the Development Workflow
- Setting up a Production Workflow
- Adding Types & Fixing Bugs
- Finishing Touches
- If user clicks New Recipe button when not logged in, do something (such as display message saying they must be signed in or redirect them to sign-in).