Remove a table row in Angular from a modal popup - html

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();

Related

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'}`);

re-initialize angular 6 datatable shows this.dtElement undefined

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();
});
}

Filter in ngFor after user click : Angular 6

Just a quick question here. I'm still a newbie in angular so please. And yes, I have my view page looks something like this.
Initially, i'm loading my page with all the required data. Now, the problem here is, when the user clicks on any of the name in "OWNERS", the data should be able to filter based on "user-click". For example, if the user click on "Krishna" all the campaigns associated with "Krishna" should be filtered and should be able to display in the same page.
My home.component.ts page looks like this.
import { CampaignService } from './../../../services/campaign.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor(private campaignService : CampaignService ) { }
Time;
campaigns;
ngOnInit(){
setInterval(() => {
this.Time = Date.now()
}, 1000);
this.campaignService.CampaignsInfo()
.subscribe(response=>{
this.campaigns = response;
});
}
}
And my home.component.html looks like this:
<campaign-header></campaign-header>
<div class="container-fluid date-time sticky-top">
<div class="container">
<form class="form-inline my-2 my-lg-0 d-flex justify-content-center radio" >
<div class="" >
<input type="radio" checked name="day"> Today
</div>
<div class="float-left">
<input type="radio" name="day"> Commulative
</div>
<!-- <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>-->
</form>
<div class="d-flex justify-content-end" style="margin-top: -16px;">
<span id="date_time"><i class="zmdi zmdi-calendar-check zmdi-hc-fw"></i> {{Time | date}} <i class="zmdi zmdi-time zmdi-hc-fw"></i> {{ Time | date:'mediumTime' }} </span>
</div>
</div>
</div>
<br>
<!-- content -->
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="card campaign border-top wrap">
<div class="card-body table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th class="border-top-0">CAMPAIGN </th>
<th class="border-top-0">STATUS</th>
<th class="border-top-0">DIALED</th>
<th class="border-top-0">OWNERS</th>
<th class="border-top-0"> <span class="invisible">Action</span></th>
<!-- <button mat-button color="primary" routerLink="/campaign-details">CampaignDetails</button> -->
</tr>
</thead>
<tbody>
<tr *ngFor="let campaign of campaigns?.result">
<td><p>{{campaign.CampaignName}}</p>
<small>{{campaign.DepartmentName}}</small>
</td>
<td>
<small class="text-info">Active</small>
</td>
<td>
<p>{{campaign.Dialed}} / <small>1500000</small></p>
<div class="progress mt-2 w-75">
<div class="progress-bar bg-info" role="progressbar" style="width: 90%;" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
<td>
<button class="badge badge-pill badge-secondary" > {{ campaign.owners }} </button>
</td>
<td class="ml-0 pl-0"><a routerLink="/campaign-details"><img src="../../assets/Images/next.png" class="next" /></a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<br>
</div>
I tried writing the (click) ="someMethod(campaign.Name)" for the button and passed campaign object and tried applying filter there in component.ts page, but no luck. Any help is much appreciated. Much thanks in advance.
P.S: This is after some research and after implementing the below suggestion.
I tried implementing a custom pipe, but after click event on owners, i'm getting the following error.
For Information: My debugging value of the pipe after click event looks like this.
My pipe Looks like this.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(values: any[], key: string, value: string): any[] {
if (!values) {
return [];
}
if (!value) {
return values;
}
return values.filter(val =>{
debugger;
console.log(values);
return val.includes(values);
});
}
}
And my click event and html looks like this:
filterByOwnr(val) {
this.filter = val;
}
<tr *ngFor="let campaign of campaigns?.result | filter : 'OWNERS' : filter;">
<td>
<button class="badge badge-pill badge-secondary" (click)="filterByOwnr(campaign.owner)"> {{ campaign.owner}} </button>
</td>
</tr>
Implement custom filter pipe. Note modify custom pipe as per your need.
import { Pipe, PipeTransform, Injectable } from '#angular/core';
#Pipe({
name: 'filter',
})
#Injectable()
export class Filter implements PipeTransform {
transform(values: any[], key: string, value: string): any[] {
if (!values) {
return [];
}
if (!key|| !value) {
return values;
}
return values.filter(val=>
val[key].toLowerCase().includes(value.toLowerCase())
);
}
}
import { Filter } from 'filterPipe';
#NgModule({
imports: [],
declarations: [ Filter ],
providers: [ ],
exports: [
Filter
],
})
export class PipeModule {}
//App module
import { NgModule } from '#angular/core';
import { PipeModule } from './modules/pipe.module';
#NgModule({
imports: [PipeModule
],
declarations: [
],
providers: [
],
bootstrap: [AppComponent],
})
export class AppModule {}
Home HTML
<tr *ngFor="let campaign of campaigns?.result | filter : 'OWNERS' : searchVal;">
<td class="text-left">
<span (click)="filterByOwnr(campaign.OWNERS)">{{campaign.OWNERS}}</span>
</td>
filterByOwnr(val){
this.searchVal = val;
}
In your custom pipe implementation, shouldn't this line:
return val.includes(values);
Be this instead?
return val.CampaignName.includes(value);

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 = {};
}
}