Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first nigh' #44

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions #serve#
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
A


BBBBBBBBBBBBBBasd
BBAABBBB
42 changes: 24 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@

This is the repository for my course **Angular Essential Training**
The full course is available at [LinkedIn Learning](https://www.linkedin.com/learning) and [lynda.com](https://lynda.com).
[LinkedIn Learning subscribers: watch here](https://www.linkedin.com/learning/angular-essential-training-2)
[Lynda.com subscribers: watch here](https://www.lynda.com/Angular-tutorials/Angular-Essential-Training/5034181-2.html)
[LinkedIn Learning subscribers: watch here](https://www.linkedin.com/learning/angular-2-essential-training-2)
[Lynda.com subscribers: watch here](https://www.lynda.com/AngularJS-tutorials/Angular-2-Essential-Training/540347-2.html)


## Course Description

Angular was designed by Google to address challenges programmers face building complex, single-page applications. This JavaScript platform provides a solid core of web functionality, letting you take care of the design and implementation details. In this course, Justin Schwartzenberger introduces you to the essentials of this "superheroic" platform, including powerful features such as two-way data binding, comprehensive routing, and dependency injection. Justin steps through the platform one feature at a time, focusing on the component-based architecture of Angular. Learn what Angular is and what it can do, as Justin builds a full-featured web app from start to finish. After mastering the essentials, you can tackle the other project-based courses in our library and create your own Angular app.
JavaScript frameworks help you code more quickly, by providing special functionality for developing specific types of web projects. Angular was designed by Google to address challenges programmers face building single-page applications. This course introduces you to the essentials of this "superheroic" framework, including declarative templates, two-way data binding, and dependency injection. Justin Schwartzenberger steps through the framework one feature at a time, focusing on the new component-based architecture of Angular. After completing this training, you'll be able to tackle the other project-based courses in our library and create your own Angular app.

Topics include:
- What is Angular?
- Working with components
- Binding events and properties
- Getting data to components
- Using directives and pipes
- Creating Angular forms
- Validating form data
- How Angular does dependency injection
- Making HTTP calls
- Routing
- Styling components
- Setting up an Angular template
- Creating a component
- Displaying data
- Working with events
- Using two-way data binding
- Creating a subcomponent
- Using the built-in HTTP module
- Using the built-in router module

## Instructions

Expand All @@ -36,10 +34,6 @@ Topics include:
3. CD to the folder

`cd angular-essential-training`

and then fetch all of the remote branches for the repository

`git fetch --all`

4. Run the following to install the project dependencies:

Expand All @@ -53,7 +47,7 @@ Topics include:

`http://localhost:4200/`

The repository has a branch for each video starting point. For example, the branch **02-01b** is used as the starting code for the video *02-01 NgModule and the root module*. You can checkout branches using `git checkout <branchname>` and not have to re-run `npm install` each time since you will remain in the same root folder.
The repository has a branch for each video starting point. For example, the branch **02-01b** is used as the starting code for the video *02-01 NgModule and the root module*. You can checkout branches using `git checkout -b <branchname>` and not have to re-run `npm install` each time since you will remain in the same root folder.


## Angular CLI
Expand All @@ -62,6 +56,18 @@ This project was generated with [Angular CLI](https://github.com/angular/angular
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).


## FAQ
If you are getting a list of errors on `npm install` that look like `Cannot find name 'Promise'`, check your `package.json` file and see if the following DevDependencies have a caret in front of the version number (the ^ symbol):
```json
"devDependencies": {

"@types/core-js": "0.9.34",
"@types/node": "6.0.41"

}
```
If the caret is there (would look like `"@types/core-js": "^0.9.34"`) then remove it (or copy the contents of the [package.json](https://github.com/coursefiles/angular2-essential-training/blob/master/package.json) file on the origin repository) and run `npm install` again.

## More Stuff
Check out some of my [other courses on LinkedIn Learning](https://www.linkedin.com/learning/instructors/justin-schwartzenberger?u=2125562).
You can also [follow me on twitter](https://twitter.com/schwarty).
27 changes: 27 additions & 0 deletions src/app/app.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
:host {
display: flex;
min-height: 100%;
}
nav {
width: 68px;
background-color: #53ace4;
}
nav .icon {
width: 48px;
height: 48px;
margin: 10px;
}
section {
width: 100%;
background-color: #32435b;
}
section > header {
color: #ffffff;
padding: 10px;
}
section > header > h1 {
font-size: 2em;
}
section > header .description {
font-style: italic;
}
8 changes: 8 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<section>
<header>
<h1>Media Watch List</h1>
<p class="description">Keeping track of the media I want to watch.</p>
</header>
<mw-media-item-form></mw-media-item-form>
<mw-media-item-list></mw-media-item-list>
</section>
8 changes: 8 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Component } from '@angular/core';

@Component({
selector: 'mw-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {}
36 changes: 36 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HttpXhrBackend } from '@angular/common/http';
import { AppComponent } from './app.component';
import { MediaItemComponent } from './media-item.component';
import { MediaItemListComponent } from './media-item-list.component';
import { FavoriteDirective } from './favorite.directive';
import { CategoryListPipe } from './category-list.pipe';
import { MediaItemFormComponent } from './media-item-form.component';
import { lookupListToken, lookupLists } from './providers';
import { MockXHRBackend } from './mock-xhr-backend';

@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule
],
declarations: [
AppComponent,
MediaItemComponent,
MediaItemListComponent,
FavoriteDirective,
CategoryListPipe,
MediaItemFormComponent
],
providers: [
{ provide: lookupListToken, useValue: lookupLists },
{ provide: HttpXhrBackend, useClass: MockXHRBackend }
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
16 changes: 16 additions & 0 deletions src/app/category-list.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'categoryList'
})
export class CategoryListPipe implements PipeTransform {
transform(mediaItems) {
const categories = [];
mediaItems.forEach(mediaItem => {
if (categories.indexOf(mediaItem.category) <= -1) {
categories.push(mediaItem.category);
}
});
return categories.join(', ');
}
}
22 changes: 22 additions & 0 deletions src/app/favorite.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Directive, HostBinding, HostListener, Input } from '@angular/core';

@Directive({
selector: '[mwFavorite]'
})
export class FavoriteDirective {
@HostBinding('class.is-favorite') isFavorite = true;

@HostBinding('class.is-favorite-hovering') hovering = false;

@HostListener('mouseenter') onMouseEnter() {
this.hovering = true;
}

@HostListener('mouseleave') onMouseLeave() {
this.hovering = false;
}

@Input() set mwFavorite(value) {
this.isFavorite = value;
}
}
52 changes: 52 additions & 0 deletions src/app/media-item-form.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
:host {
display: block;
padding: 10px;
}
ul {
list-style-type: none;
}
ul li {
margin: 10px 0;
}
header, label {
color: #53ace4;
}
input, select {
background-color: #29394b;
color: #c6c5c3;
border-radius: 3px;
border: none;
box-shadow: 0 1px 2px rgba(0,0,0,0.2) inset, 0 -1px 0 rgba(0,0,0,0.05) inset;
border-color: #53ace4;
padding: 6px;
}
.ng-invalid:not(.ng-pristine):not(.required-invalid) {
border: 1px solid #d93a3e;
}
input[required].ng-invalid {
border-right: 5px solid #d93a3e;
}
input[required]:not(.required-invalid),
input[required].ng-invalid:not(.required-invalid) {
border-right: 5px solid #37ad79;
}
.error {
color: #d93a3e;
}
#year {
width: 50px;
}
button[type=submit] {
background-color: #45bf94;
border: 0;
padding: 10px;
font-size: 1em;
border-radius: 4px;
color: #ffffff;
cursor: pointer;
}
button[type=submit]:disabled {
background-color: #333;
color: #666;
cursor: default;
}
44 changes: 44 additions & 0 deletions src/app/media-item-form.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<header>
<h2>Add Media to Watch</h2>
</header>
<form
[formGroup]="form"
(ngSubmit)="onSubmit(form.value)">
<ul>
<li>
<label for="medium">Medium</label>
<select name="medium" id="medium" formControlName="medium">
<option *ngFor="let medium of lookupLists.mediums" value="{{medium}}">{{medium}}</option>
</select>
</li>
<li>
<label for="name">Name</label>
<input type="text" name="name" id="name" formControlName="name">
<div *ngIf="form.get('name').hasError('pattern')" class="error">
Name has invalid characters
</div>
</li>
<li>
<label for="category">Category</label>
<select name="category" id="category" formControlName="category">
<option value="Action">Action</option>
<option value="Science Fiction">Science Fiction</option>
<option value="Comedy">Comedy</option>
<option value="Drama">Drama</option>
<option value="Horror">Horror</option>
<option value="Romance">Romance</option>
</select>
</li>
<li>
<label for="year">Year</label>
<input type="text" name="year" id="year" maxlength="4" formControlName="year">
<div *ngIf="form.get('year').errors as yearErrors" class="error">
Must be between
{{yearErrors.year.min}}
and
{{yearErrors.year.max}}
</div>
</li>
</ul>
<button type="submit" [disabled]="!form.valid">Save</button>
</form>
54 changes: 54 additions & 0 deletions src/app/media-item-form.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Component, OnInit, Inject } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { MediaItemService } from './media-item.service';
import { lookupListToken } from './providers';

@Component({
selector: 'mw-media-item-form',
templateUrl: './media-item-form.component.html',
styleUrls: ['./media-item-form.component.css']
})
export class MediaItemFormComponent implements OnInit {
form: FormGroup;

constructor(
private formBuilder: FormBuilder,
private mediaItemService: MediaItemService,
@Inject(lookupListToken) public lookupLists) {}

ngOnInit() {
this.form = this.formBuilder.group({
medium: this.formBuilder.control('Movies'),
name: this.formBuilder.control('', Validators.compose([
Validators.required,
Validators.pattern('[\\w\\-\\s\\/]+')
])),
category: this.formBuilder.control(''),
year: this.formBuilder.control('', this.yearValidator),
});
}

yearValidator(control: FormControl) {
if (control.value.trim().length === 0) {
return null;
}
const year = parseInt(control.value, 10);
const minYear = 1900;
const maxYear = 2100;
if (year >= minYear && year <= maxYear) {
return null;
} else {
return {
year: {
min: minYear,
max: maxYear
}
};
}
}

onSubmit(mediaItem) {
this.mediaItemService.add(mediaItem)
.subscribe();
}
}
Loading