re-initialize angular 6 datatable shows this.dtElement undefined - angular6

i have created a form for saving and the saved data will be displayed in the datatable at the same page. Datatable rerender() works fine with submission. but on edit rerender() showing "this.dtElement" undefined..
manage-templates.component.ts
import { Component, OnInit, ViewEncapsulation, AfterViewInit, OnDestroy, ViewChild } from '#angular/core';
import { HttpClient, HttpResponse } from '#angular/common/http';
import { FormBuilder, FormGroup, Validators, FormControl } from '#angular/forms';
import { NotifierService } from 'angular-notifier';
import { emailTemplatesService } from '../email-templates.service';
import { Globals } from '../../app.global';
import { Subject } from 'rxjs';
import { DataTableDirective } from 'angular-datatables';
import { Router } from '#angular/router';
class Template {
template_id: string;
template_name: string;
template_desc: string;
template_status: boolean;
}
class DataTablesResponse {
data: any[];
draw: number;
recordsFiltered: number;
recordsTotal: number;
}
#Component({
selector: 'app-manage-templates',
templateUrl: './manage-templates.component.html',
styleUrls: ['./manage-templates.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ManageTemplatesComponent implements AfterViewInit, OnDestroy, OnInit {
// Creating formgroup object
createEmailTemplate = new FormGroup({
templateName: new FormControl('', [Validators.required]),
templateBody: new FormControl('', [Validators.required]),
templateDesc: new FormControl('', [Validators.required])
});
// Initializing variables
submitted = false;
editFlag = false;
#ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<Template> = new Subject();
templates: Template[];
constructor(
private http: HttpClient,
private formBuilder: FormBuilder,
private postData: emailTemplatesService,
private notifier: NotifierService,
private router: Router
) { }
ngOnInit(): void {
const that = this;
this.dtOptions = {
searching: false,
pagingType: 'full_numbers',
pageLength: 10,
serverSide: true,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
that.http
.post<DataTablesResponse>(
Globals.baseAPIUrl + '/getEmailTemplates',
JSON.stringify({ dataTablesParameters })
).subscribe(resp => {
that.templates = resp.data;
callback({
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsFiltered,
data: []
});
});
},
columns: [
{ title: 'Template Name', data: 'template_name' },
{ title: 'Template Desc', data: 'template_desc' },
{ title: 'Status', data: 'template_status' },
]
};
}
ngAfterViewInit(): void {
this.dtTrigger.next();
}
ngOnDestroy(): void {
// Do not forget to unsubscribe the event
this.dtTrigger.unsubscribe();
}
rerender(): void {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
// Destroy the table first
dtInstance.destroy();
// Call the dtTrigger to rerender again
this.dtTrigger.next();
});
}
get formfields() { return this.createEmailTemplate.controls; }
// On form submit
onSubmit() {
this.submitted = true;
if (this.createEmailTemplate.invalid) {
return;
}
this.postData.createTemplate(JSON.stringify(this.createEmailTemplate.value)).subscribe(
data => {
this.notifier.notify(data['status'], data['message']);
if (data['status'] === 'success') {
this.rerender();
}
}
);
}
// On edit button
editTemplate(template_id) {
this.postData.getTemplateDetails(template_id).subscribe(
data => {
this.createEmailTemplate.patchValue({
templateName: data['message']['0']['templateName'],
templateDesc: data['message']['0']['templateDesc'],
templateBody: data['message']['0']['templateBody']
});
this.editFlag = true;
}
);
}
loadTemplates() {
this.editFlag = false;
this.rerender();
}
}
manage-templates.component.html
<div class="animated fadeIn">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<strong>Create Email Template</strong>
</div>
<form [formGroup]="createEmailTemplate" (ngSubmit)="onSubmit()" action="" method="post" class="form-horizontal">
<div class="card-body">
<div class="form-group row">
<label class="col-md-3 col-form-label" for="select1">Template Name</label>
<div class="col-md-6">
<input type="text" formControlName="templateName" class="form-control" placeholder="Template Name"
[ngClass]="{ 'is-invalid': submitted && formfields.templateName.errors }">
<span class="invalid-feedback" *ngIf="formfields.templateName.errors">Please Enter
Template Name</span>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label" for="select1">Template Description</label>
<div class="col-md-6">
<input type="text" formControlName="templateDesc" class="form-control" placeholder="Template Description"
[ngClass]="{ 'is-invalid': submitted && formfields.templateDesc.errors }">
<span class="invalid-feedback" *ngIf="formfields.templateDesc.errors">Please Enter
Template Description</span>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label" for="text-input">Email Body</label>
<div class="col-md-6">
<editor [(ngModel)]="dataModel" class="form-control" formControlName="templateBody"
[ngClass]="{ 'is-invalid': submitted && formfields.templateBody.errors }"></editor>
<span class="invalid-feedback" *ngIf="formfields.templateBody.errors">Email body need
not be empty</span>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" *ngIf="editFlag == false" class="btn btn-sm btn-primary" type="submit"><i class="fa fa-dot-circle-o"></i> Submit</button>
<button type="submit" *ngIf="editFlag == true" class="btn btn-sm btn-primary" type="submit"><i class="fa fa-dot-circle-o"></i> Update</button>
<button type="reset" class="btn btn-sm btn-danger" *ngIf="editFlag == false"><i class="fa fa-ban"></i> Reset</button>
<button type="reset" class="btn btn-sm btn-danger" *ngIf="editFlag == true" (click)="loadTemplates()"><i class="fa fa-ban"></i> Cancel</button>
</div>
</form>
</div>
</div>
</div>
<!--/.row-->
<div class="row" *ngIf="editFlag == false">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<i class="fa fa-align-justify"></i> Email Templates
</div>
<div class="card-body template_list">
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="row-border hover" width="100%">
<thead>
<tr>
<th>Template Name</th>
<th>Template Desc</th>
<th>Template Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody *ngIf="templates?.length != 0">
<tr *ngFor="let template of templates">
<td>{{ template.template_name }}</td>
<td>{{ template.template_desc }}</td>
<!-- <td>{{ template.template_status }}</td> -->
<td>
<span *ngIf="template.template_status == true" class="badge badge-success"> Active </span>
<span *ngIf="template.template_status == false" class="badge badge-danger">Inactive</span>
</td>
<td>
<a routerLink="edit" (click)="editTemplate(template.template_id)">Edit</a>
/
<a routerLink="disable/{{template.template_id}}" *ngIf="template.template_status == true">Deactivate</a>
<a routerLink="enable/{{template.template_id}}" *ngIf="template.template_status == false">Activate</a>
</td>
</tr>
</tbody>
<tbody *ngIf="templates?.length == 0">
<tr>
<td colspan="3" class="no-data-available">No data!</td>
</tr>
<tbody>
</table>
</div>
</div>
</div>
</div>
</div>
on editing an email template datatable hides and the values displayed in the form. Here i haven't write code for update form values. I want to repopulate the page on pressing "Cancel" button. On cancel button content in the datatable repopulates without pagination or any styles of datatable.
ERROR TypeError: "this.dtElement is undefined"

