Skip to content

Commit 5d100d2

Browse files
committed
Add directly-accessible modal demo in Angular 7.2.15.
1 parent 8464dff commit 5d100d2

32 files changed

Lines changed: 8503 additions & 0 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ with.
1010

1111
## My JavaScript Demos - I Love JavaScript!
1212

13+
* [Most Of Your Modal Windows Should Be Directly Accessible By Route In Angular 7.2.15](https://bennadel.github.io/JavaScript-Demos/demos/router-routable-modals-angular7/)
1314
* [Prevent Routing To Secondary View If Page Refresh In Angular 7.2.15](https://bennadel.github.io/JavaScript-Demos/demos/prevent-secondary-view-on-refresh-angular7/)
1415
* [Performing A SublimeText-Inspired Fuzzy Search For String Matching In Angular 7.2.15](https://bennadel.github.io/JavaScript-Demos/demos/fuzzy-match-angular7/)
1516
* [Using replaceUrl To Persist Search Filters In The URL Without Messing Up The Browser History In Angular 7.2.14](https://bennadel.github.io/JavaScript-Demos/demos/router-filter-replace-state-angular7/)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Now that we're using Webpack, we can install modules locally and just ignore
3+
# them since the assets are baked into the compiled modules.
4+
node_modules/
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
:host {
3+
background-color: #ffffff ;
4+
border-radius: 7px 7px 7px 7px ;
5+
display: block ;
6+
padding: 20px 20px 20px 20px ;
7+
position: relative ;
8+
width: 400px ;
9+
}
10+
11+
.close {
12+
color: #666666 ;
13+
cursor: pointer ;
14+
font-size: 24px ;
15+
font-weight: 800 ;
16+
line-height: 24px ;
17+
position: absolute ;
18+
right: 10px ;
19+
text-decoration: none ;
20+
top: 7px ;
21+
}
22+
23+
.title {
24+
margin: 0px 0px 20px 0px ;
25+
}
26+
27+
.form {
28+
margin: 0px 0px 0px 0px ;
29+
}
30+
31+
.field {
32+
display: flex ;
33+
margin-bottom: 10px ;
34+
35+
&__input {
36+
flex: 1 1 auto ;
37+
font-size: 20px ;
38+
margin-right: 8px ;
39+
}
40+
41+
&__submit {
42+
flex: 0 1 auto ;
43+
font-size: 20px ;
44+
}
45+
}
46+
47+
.bulk {
48+
display: flex ;
49+
50+
&__input {
51+
flex: 0 1 auto ;
52+
margin-right: 7px ;
53+
}
54+
55+
&__label {
56+
flex: 1 1 auto ;
57+
font-size: 15px ;
58+
line-height: 20px ;
59+
}
60+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
import { ElementRef } from "@angular/core";
5+
import { ViewChild } from "@angular/core";
6+
7+
// Import the application components and services.
8+
import { FriendsRuntime } from "./friends.runtime";
9+
import { ModalViewComponent } from "./modal-view.component";
10+
11+
// ----------------------------------------------------------------------------------- //
12+
// ----------------------------------------------------------------------------------- //
13+
14+
@Component({
15+
selector: "add-friend-view",
16+
queries: {
17+
nameRef: new ViewChild( "nameRef" )
18+
},
19+
styleUrls: [ "./add-friend-view.component.less" ],
20+
template:
21+
`
22+
<a (click)="closeModal()" class="close">
23+
&times;
24+
</a>
25+
26+
<h2 class="title">
27+
Add New Friend
28+
</h2>
29+
30+
<form (submit)="processForm()" class="form">
31+
32+
<div class="field">
33+
<input
34+
#nameRef
35+
type="text"
36+
name="name"
37+
[(ngModel)]="form.name"
38+
class="field__input"
39+
/>
40+
41+
<button type="submit" class="field__submit">
42+
Add Friend
43+
</button>
44+
</div>
45+
46+
<label for="add-friend-view-bulk-checkbox" class="bulk">
47+
<input
48+
id="add-friend-view-bulk-checkbox"
49+
type="checkbox"
50+
name="isBulkAction"
51+
[(ngModel)]="form.isBulkAction"
52+
class="bulk__input"
53+
/>
54+
55+
<span class="bulk__label">
56+
I want to add multiple friends.
57+
</span>
58+
</label>
59+
60+
</form>
61+
`
62+
})
63+
export class AddFriendViewComponent {
64+
65+
public form: {
66+
isBulkAction: boolean;
67+
name: string;
68+
};
69+
public nameRef!: ElementRef;
70+
71+
private friendsRuntime: FriendsRuntime;
72+
private modalViewComponent: ModalViewComponent;
73+
74+
// I initialize the add-friend-view component.
75+
constructor(
76+
friendsRuntime: FriendsRuntime,
77+
modalViewComponent: ModalViewComponent
78+
) {
79+
80+
this.friendsRuntime = friendsRuntime;
81+
this.modalViewComponent = modalViewComponent;
82+
83+
this.form = {
84+
isBulkAction: false,
85+
name: ""
86+
};
87+
88+
}
89+
90+
// ---
91+
// PUBLIC METHODS.
92+
// ---
93+
94+
// I close the modal window.
95+
public closeModal() : void {
96+
97+
this.modalViewComponent.closeModal();
98+
99+
}
100+
101+
102+
// I get called once after the view has been initialized.
103+
public ngAfterViewInit() : void {
104+
105+
this.focusInput();
106+
107+
}
108+
109+
110+
// I process the new friend form.
111+
public processForm() : void {
112+
113+
if ( ! this.form.name.trim() ) {
114+
115+
return;
116+
117+
}
118+
119+
this.friendsRuntime
120+
.addFriend( this.form.name )
121+
.then(
122+
( id ) => {
123+
124+
if ( this.form.isBulkAction ) {
125+
126+
this.form.name = "";
127+
this.focusInput();
128+
129+
} else {
130+
131+
this.closeModal();
132+
133+
}
134+
135+
},
136+
( error ) => {
137+
138+
console.warn( "There was a problem adding the friend." );
139+
console.error( error );
140+
141+
}
142+
)
143+
;
144+
145+
}
146+
147+
// ---
148+
// PRIVATE METHODS.
149+
// ---
150+
151+
// I put the browser focus to the name input.
152+
private focusInput() : void {
153+
154+
this.nameRef.nativeElement.focus();
155+
156+
}
157+
158+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
:host {
3+
display: block ;
4+
font-size: 18px ;
5+
}
6+
7+
a {
8+
color: red ;
9+
cursor: pointer ;
10+
text-decoration: underline ;
11+
user-select: none ;
12+
-moz-user-select: none ;
13+
-webkit-user-select: none ;
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
5+
// ----------------------------------------------------------------------------------- //
6+
// ----------------------------------------------------------------------------------- //
7+
8+
@Component({
9+
selector: "my-app",
10+
styleUrls: [ "./app.component.less" ],
11+
template:
12+
`
13+
<p>
14+
<a routerLink="/app">Goto Home</a>
15+
&mdash;
16+
<a routerLink="/app/friends">Goto Friends</a>
17+
&mdash;
18+
<a [routerLink]="[ '/app', { outlets: { modal: 'modal/add-friend' } } ]">
19+
Add Friends From Home
20+
</a>
21+
</p>
22+
23+
<!-- Primary outlet. -->
24+
<router-outlet></router-outlet>
25+
26+
<!-- Modal outlet. -->
27+
<router-outlet name="modal"></router-outlet>
28+
`
29+
})
30+
export class AppComponent {
31+
// ...
32+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
// Import the core angular services.
3+
import { BrowserModule } from "@angular/platform-browser";
4+
import { FormsModule } from "@angular/forms";
5+
import { NgModule } from "@angular/core";
6+
import { RouterModule } from "@angular/router";
7+
8+
// Import the application components and services.
9+
import { AddFriendViewComponent } from "./add-friend-view.component";
10+
import { AppComponent } from "./app.component";
11+
import { FriendsViewComponent } from "./friends-view.component";
12+
import { ModalViewComponent } from "./modal-view.component";
13+
14+
// ----------------------------------------------------------------------------------- //
15+
// ----------------------------------------------------------------------------------- //
16+
17+
@NgModule({
18+
imports: [
19+
BrowserModule,
20+
FormsModule,
21+
RouterModule.forRoot(
22+
[
23+
// Redirecting to keep all of the app under the "/app" prefix. This
24+
// helps deal with some routing issues with empty segments.
25+
{
26+
path: "",
27+
pathMatch: "full",
28+
redirectTo: "app"
29+
},
30+
{
31+
path: "app",
32+
children: [
33+
{
34+
path: "friends",
35+
component: FriendsViewComponent
36+
},
37+
// Notice that the "add-friend" view is in the "modal" outlet.
38+
// This allows it (and most of your modals) to be shown to the
39+
// user regardless of what is in the primary outlet. This is what
40+
// makes Auxiliary Routes so freaking exciting!
41+
{
42+
path: "modal",
43+
outlet: "modal",
44+
component: ModalViewComponent,
45+
children: [
46+
{
47+
path: "add-friend",
48+
component: AddFriendViewComponent
49+
}
50+
]
51+
}
52+
]
53+
}
54+
],
55+
{
56+
// Tell the router to use the hash instead of HTML5 pushstate.
57+
useHash: true,
58+
59+
// Enable the Angular 6+ router features for scrolling and anchors.
60+
scrollPositionRestoration: "enabled",
61+
anchorScrolling: "enabled",
62+
enableTracing: false
63+
}
64+
)
65+
],
66+
providers: [
67+
// CAUTION: We don't need to specify the LocationStrategy because we are setting
68+
// the "useHash" property in the Router module above (which will be setting the
69+
// strategy provider for us).
70+
// --
71+
// {
72+
// provide: LocationStrategy,
73+
// useClass: HashLocationStrategy
74+
// }
75+
],
76+
declarations: [
77+
AddFriendViewComponent,
78+
AppComponent,
79+
FriendsViewComponent,
80+
ModalViewComponent
81+
],
82+
bootstrap: [
83+
AppComponent
84+
]
85+
})
86+
export class AppModule {
87+
// ...
88+
}

0 commit comments

Comments
 (0)