Skip to content

Commit fd33ec1

Browse files
committed
Curriculum: Validators + Sync Validators
1 parent a888687 commit fd33ec1

File tree

92 files changed

+331094
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+331094
-0
lines changed

43-validators-object/.editorconfig

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# EditorConfig helps developers define and maintain consistent
2+
# coding styles between different editors and IDEs
3+
# editorconfig.org
4+
5+
root = true
6+
7+
[*]
8+
9+
# Change these settings to your own preference
10+
indent_style = space
11+
indent_size = 2
12+
13+
# We recommend you to keep these unchanged
14+
end_of_line = lf
15+
charset = utf-8
16+
trim_trailing_whitespace = true
17+
insert_final_newline = true
18+
19+
[*.md]
20+
trim_trailing_whitespace = false

43-validators-object/.gitignore

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Project
2+
.idea
3+
4+
# Node
5+
node_modules
6+
7+
# macOS
8+
.DS_Store
9+
.AppleDouble
10+
.LSOverride
11+
Icon
12+
._*
13+
.Spotlight-V100
14+
.Trashes
15+
16+
## Windows
17+
Thumbs.db
18+
ehthumbs.db
19+
Desktop.ini
20+
$RECYCLE.BIN/
21+
22+
# Package Managers
23+
yarn-error.log
24+
npm-debug.log
25+
26+
# Cache
27+
.awcache