Here is my solution, the order of ViewChild/dtElement/... is important in this case
export class DemoComponent implements OnInit {
#ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: any = {};
dtInstance: DataTables.Api;
dtTrigger: Subject<any> = new Subject();
dt_data: any = {};
......
ngOnInit() {
this.dtOptions = {
...
};
}
ngAfterViewInit(){
//Define datatable
this.dtTrigger.next();
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
SomeFunction(){
//return the updated record, all the update function must be using rerender
this.dt_data = resp;
this.rerender();
}
rerender(): void {
try {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
// Destroy the table first
dtInstance.destroy();
// Call the dtTrigger to rerender again
this.dtTrigger.next();
});
} catch (err) {
console.log(err);
}
}

When I faced this same issue, I managed to solve it by using [hidden] instead of *ngIf. Aparently, ViewChild couldn't find the DataTableDirective because it wasn't in the HTML (thanks to *ngIf) resulting in the error, since this.dtElement was equal to undefined.
I suggest you try using this:
<div class="row" [hidden]="editFlag == true">
<!-- DataTable Content -->
</div

If you are using Forms and every time you submit new data and data coming from post request is different you can use something like this (angular 8) -
export class Demo implements OnDestroy, OnInit, AfterViewInit {
//this part did the job for me #view...
#ViewChild(DataTableDirective, { static: false }) datatableElement: DataTableDirective;
dtElement: DataTableDirective;
dtOptions: any = {};
dtInstance: DataTables.Api;
dtTrigger: Subject<any> = new Subject();
dt_data: any = {};
......
ngOnInit() {
this.dtOptions = {
paging: false,
"ordering": false,
dom: 'Bfrtip',
buttons: [
'copy',
'csv',
'excel'
]
};
}
ngAfterViewInit(){
this.dtTrigger.next();
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
getData(){
//post request and when assigning data to variable
this.dt_data = resp;
this.rerender();
}
rerender(): void {
//this.datatableElement is important
this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
this.dtTrigger.next();
});
}

Related

Remove a table row in Angular from a modal popup

