declarations: [
AppComponent
],
main.ts
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
we can have different components in the app eg: app-header, app-brand, app-feature … can have another components in app-header like app-nav-item, app-nav-search.
in this app, we have to create, edit, delete post.
ng g c posts/post-create
above command will create a posts folder - then add post-create component with in the posts folder.
final output will be like this:
here v create post-create component in posts folder.
add contents in post-create template file
add the post-create selector in app component.html
<h1>Our First App</h1>
<app-post-create></app-post-create>
event binding means a feature that allows angular to listen to events made by users. here v add input and clicking on button angular listen to that click event and execute some function there.
post-create-component.html
<button (click)="onAddPost()">Save post</button>
post-create-component.ts
onAddPost(){
alert("post added");
}
<textarea name="post" id="post" cols="30" rows="5" value ="newPost"></textarea>
<p>{{ newPost }}</p>
accessing the element - getting the value.
first set a reference to the element.
<textarea
name="post"
id="post"
cols="30"
rows="5"
[value]="newPost"
#postInput
></textarea
><br /><br />
postInput is the reference to the textArea element.
<button (click)="onAddPost(postInput)">Add Post</button>
onAddPost(postInput: HTMLInputElement){
this.newPost = postInput.value;
}
<textarea
name="post"
id="post"
cols="30"
rows="5"
[(ngModel)]="postValue"
></textarea
><br /><br />
here v get the value to textArea element and output the value from textArea at same time. earlier v do property binding to output the value. and do a local reference to get the value. by using ngModel directive, v get the value from user and output the value on template at same time.
postValue: string ="";
ngOnInit(): void {
}
onAddPost(){
this.newPost = this.postValue;
}
declare postValue property here, assign it to newPost.
finally add FormsModule to the imports array in app module.
(Angular Material)[https://material.angular.io/guide/getting-started]
(Angular Component)[https://material.angular.io/components/categories]
<div class="container">
<mat-card>
<h3>Add Posts</h3>
<mat-form-field class="example-form-field">
<textarea
rows="5"
matInput
[(ngModel)]="postValue"
></textarea></mat-form-field
><br />
<button mat-raised-button color="primary" (click)="onAddPost()">
Add Post
</button>
<br />
<p>{{ newPost }}</p>
</mat-card>
</div>
app.module.ts
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
imports: [MatInputModule, MatButtonModule, MatCardModule];
to add header to the page. create header component in post component.
ng g component posts/header --skipTests=true
import MatToolbar Module in app module add same in imports array.
(Angular Toolbar)[https://material.angular.io/components/toolbar/overview]
header.component.html
<p>
<mat-toolbar color="primary">
<span>My Application</span>
</mat-toolbar>
</p>
create post-list component in posts component
ng g component posts.post-list --skipTests=true
add post-list in component app component template using Expansion panel to output the post. import MatExpansion Module -add to imports array.
posts: Array<Object> = [];
<mat-accordion *ngIf="posts.length > 0">
<mat-expansion-panel hideToggle *ngFor="let post of posts">
<mat-expansion-panel-header>
<mat-panel-title> {{post.title}} </mat-panel-title>
</mat-expansion-panel-header>
<p>{{post.content}}</p>
</mat-expansion-panel>
</mat-accordion>
<p class="mat-body-1 info-text" *ngIf="posts.length <= 0">No posts added yet</p>
<mat-form-field class="example-full-width">
<input
matInput
type="text"
placeholder="Title goes Here"
[(ngModel)]="postTitle"
/>
</mat-form-field>
<mat-form-field class="example-form-field">
<textarea
rows="5"
matInput
[(ngModel)]="postContent"
placeholder="content goes here"
></textarea></mat-form-field
><br />
post-create.component.ts
constructor() { }
postTitle: string ="";
postContent: string ="";
ngOnInit(): void {
}
onAddPost(){
// create post object to store title and content
const post = {title: this.postTitle, content: this.postContent};
}
here v got the values - next need to output those, first need to emit an event - create an event emitter also need to listen to this event from other components. for that add Output decorator to the event. thus v can listen it from the parent component.
@Output() postEvent = new EventEmitter();
ngOnInit(): void {
}
onAddPost(){
// create post object to store title and content
const post = {title: this.postTitle, content: this.postContent};
// emit the post object
this.postEvent.emit(post);
}
app.component.html
access the event emitted in app component. here $event argument receives the data emitted
<app-post-create (postEvent)="onPostAdded($event)"></app-post-create>
app.component.ts
push the post to posts array
// empty array
storedPosts:Array<Object> = [];
// define function, get post
onPostAdded(post: Object){
// push the received post object to posts Array
this.posts.push(post);
}
next v have to pass the posts Array to post list component.
for that make post property in post-list component bindable from outside thru property binding.
for that v use Input decorator,
post-list.component.ts
// make posts property bindable from outside thru property binding
@Input() posts: Array<Object> = [];
app.component.html
<!--property binding of posts property on storedPosts array-->
<app-post-list [posts]="storedPosts "></app-post-list>
app.component.ts
storedPosts:Array<Object> = [];
// define function, get post
onPostAdded(post: Object){
// push the received post object to posts Array
this.storedPosts.push(post);
}
ng generate class posts/post --type=model
export class Post {
title: string;
content: string;
}
app.component.ts
// empty array
storedPosts:Post[] = [];
post-create.component.ts
@Output() postEvent = new EventEmitter<Post>();
onAddPost(){
// create post object to store title and content
const post: Post = {title: this.postTitle, content: this.postContent};
// emit the post object
this.postEvent.emit(post);
}
post-list.component.ts
@Input() posts: Post[] = [];
add ngModel directive to the each inputs. thus it register the inputs as a control to the forms. but have to add name attribute for the inputs since angular needs to know how to name the input. change button type to submit. while submitting, it triggers an event submit that v can listen to. add submit event to the form. assign the method to it.
<form (submit)="onAddPost()">
<mat-form-field>
<input
matInput
type="text"
placeholder="Title goes Here"
ngModel
name="title"
/>
</mat-form-field>
<mat-form-field>
<textarea
rows="5"
matInput
ngModel
placeholder="content goes here"
name="content"
></textarea>
</mat-form-field>
<br />
<button mat-raised-button color="primary" type="submit">Add Post</button>
<br />
</form>
now need to get access to values in the form.
For that purpose, v set a local reference in the form element- assign ngForm directive to the local reference as string - pass that local reference as an argument to the method.
post-create.component.html
<input
matInput
type="text"
placeholder="Title goes Here"
ngModel
name="title"
required
minlength="5"
#title="ngModel"
/>
<mat-error *ngIf="title.invalid">Please give valid title</mat-error>
give both the inputs a local reference. thus can use in the ngIf.
this form creation is done by template driven approach.
ng generate service posts/post --skipTests=true
create a posts array of type Post. get posts and later add posts to the post array.
post.service.ts
export class PostService {
constructor() {}
// create a private property of type Post array
private posts: Post[] = [];
getPosts() {
// return copy of post array, use spread operator, so changes only affected on its copy, not the original array
return [...this.posts];
}
// adding new post
addPost(post: Post) {
this.posts.push(post);
}
}
next v have to inject the instance of this service class to needed component. called dependency injection
for that add a constructor in component > define an a public property of type PostService type.
that property will store incoming value of PostService.
add OnInIt interface on component. later define ngOnInIt method - call the getPosts method on postService property.
post-list.component.ts
ngOnInit(): void {
// call get post method here
this.postService.getPosts();
}
also do the same in post-create component for creating post as well.
constructor(public postService: PostService) { }
onAddPost(form: NgForm){
// create post object to store title and content
const post: Post = {title: form.value.title, content: form.value.postContent};
// emit the post object
this.postService.addPost(post);
}
here the after entering inputs posts wont be listed, since v fetched the post before adding them. to solve it, first remove the bindings in app component. next use rxjs package. import Subject from rxjs package. create new instance of Subject. call next on that subject instance - pass the post array copy.
post.service.ts
private postUpdated = new Subject<Post[]>();
// adding new post
addPost(post: Post){
this.posts.push(post);
// call next() on subject - pass copy of posts array as argument.
this.postUpdated.next([...this.posts]);
}
next u have to listen to that subject whenever it emits a post. create new method - call asObservable() on subject and return it. it will return an object that v can listen to.
getPostUpdateListener(){
// call asObservable method on postUpdated. which in turn returns an object.
return this.postUpdated.asObservable();
}
next v have to subscribe to this listener object from post-list component call subscribe(). subscribe takes a function as an argument which will b called when new data is emitted.
post-list.component.ts
ngOnInit(): void {
// call get post method here
this.posts = this.postService.getPosts();
this.postService.getPostUpdateListener()
.subscribe((post: Post[]) => {
// set posts property with post array received.
this.posts = post;
});
}
next have to store the subscription in a property. finally unsubscribe the subscription. implement OnDestroy method.
post-list.component.ts
private postSub: Subscription;
ngOnInit(): void {
// call get post method here
this.posts = this.postService.getPosts();
this.postSub = this.postService.getPostUpdateListener()
.subscribe((post: Post[]) => {
// set posts property with post array received.
this.posts = post;
});
}
ngOnDestroy(){
// unsubscribe
this.postSub.unsubscribe()
}
observer subscribes to the observable, simply means they establishes the subscription. 3 methods in observer,
v call next() on subject, subject is an observable. v invoke error() on observable when needed to throw some error. can call complete() on observable when no more data left to be emitted.
a subject is a kind of observable. normal observable is passive. eg: wraps callback, emitting events subject is active observable. v also subcribe to the subject, but here v call next() manually. for example, when v add a new post, v actively can notify our entire application. it can be done with subject.
consider observables/subjects as a stream of values/data. and these values r emitted over time.
observer - have set of functions we can call,
this is how observables work.
Author: jisshub
Source Code: https://github.com/jisshub/mean-stack-app-snippets-angular-nodejs
#nodejs #node #javascript