43-validators-object/README.md

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<a href="https://ultimateangular.com" target="_blank"><img src="https://toddmotto.com/img/ua.png"></a>
2+
3+
# Angular Fundamentals Seed
4+
5+
> This is the seed project for the [Angular Fundamentals](https://ultimateangular.com/courses/#angular-2) course by [Todd Motto](https://twitter.com/toddmotto).
6+
7+
## Project Setup and Tooling
8+
9+
### Tools
10+
11+
This course is recorded with the following tools, you can optionally follow along using the same, or your favourite text editor/IDE and browser.
12+
13+
*Text editor*: Visual Studio Code, you can [download it here](http://code.visualstudio.com) for both Mac, Windows and Linux.
14+
*Browser*: Google Chrome, you can [download it here](https://www.google.com/chrome)
15+
16+
### Prerequisites
17+
18+
Please make sure that you have the following installed:
19+
20+
* Install the _latest version_ of [Node.js](http://nodejs.org) (Mac or Windows)
21+
* Mac users can optionally `brew install node` if they have [brew](http://brew.sh) installed
22+
23+
* Node Sass, you _may_ need it if you haven't already got it installed:
24+
25+
```bash
26+
npm install -g node-sass
27+
```
28+
29+
### Project Install
30+
31+
To grab the seed project, either Fork this repo or [click here to download](https://github.com/UltimateAngular/angular-fundamentals-seed/archive/master.zip) the `.zip` folder and extract the files wherever you like on your machine.
32+
33+
#### Step 1: Package Manager
34+
35+
To install the project dependencies, you will need to install `yarn`. To install `yarn`, run the following in your terminal:
36+
37+
```bash
38+
npm install -g yarn
39+
```
40+
41+
Mac users can alternatively use `brew` to install `yarn`.
42+
43+
```bash
44+
brew update
45+
brew install yarn
46+
```
47+
48+
If you experience any issues when installing/using `yarn` you can checkout the installation instructions [here](https://yarnpkg.com/en/docs/install).
49+
50+
##### Step 2: Project Dependencies
51+
52+
Now that we have a package manager, we can install the project dependencies. You can do this by running:
53+
54+
```bash
55+
yarn install
56+
```
57+
58+
This will install our dependencies for running our Angular application.
59+
60+
#### Step 3: Running the project
61+
62+
During development, the project is built using `webpack-dev-server`. This provides a local development server as well as having webpack recompile our app when a file changes. The project will also automatically refresh the page whenever we make changes.
63+
64+
To start the project in development, run:
65+
66+
```
67+
yarn start
68+
```
69+
70+
This will output some information about the project (such as the TypeScript version and build progress). Once you see "build completed", you are ready to code!
71+
72+
Open your browser to [localhost:4000](http://localhost:4000) to start running the code.
73+
74+
### Project Tooling
75+
76+
The project uses `webpack` to build and compile all of our assets. This will do the following for us:
77+
78+
- Compile all our TypeScript code into JavaScript (starting from `main.ts` and branching outwards from imported files)
79+
- Bundle all our JavaScript into one file to use
80+
- Allow us to use SASS for our component's CSS files
81+
- Provide the polyfills needed to run our app in all modern browsers
82+
- Mock a JSON backend using [json-server](https://github.com/typicode/json-server)
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Component } from '@angular/core';
2+
@Component({
3+
selector: 'app-root',
4+
template: `
5+
<div>
6+
<stock-inventory></stock-inventory>
7+
</div>
8+
`
9+
})
10+
export class AppComponent {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NgModule } from '@angular/core';
2+
import { BrowserModule } from '@angular/platform-browser';
3+
4+
import { StockInventoryModule } from './stock-inventory/stock-inventory.module';
5+
6+
import { AppComponent } from './app.component';
7+
8+
@NgModule({
9+
declarations: [
10+
AppComponent
11+
],
12+
imports: [
13+
BrowserModule,
14+
StockInventoryModule
15+
],
16+
bootstrap: [
17+
AppComponent
18+
]
19+
})
20+
export class AppModule {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
:host {
2+
border-bottom: 1px solid #ccc;
3+
margin: 0 0 20px;
4+
padding: 0 0 20px;
5+
display: block;
6+
}
7+
.error {
8+
background: #B52D30;
9+
color: #fff;
10+
font-weight: 500;
11+
font-size: 12px;
12+
text-transform: uppercase;
13+
border-radius: 0 0 3px 3px;
14+
line-height: 1;
15+
padding: 6px 10px;
16+
margin-top: -1px;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Component, Input } from '@angular/core';
2+
import { FormGroup } from '@angular/forms';
3+
4+
@Component({
5+
selector: 'stock-branch',
6+
styleUrls: ['stock-branch.component.scss'],
7+
template: `
8+
<div [formGroup]="parent">
9+
<div formGroupName="store">
10+
<input
11+
type="text"
12+
placeholder="Branch ID"
13+
formControlName="branch">
14+
<div
15+
class="error"
16+
*ngIf="required('branch')">
17+
Branch ID is required
18+
</div>
19+
<input
20+
type="text"
21+
placeholder="Manager Code"
22+
formControlName="code">
23+
<div
24+
class="error"
25+
*ngIf="required('code')">
26+
Manager ID is required
27+
</div>
28+
</div>
29+
</div>
30+
`
31+
})
32+
export class StockBranchComponent {
33+
@Input()
34+
parent: FormGroup;
35+
36+
required(name: string) {
37+
return (
38+
this.parent.get(`store.${name}`).hasError('required') &&
39+
this.parent.get(`store.${name}`).touched
40+
);
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.stock-counter {
2+
&.focused {
3+
box-shadow: 0 1px 1px rgba(0,0,0,.3);
4+
}
5+
background: rgba(0, 0, 0, 0.05);
6+
border-radius: 3px;
7+
overflow: hidden;
8+
& > div > div {
9+
display: flex;
10+
align-items: center;
11+
12+
& > div {
13+
display: flex;
14+
flex-direction: column;
15+
}
16+
}
17+
18+
p {
19+
font-size: 16px;
20+
font-weight: 400;
21+
text-align: center;
22+
width: 50px;
23+
}
24+
25+
button {
26+
padding: 3px;
27+
border-radius: 0;
28+
line-height: 1;
29+
padding: 3px 7px;
30+
background: #9E61C8;
31+
color: #fff;
32+
font-weight: 500;
33+
&:disabled {
34+
background: rgba(0, 0, 0, 0.1);
35+
color: rgba(0, 0, 0, 0.4);
36+
}
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { Component, Input, forwardRef } from '@angular/core';
2+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
3+
4+
const COUNTER_CONTROL_ACCESSOR = {
5+
provide: NG_VALUE_ACCESSOR,
6+
useExisting: forwardRef(() => StockCounterComponent),
7+
multi: true
8+
};
9+
10+
@Component({
11+
selector: 'stock-counter',
12+
providers: [COUNTER_CONTROL_ACCESSOR],
13+
styleUrls: ['stock-counter.component.scss'],
14+
template: `
15+
<div
16+
class="stock-counter"
17+
[class.focused]="focus">
18+
<div>
19+
<div
20+
tabindex="0"
21+
(keydown)="onKeyDown($event)"
22+
(blur)="onBlur($event)"
23+
(focus)="onFocus($event)">
24+
<p>{{ value }}</p>
25+
<div>
26+
<button
27+
type="button"
28+
(click)="increment()"
29+
[disabled]="value === max">
30+
+
31+
</button>
32+
<button
33+
type="button"
34+
(click)="decrement()"
35+
[disabled]="value === min">
36+
-
37+
</button>
38+
</div>
39+
</div>
40+
</div>
41+
</div>
42+
`
43+
})
44+
export class StockCounterComponent implements ControlValueAccessor {
45+
46+
private onTouch: Function;
47+
private onModelChange: Function;
48+
49+
registerOnTouched(fn) {
50+
this.onTouch = fn;
51+
}
52+
53+
registerOnChange(fn) {
54+
this.onModelChange = fn;
55+
}
56+
57+
writeValue(value) {
58+
this.value = value || 0;
59+
}
60+
61+
@Input() step: number = 10;
62+
@Input() min: number = 10;
63+
@Input() max: number = 1000;
64+
65+
value: number = 10;
66+
67+
focus: boolean;
68+
69+
onKeyDown(event: KeyboardEvent) {
70+
71+
const handlers = {
72+
ArrowDown: () => this.decrement(),
73+
ArrowUp: () => this.increment()
74+
};
75+
76+
if (handlers[event.code]) {
77+
handlers[event.code]();
78+
event.preventDefault();
79+
event.stopPropagation();
80+
}
81+
this.onTouch();
82+
}
83+
84+
onBlur(event: FocusEvent) {
85+
this.focus = false;
86+
event.preventDefault();
87+
event.stopPropagation();
88+
this.onTouch();
89+
}
90+
onFocus(event: FocusEvent) {
91+
this.focus = true;
92+
event.preventDefault();
93+
event.stopPropagation();
94+
this.onTouch();
95+
}
96+
97+
increment() {
98+
if (this.value < this.max) {
99+
this.value = this.value + this.step;
100+
this.onModelChange(this.value);
101+
}
102+
this.onTouch();
103+
}
104+
decrement() {
105+
if (this.value > this.min) {
106+
this.value = this.value - this.step;
107+
this.onModelChange(this.value);
108+
}
109+
this.onTouch();
110+
}
111+
}

0 commit comments

Comments
 (0)