How do I delete a table row after clicking the confirm button in the modal popup?
Delete row modal popup
I have tried some ways but none have worked so far.
I have created separate components for add, edit and delete user. Below are my codes.
start.component.html
<div class="row py-3 animate__animated animate__fadeIn">
<div class="d-flex">
<div class="w-25 me-auto">
<mdb-form-control>
<input mdbInput type="text" class="form-control" id="search-input" (keyup)="search($event)" />
<label mdbLabel class="form-label" for="search-input">Search</label>
</mdb-form-control>
</div>
<div>
<button mdbRipple type="button" class="btn btn-primary btn-sm" (click)="addUser()">Create New</button>
</div>
</div>
<div class="datatable mt-4">
<table class="table datatable-table" aria-label="datatable"
mdbTable mdbTableSort
#datatable="mdbTable" #sortSearch="mdbTableSort"
[dataSource]="listData" [striped]="true" [sort]="sortSearch" [pagination]="paginationSearch">
<thead class="datatable-header table-dark">
<tr>
<th *ngFor="let header of headers" [mdbTableSortHeader]="header" scope="col">
{{ header }}
</th>
</tr>
</thead>
<tbody class="datatable-body">
<tr *ngFor="let data of datatable.data; let i = index" scope="row">
<td>
{{ data.id }}
</td>
<td>
{{ data.name }}
</td>
<td>
{{ data.position }}
</td>
<td>
<button mdbRipple type="button" class="btn btn-primary btn-sm" (click)="editUser(data, i)" >Edit</button>
<button mdbRipple type="button" class="btn btn-primary btn-sm" (click)="deleteUser(data, i)" >Delete</button>
</td>
</tr>
</tbody>
</table>
<mdb-table-pagination #paginationSearch></mdb-table-pagination>
</div>
</div>
start.component.ts
import {Component, OnInit, ViewChild} from '#angular/core';
import {MdbTableDirective} from 'mdb-angular-ui-kit/table';
import {MdbModalRef, MdbModalService} from 'mdb-angular-ui-kit/modal';
import { AddUserFormComponent } from '../add-user-form/add-user-form.component';
import { EditUserFormComponent } from '../edit-user-form/edit-user-form.component';
import { DeleteUserFormComponent } from '../delete-user-form/delete-user-form.component';
export interface Person {
id: string;
name: string;
position: string;
isEdit: true;
}
#Component({
selector: 'app-start',
templateUrl: './start.component.html',
styleUrls: ['./start.component.scss']
})
export class StartComponent implements OnInit {
modalRefAdd: MdbModalRef<any> | null = null;
modalRefEdit: MdbModalRef<any> | null = null;
modalRefDelete: MdbModalRef<any> | null = null;
selectedIndex: number = 0;
constructor(private modalService: MdbModalService) {
}
ngOnInit(): void {
}
addUser(size: string = ''): void{
this.modalRefAdd = this.modalService.open(AddUserFormComponent, {
modalClass: size,
data: {},
});
this.modalRefAdd.onClose.subscribe(res => {
if(res != null) {
this.listData = [...this.listData, res];
} else {
close();
}
});
}
editUser(data: any, index: number){
this.selectedIndex = index;
this.modalRefEdit = this.modalService.open(EditUserFormComponent, {
modalClass: data,
data: {data}
});
this.modalRefEdit.onClose.subscribe(res => {
this.listData[this.selectedIndex] = res;
this.datatable.search('');
});
}
deleteUser(data: any, index: number) {
this.selectedIndex = index;
this.modalRefDelete = this.modalService.open(DeleteUserFormComponent, {
modalClass: data,
data: {data}
});
this.modalRefDelete.onClose.subscribe(res => {
this.listData[this.selectedIndex] = res;
this.datatable.search('');
});
}
#ViewChild('datatable') datatable!: MdbTableDirective<Person>;
headers = ['Employee ID', 'Name', 'Position', 'Actions'];
listData: Person[] = [
{
id: 'Evonik042',
name: 'Amrita Kaur',
position: 'Manager',
isEdit: true,
},
{
id: 'Evonik067',
name: 'Mahathir Abdul Wahib',
position: 'Developer',
isEdit: true,
},
{
id: 'Evonik071',
name: 'Tan KiatYao',
position: 'Developer',
isEdit: true,
},
{
id: 'Evonik118',
name: 'Haziq Morsim',
position: 'IT Intern',
isEdit: true,
}
];
search(event: Event): void {
const searchTerm = (event.target as HTMLInputElement).value;
this.datatable.search(searchTerm);
}
}
delete-user-form.component.html
<!-- Delete user starts -->
<div id="delete-employee">
<div class="modal-header evonik white-text">
<h5 class="modal-title text-white">Delete Employee Details</h5>
<button type="button" class="close pull-right" aria-label="Close" (click)="close()"><span aria-hidden="true" style="color: #000000;">×</span></button>
</div>
<div class="modal-body m-0 p-50">
<p>Are you sure you would like to remove this employee?</p>
</div>
<div class="modal-footer mt-1">
<button mdbRipple type="button" class="btn btn-primary" (click)="deleteRow(data)">Confirm</button>
<button mdbRipple type="button" class="btn btn-outline-primary" (click)="close()">Cancel</button>
</div>
</div>
<!-- Delete user ends -->
delete-user-form.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import { MdbModalRef } from 'mdb-angular-ui-kit/modal';
#Component({
selector: 'app-delete-user-form',
templateUrl: './delete-user-form.component.html',
styleUrls: ['./delete-user-form.component.scss']
})
export class DeleteUserFormComponent implements OnInit {
userForm: FormGroup = new FormGroup({
id: new FormControl('', [Validators.required]),
name: new FormControl('', [Validators.required]),
position: new FormControl('', [Validators.required])
});
data: any;
constructor(public modalRefDelete: MdbModalRef<DeleteUserFormComponent>,
public fb: FormBuilder) { }
ngOnInit() {
this.userForm.patchValue(this.data);
}
deleteRow(index: number) {
this.data.splice(index, 1);
//this.modalRefDelete.close();
}
close() {
this.modalRefDelete.close();
}
}
I hope someone can assist me with this problem. Thank you in advance.
so if the change was made in the database then you can just refresh the parent component.
there are several ways to refresh a component either you reload with route or you call the oninit function.
you can use this which will refresh the route :
setTimeout(() => {
window.location.reload();
}, 1000);
or use
this.ngOnInit();

Angular renders child component in parent view

I have an application in which the user can register an account. After registration he needs to confirm it by entering a code he received in the email.
Follwowing route setup:
const routes: Routes = [
{
path: 'register', component: RegisterComponent, children: [
{path: 'confirm', component: ConfirmRegisterComponent, pathMatch: 'full'}
]
},
];
RegisterComponent.ts:
export class RegisterComponent implements OnInit {
registerForm: FormGroup = new FormGroup({
username: new FormControl('', Validators.required),
email: new FormControl('', Validators.required),
password: new FormControl('', Validators.required)
});
constructor(private authService: AuthService, private router: Router, private route: ActivatedRoute) {
}
ngOnInit(): void {
}
performRegister() {
console.log(this.registerForm.value);
this.authService.register(this.username, this.email, this.password).subscribe(
(response: AbstractResponse) => this.handleResponse(response)
);
}
handleResponse(response: AbstractResponse) {
if (response.status === 200) {
this.router.navigate(['confirm'], {relativeTo: this.route, queryParams: {id: response.payload}})
}
}
get username() {
return this.registerForm.get('password')?.value;
}
get email() {
return this.registerForm.get('email')?.value;
}
get password() {
return this.registerForm.get('password')?.value;
}
}
RegisterComponent.html with router-outlet:
<router-outlet></router-outlet>
<h1>Register</h1>
<form (ngSubmit)="performRegister()" [formGroup]="registerForm">
<div class="form-group">
<label for="username">Username</label><br/>
<input class="form-control" formControlName="username" id="username" name="username" ngModel
placeholder="Username" type="text">
<div *ngIf="username?.invalid && (username?.dirty || username?.touched)"
class="alert alert-danger">
<div *ngIf="username?.errors?.required">
Username is required.
</div>
</div>
<br/>
</div>
<div class="form-group">
<label for="email">Email:</label><br/>
<input class="form-control" formControlName="email" id="email" name="email" ngModel placeholder="Email address"
type="email">
<div *ngIf="email?.invalid && (email?.dirty || email?.touched)"
class="alert alert-danger">
<div *ngIf="email?.errors?.required">
Username is required.
</div>
</div>
<br/>
</div>
<div class="form-group">
<label for="password">Your password:</label> <br/>
<input class="form-control" formControlName="password" id="password" name="password" ngModel
placeholder="Password" type="password">
<div *ngIf="password?.invalid && (password?.dirty || password?.touched)"
class="alert alert-danger">
<div *ngIf="password?.errors?.required">
Username is required.
</div>
</div>
<br/>
</div>
<div class="form-check">
<input class="form-check-input" id="exampleCheck1" type="checkbox">
<label class="form-check-label" for="exampleCheck1">Check me out</label>
</div>
<button [disabled]="!registerForm.valid" class="btn btn-secondary" type="submit">Register</button>
<br/>
<a routerLink="/login">Login</a>
</form>
RegisterConfirmation.ts:
#Component({
selector: 'app-confirm-register',
templateUrl: './confirm-register.component.html',
styleUrls: ['./confirm-register.component.css']
})
export class ConfirmRegisterComponent implements OnInit {
private id!: string;
public confirmationCodeForm: FormGroup = new FormGroup({
code: new FormControl('', Validators.required),
});
constructor(private authService: AuthService, private router: Router, private activatedRoute: ActivatedRoute) {
}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe(params => {
this.id = params['id'];
})
}
get code() {
return this.confirmationCodeForm.get('code')?.value;
}
performConfirmRegistration() {
this.authService.confirmRegistration(this.id, this.code).subscribe(
(response: AbstractResponse) => this.handleResponse(response)
);
}
handleResponse(response: AbstractResponse) {
if (response.status === 200) {
this.router.navigate(['login'])
}
}
}
and the html:
<h1>Confirm Registration</h1>
<form (ngSubmit)="performConfirmRegistration()" [formGroup]="confirmationCodeForm">
<div class="form-group">
<label for="code">Confirmation Code</label><br/>
<input class="form-control" formControlName="code" id="code" name="code" ngModel
placeholder="XXX-XXX-XXX" type="text">
<div *ngIf="code?.invalid && (code?.dirty || code?.touched)"
class="alert alert-danger">
<div *ngIf="code?.errors?.required">
Confirmation code is required.
</div>
</div>
<br/>
</div>
<button [disabled]="!confirmationCodeForm.valid" class="btn btn-secondary" type="submit">Confirm</button>
<br/>
</form>
But it seems to render both components simultanously which i dont want :/
Can somebody help me on this? I know it works without specifing the confirm as a child of register, but i think it being the child is better.
you can has a router like
const routes: Routes = [
{path: 'register', component: RegisterComponent}
{path: 'register/confirm', component: ConfirmRegisterComponent}
]
and remove the <router-outlet> of the RegisterComponent

bootstrap modal doesn't pass the data properly

I'm trying to pass the data of my books every time I click the button 'Summary' but it pass only the data of the first book, all the others that i click the button on the still show the data of the first book.
book.component.html
<body>
<div class="search-hero">
<input class="form-control" type="text" name="search" [(ngModel)]="searchText" autocomplete="off"
placeholder=" Start searching for a book by name, price or type" />
</div>
<div class="container" *ngFor="let item of books | filter: searchText">
<img src="{{ item.image }}" alt="img" class="image" />
<div class="overlay overlayFade">
<div class="text">
<label>Book Name</label>
<input type="text" class="form-control" placeholder="Enter name" [(ngModel)]="item.name"
[disabled]="isAfford ? false : true" />
<label>Category</label>
<input type="text" class="form-control" placeholder="Enter category" [(ngModel)]="item.category"
[disabled]="isAfford ? false : true" />
<label>Price</label>
<input type="number" class="form-control" placeholder="Enter price" [(ngModel)]="item.price"
[disabled]="isAfford ? false : true" />
<label>Amount</label>
<input type="number" class="form-control" placeholder="Enter amount" [(ngModel)]="item.amount"
[disabled]="isAfford ? false : true" />
<button class="btn btn-primary" *ngIf="canPurchase" (click)="purchaseBook(item)">
Purchase
</button>
<button class="btn btn-warning" (click)="updateBook(item)" *ngIf="isAfford">
Update
</button>
<button class="btn btn-danger" (click)="deleteBook(item.id)">
Delete
</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Summary
</button>
<div class="alert alert-success" *ngIf="message">{{ message }}</div>
</div>
</div>
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-
labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{item.name}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{{item.summary}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</body>
books.component.ts
import { CustomerService } from './../../services/customer.service';
import { AdminService } from './../../services/admin.service';
import { LoginService } from './../../services/login.service';
import { AuthorService } from './../../services/author.service';
import { Book } from './../../models/book';
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { FormGroup } from '#angular/forms';
#Component({
selector: 'app-books',
templateUrl: './books.component.html',
styleUrls: ['./books.component.css'],
})
export class BooksComponent implements OnInit {
modalForm: FormGroup;
searchText: string;
message: string;
public canPurchase = false;
public authorID: number;
public email: string;
public password: string;
public book = new Book();
public books: Book[] = [];
public type: string;
public isAfford = false;
id: number = 0;
constructor(
private authorService: AuthorService,
private activateRoute: ActivatedRoute,
private loginService: LoginService,
private router: Router,
private adminService: AdminService,
private customerService: CustomerService
) { }
ngOnInit(): void {
this.type = this.loginService.type;
if (this.type === 'Author') {
this.authorService
.getAuthorID(this.loginService.email, this.loginService.password)
.subscribe(
(res) => {
this.authorID = res;
this.getAllBooks();
},
(err) => {
alert(err.message);
}
);
this.isAfford = true;
}
if (this.type === 'Admin') {
this.id = 1;
this.isAfford = false;
this.getAllBooks();
}
if (this.type === 'Customer') {
this.customerService
.getCustomerID(this.loginService.email, this.loginService.password)
.subscribe(
(res) => {
this.id = res;
this.getAllBooks();
},
(err) => {
alert(err.message);
}
);
this.canPurchase = true;
}
}
resetForm() {
this.modalForm.reset();
console.log('reset');
}
addBook() {
this.router.navigateByUrl('add-book');
}
getOneBook(id: number) {
this.authorService.getOneBook(id).subscribe(
(res) => {
this.book = res;
},
(err) => {
alert(err.message);
}
);
}
purchaseBook(book: Book) {
this.customerService.setCustomerID(this.id).subscribe(
(res) => {
this.customerService.purchaseBook(book).subscribe(
(res) => {
this.router.navigateByUrl('purchases');
},
(err) => {
alert(err.message);
}
);
},
(err) => {
alert(err.message);
}
);
}
updateBook(book: Book) {
this.authorService.updateBook(book).subscribe(
(res) => {
this.book = res;
this.message = book.name + ' update successfully!';
setTimeout(() => {
this.message = '';
} , 2000);
},
(err) => {
alert(err.message);
}
);
}
deleteBook(id: number) {
this.authorService.deleteBook(id).subscribe(
(res) => {
this.books = this.books.filter((book) => book.id !== id);
},
(err) => {
alert(err.message);
}
);
}
getAllBooks() {
if (this.type === 'Author') {
this.authorService.getAllBooks(this.authorID).subscribe(
(res) => {
this.books = res;
},
(err) => {
alert(err.message);
}
);
}
if (this.type === 'Admin' || this.type === 'Customer') {
this.adminService.getAllBooks().subscribe(
(res) => {
this.books = res;
},
(err) => {
alert(err.message);
}
);
}
}
}
Only the data of the first book is showing to me but if i cick on the other books summary is it still show me the data of the first book. thanks for the helpers

Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe' at invalidPipeArgumentError

I'm trying to make a contact management application with CRUD functionalities using Angular 8 and Spring Boot. All functions work properly except Search. I'm trying to search for data of a particular name and display that in the table. But when I try to search it is giving me the above error.
.html file
<div class="panel panel-primary">
<div class="panel-heading">
<h2>Contact List</h2>
</div>
<div class="row">
<div class="input-group col-lg-4 col-lg-offset-4" style="text-align: center">
<input type="search" id="search" value="" class="form-control" placeholder="Search by name..." name="name" [(ngModel)]="new_name"/>
<span class="input-group-btn">
<button class="btn btn-search" type="button" (click)="findContact()"><i class="fa fa-search fa-fw"></i> Search </button>
</span>
</div>
</div>
<br>
<div class="panel-body">
<table class="table table-responsive table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Work Phone</th>
<th>Home Phone</th>
<th>Address</th>
<th>City</th>
<th>Category</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let contactInfo of contactList | async">
<td>{{contactInfo.name}}</td>
<td>{{contactInfo.email}}</td>
<td>{{contactInfo?.workPhone}}</td>
<td>{{contactInfo?.homePhone}}</td>
<td>{{contactInfo.address}}</td>
<td>{{contactInfo.city}}</td>
<td *ngIf="contactInfo.category==1" >Friends</td>
<td *ngIf="contactInfo.category==2" >Collegues</td>
<td *ngIf="contactInfo.category==3" >Family</td>
<!-- <ng-template #two>Collegues</ng-template>-->
<td><button (click)="deleteContact(contactInfo.contactID)" class="btn btn-danger">Delete</button>
<button (click)="updateContact(contactInfo.contactID)" class="btn btn-info" style="margin-left: 10px">Update</button>
<button (click)="contactDetails(contactInfo.contactID)" class="btn btn-info" style="margin-left: 10px">Details</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
.ts file
import { EmployeeDetailsComponent } from './../employee-details/employee-details.component';
import { Observable } from "rxjs";
import { ContactInfoService } from "./../contactInfo.service";
import { ContactInfo } from "../models/contactInfo";
import { Component, OnInit } from "#angular/core";
import { Router } from '#angular/router';
#Component({
selector: "app-employee-list",
templateUrl: "./employee-list.component.html",
styleUrls: ["./employee-list.component.css"]
})
export class EmployeeListComponent implements OnInit {
new_name='';
contactList: Observable<ContactInfo[]>;
constructor(private contactInfoService: ContactInfoService,
private router: Router) {}
ngOnInit() {
this.reloadData();
}
reloadData() {
this.contactList = this.contactInfoService.getContactList();
}
public findContact(){
this.contactInfoService.findContactByName(this.new_name)
.subscribe(
data => {
this.contactList= data;
console.log("data"+ JSON.stringify(data));
},
error => {
console.log(error);
});
}
deleteContact(id: number) {
this.contactInfoService.deleteContact(id)
.subscribe(
data => {
console.log(data);
this.reloadData();
},
error => console.log(error));
}
contactDetails(id: number){
this.router.navigate(['details', id]);
}
updateContact(id: number){
this.router.navigate(['update', id]);
}
}
.service file
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ContactInfoService{
private baseUrl = 'http://localhost:8080/';
constructor(private http: HttpClient) { }
getContact(id: number): Observable<any> {
return this.http.get(`${this.baseUrl+'get-contact'}/${id}`);
}
findContactByName(name): Observable<any> {
return this.http.get(`${this.baseUrl+'find'}/${name}`);
}
createContact(contactInfo: Object): Observable<Object> {
return this.http.post(`${this.baseUrl+'save-contact'}`, contactInfo);
}
updateContact(id: number, value: any): Observable<Object> {
return this.http.put(`${this.baseUrl+'contact'}/${id}`, value);
}
deleteContact(id: number): Observable<any> {
return this.http.delete(`${this.baseUrl+'delete'}/${id}`, { responseType: 'text' });
}
getContactList(): Observable<any> {
return this.http.get(`${this.baseUrl+'contact-information'}`);
}
}
‘contactList’ is an object but it needs to be an array for use with *ngFor. Return ‘any[]’ from your service so the return value is typed as an array. Better still use a proper type instead of ‘any’.
getContactList(): Observable<any[]> {
return this.http.get(`${this.baseUrl+'contact-information'}`);
A better alternative would be to type the http get call which will implicitly type the ‘getContact’ method:
getContactList() {
return this.http.get<any[]>(`${this.baseUrl+'contact-information'}`);

How to connect the form in angular routing

i have added angular routing to my crud operation.. before without routing the data i added was able to display in the table but now after implementation of routing the data is not getting stored in the table
here is the code of createemployee.component.html
<h2>Add Employee:</h2>
<form class="form-horizontal" #empForm="ngForm">
<div class="form-group">
<label class="control-label col-sm-2" for="name">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" minlength="4" maxlength="10" pattern="^[A-Za-z0-9]*[A-Za-z0-9][A-Za-z0-9]\S*$" [(ngModel)]="model.name" placeholder="Enter Your Name"
#name="ngModel" required/>
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.pattern">
No Spaces
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="position">Position:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="position" minlength="4" maxlength="10" pattern="^[a-z]*$" [(ngModel)]="model.position" placeholder="Enter your position"
#position="ngModel" required />
<div *ngIf="position.invalid && (position.dirty || position.touched)" class="alert alert-danger">
<div *ngIf="position.errors.required">
Position is required.
</div>
<div *ngIf="position.errors.pattern">
Only Alphabets are must be entered
</div>
<div *ngIf="position.errors.minlength">
Position must be at least 4 characters long.
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="salary">Salary:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="salary" pattern="[0-9]*"
minlength="5" maxlength="7" [(ngModel)]="model.salary" placeholder="Enter Salary" #salary="ngModel" required />
<div *ngIf="salary.invalid && (salary.dirty || salary.touched)" class="alert alert-danger">
<div *ngIf="salary.errors.required">
Salary is required.
</div>
<div *ngIf="salary.errors.minlength">
Salary must be in 5 numbers.
</div>
<div *ngIf="salary.errors.maxlength">
Salary must not be exceeded morethan 7 numbers.
</div>
<div *ngIf="salary.errors?.pattern">Only numebers should be typed
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" routerLink="../viewemployee" [disabled]="empForm.invalid">Add Employee</button>
<button type="button" class="btn btn-default" routerLink="../home">Cancel</button>
</div>
</div>
</form>
createemployee.component.ts
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup , Validators} from '#angular/forms';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#Component({
selector: 'app-createemployee',
templateUrl: './createemployee.component.html',
styleUrls: ['./createemployee.component.css']
})
export class CreateemployeeComponent implements OnInit {
model: any = {};
model2: any = {};
add=false;
create=true;
ngOnInit() {
this.model = new FormGroup({
'name': new FormControl(this.model.name,
[Validators.required, Validators.minLength(4),]),
'position': new FormControl(this.model.position,
[Validators.required, Validators.minLength(4),]),
'salary': new FormControl(this.model.salary, Validators.required)
});
}
employees = [{name: "Sunil", position: "Developer", salary: 20000},
{name: "Vamshi", position: "Java Developer", salary: 30000},
{name: "Chethan", position: ".Net Developer", salary: 10000}];
createEmp(){
this.add=true;
this.create=false;
this.Show=false;
this.edit=false;
}
addEmployee() {
this.employees.push(this.model);
this.Show = true;
this.add = false;
this.model = {};
}
}
viewemployeecomponent.ts
<h2>Employee Details</h2>
<table class="table table-bordered">
<thead>
<tr>
<th width=400>Name</th>
<th width=400>Position</th>
<th width=200>Salary</th>
<th width=400>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of employees; let i=index">
<td>{{employee.name}}</td>
<td>{{employee.position}}</td>
<td>{{employee.salary}}</td>
<td>
<a class="btn btn-success" (click)="editEmployee(i)">Edit</a>
<a class="btn btn-danger" (click)="deleteEmployee(i)">Delete</a>
</td>
</tr>
</tbody>
</table>
app.router.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { CreateemployeeComponent } from './createemployee/createemployee.component';
import { ViewemployeeComponent } from './viewemployee/viewemployee.component';
import { UpdateemployeeComponent } from './updateemployee/updateemployee.component';
export const router: Routes = [
{ path: '',redirectTo: 'home',pathMatch: 'full'},
{ path: 'createemployee', component: CreateemployeeComponent },
{ path: 'updateemployee', component: UpdateemployeeComponent},
{ path: 'viewemployee', component: ViewemployeeComponent },
{ path: 'home', component: HomeComponent},
{ path: 'appcomponent', component: AppComponent}
];
export const routes: ModuleWithProviders = RouterModule.forRoot(router)
where did i have done the mistake.. i am trying to add the created employee into existing table with all other 3 hard coded employees
form what i ca see your problem is you're pushing a new employee in a component ..but you render the employee table in another and i see yours employee array is not from a service or from a #input() directive ...
so for example create a service like:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Rx';
import { environment } from '../../../../environments/environment';
import { PraticheGridVM, PraticheDTO } from 'app/awards/shared/models';
#Injectable()
export class EmployeeService {
private employees = [{name: "Sunil", position: "Developer", salary: 20000},
{name: "Vamshi", position: "Java Developer", salary: 30000},
{name: "Chethan", position: ".Net Developer", salary: 10000}];
constructor(private http: HttpClient) { }
/**
* Get Pratiche Mese Paginate
* #param {PraticheGridVM} filter
* #returns {Promise<Array<PraticheDTO>>}
* #memberof PraticheService
*/
public GetEmployee(): Array<Employee> {
return this.employees;
}
/**
* Get Pratiche Trimestre Paginate
* #param {PraticheGridVM} filter
* #returns {Promise<PraticheDTO>}
* #memberof PraticheService
*/
public AddEmployee(emp: Employee): Array<Employee> {
return this.employees.push(emp);
}
}
and then use it in your components .. like:
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup , Validators} from '#angular/forms';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import {EmployeeService} from 'yourservicePATH'
#Component({
selector: 'app-createemployee',
templateUrl: './createemployee.component.html',
styleUrls: ['./createemployee.component.css']
})
export class CreateemployeeComponent implements OnInit {
model: any = {};
model2: any = {};
add=false;
create=true;
constructor(private employeeService: EmployeeService){
}
ngOnInit() {
this.model = new FormGroup({
'name': new FormControl(this.model.name,
[Validators.required, Validators.minLength(4),]),
'position': new FormControl(this.model.position,
[Validators.required, Validators.minLength(4),]),
'salary': new FormControl(this.model.salary, Validators.required)
});
}
employees = [{name: "Sunil", position: "Developer", salary: 20000},
{name: "Vamshi", position: "Java Developer", salary: 30000},
{name: "Chethan", position: ".Net Developer", salary: 10000}];
createEmp(){
this.add=true;
this.create=false;
this.Show=false;
this.edit=false;
}
addEmployee() {
this.employeeService.AddEmployee(this.model);
this.Show = true;
this.add = false;
this.model = {};
}
}