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
Related
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();
I have an Angular app where user can login with his email and password. so at first i just want the login (login.component) page to appear first, when the user enters his email and password then we go directly to menu page (app.component), in the menu page we have LogOut so when the user click on it then return to login page.
This is what i do :
code :
login.component.html :
<h1 style="text-align:center">
<img src="../../assets/images/logo.png">
</h1>
<div class="login-wrap">
<div class="login-html">
<div class='login'>
<div class='col-md-4 offset-4 mt-5' *ngIf='!this.isLogin'>
<h2 class="login-header">S'identifier</h2>
<form class="login-container" #myform="ngForm" (ngSubmit)="onSubmit(myform)">
<div class='form-group'>
<input class='form-control' type="email" name="email" placeholder="email" ngModel>
</div>
<div class='form-group'>
<input class='form-control' type="password" name="password" placeholder="Password"
[type]="hide ? 'password': 'text'" [(ngModel)]="passwordValue">
<span class="material-icons" matSuffix (click)="hide = !hide">
{{hide ? 'visibility': 'visibility_off'}}
</span>
</div>
<input class='btn btn-outline-info' type="submit" value="Login">
</form>
</div>
<div class='col-md-4 offset-4 mt-5' *ngIf='this.isLogin'>
<h1>You are logged in</h1>
<button class='btn btn-outline-info' (click)='logout()'>Log-out</button>
</div>
</div>
</div>
</div>
login.component.ts :
export class LoginComponent implements OnInit {
isLogin: boolean = false
errorMessage: any
hide =true;
passwordValue='';
constructor(
private _api: ApiService,
private _auth: AuthService,
private _router:Router, private toastr : ToastrService) { }
ngOnInit(){
this.isUserLogin();
}
onSubmit(form: NgForm) {
console.log('Your form data : ', form.value);
this._api.postTypeRequest('user/login', form.value).subscribe((res: any) => {
switch (res.status) {
case 0:
this.toastr.error("you have a problem","Erreur");
break;
case 1:
this._auth.setDataInLocalStorage('userData', JSON.stringify(res.data));
this._auth.setDataInLocalStorage('token', res.token);
this._router.navigate(['']);
break;
case 2:
this.toastr.warning("your email or password is incorrect","Warning");
this.passwordValue = '';
break;
}
})
}
isUserLogin(){
if(this._auth.getUserDetails() != null){
this.isLogin = true;
}
}
logout(){
this._auth.clearStorage()
this._router.navigate(['']);
}
}
app.component.html (menu) :
<nav class="menu">
<ol>
<li class="menu-item"><a routerLink="adherents">Adherents</a></li>
<li class="menu-item">
<a routerLink="factures">Factures</a>
</li>
<li class="menu-item">
<a routerLink="logs">Logs</a>
</li>
<li class="menu-item">
<a routerLink="regions">Regions</a>
</li>
<li class="menu-item">
<a routerLink="roles">Roles</a>
</li>
<li class="menu-item">
<img class="img" src="../assets/images/user.png">
<a>welcome james</a>
<ol class="sub-menu">
<li class="menu-item"><a routerLink="/login">LogOut</a></li>
</ol>
</li>
</ol>
</nav>
<router-outlet></router-outlet>
auth-guard.service.ts :
#Injectable({
providedIn: 'root'
})
export class AuthGuardService {
constructor( private _authService: AuthService,
private _router: Router) { }
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this._authService.getToken()) {
return true;
}
this._router.navigate(['/login']);
return false;
}
}
auth.service.ts:
#Injectable({
providedIn: 'root'
})
export class AuthService {
constructor() { }
getUserDetails() {
if(localStorage.getItem('userData')){
return localStorage.getItem('userData')
}else{
return null
}
}
setDataInLocalStorage(variableName, data) {
localStorage.setItem(variableName, data);
}
getToken() {
return localStorage.getItem('token');
}
clearStorage() {
localStorage.clear();
}
}
api.service.ts :
import { Injectable } from '#angular/core';
import { environment } from '../../environments/environment';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ApiService {
baseUrl = 'http://localhost:3000/';
constructor(private _http: HttpClient) { }
getTypeRequest(url) {
const headers = new HttpHeaders().set('Content-Type','application/json');
return this._http.get(`${this.baseUrl}${url}`, {headers}).pipe(map(res => {
return res;
}));
}
postTypeRequest(url, payload) {
const headers = new HttpHeaders().set('Content-Type','application/json');
return this._http.post(`${this.baseUrl}${url}`, payload, {headers}).pipe(map(res => {
return res;
}));
}
}
The question is not clear but I guess you just need to use logout() method in the app component the same way you are using it in the login component
<ol class="sub-menu">
<li class="menu-item"><a href="#" (click)="logout()>LogOut</a></li>
</ol>
You have to follow the below steps
Replace app.component.html code like
Existing
<li class="menu-item"><a routerLink="/login">LogOut</a></li>
New
<li class="menu-item"><a href="#" (click)="logout()>LogOut</a></li>
Paste the below code lines in app.component.ts
logout(){this._auth.clearStorage();this._router.navigate(['/login']);}
Check the constructor of app.component.ts and verify that there are the following lines added (similar to login.component.ts)
private _auth: AuthService, private _router:Router
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
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();
});
}
I have this website that is almost a 100% complete but it is based on a customized bootstrap 2.X to meet my needs (bad practice, the fault is entirely on my end.) and what I would like to do is to come up with a modal login that looks like this:
DEMO
The live preview above is based on bootstrap 3.X
You can check with the below link.
Fiddle
<a data-target="#myModal" role="button" class="btn" data-toggle="modal">Launch demo modal</a>
<div class="modal fade hide" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-remote="/mmfansler/aQ3Ge/show/">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div style="margin-left:35%;>
<modal title="Login form" visible="showModal">
<form role="form">
<div class="form-group">
<label for="email">Email address</label>
<input type="email" class="form-control" id="email" placeholder="Enter email" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password" />
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</modal>
</div>
</div>
</div>
Please Try This one:
$(function() {
var $formLogin = $('#login-form');
var $formLost = $('#lost-form');
var $formRegister = $('#register-form');
var $divForms = $('#div-forms');
var $modalAnimateTime = 300;
var $msgAnimateTime = 150;
var $msgShowTime = 2000;
$("form").submit(function () {
switch(this.id) {
case "login-form":
var $lg_username=$('#login_username').val();
var $lg_password=$('#login_password').val();
if ($lg_username == "ERROR") {
msgChange($('#div-login-msg'), $('#icon-login-msg'), $('#text-login-msg'), "error", "glyphicon-remove", "Login error");
} else {
msgChange($('#div-login-msg'), $('#icon-login-msg'), $('#text-login-msg'), "success", "glyphicon-ok", "Login OK");
}
return false;
break;
case "lost-form":
var $ls_email=$('#lost_email').val();
if ($ls_email == "ERROR") {
msgChange($('#div-lost-msg'), $('#icon-lost-msg'), $('#text-lost-msg'), "error", "glyphicon-remove", "Send error");
} else {
msgChange($('#div-lost-msg'), $('#icon-lost-msg'), $('#text-lost-msg'), "success", "glyphicon-ok", "Send OK");
}
return false;
break;
case "register-form":
var $rg_username=$('#register_username').val();
var $rg_email=$('#register_email').val();
var $rg_password=$('#register_password').val();
if ($rg_username == "ERROR") {
msgChange($('#div-register-msg'), $('#icon-register-msg'), $('#text-register-msg'), "error", "glyphicon-remove", "Register error");
} else {
msgChange($('#div-register-msg'), $('#icon-register-msg'), $('#text-register-msg'), "success", "glyphicon-ok", "Register OK");
}
return false;
break;
default:
return false;
}
return false;
});
$('#login_register_btn').click( function () { modalAnimate($formLogin, $formRegister) });
$('#register_login_btn').click( function () { modalAnimate($formRegister, $formLogin); });
$('#login_lost_btn').click( function () { modalAnimate($formLogin, $formLost); });
$('#lost_login_btn').click( function () { modalAnimate($formLost, $formLogin); });
$('#lost_register_btn').click( function () { modalAnimate($formLost, $formRegister); });
$('#register_lost_btn').click( function () { modalAnimate($formRegister, $formLost); });
function modalAnimate ($oldForm, $newForm) {
var $oldH = $oldForm.height();
var $newH = $newForm.height();
$divForms.css("height",$oldH);
$oldForm.fadeToggle($modalAnimateTime, function(){
$divForms.animate({height: $newH}, $modalAnimateTime, function(){
$newForm.fadeToggle($modalAnimateTime);
});
});
}
function msgFade ($msgId, $msgText) {
$msgId.fadeOut($msgAnimateTime, function() {
$(this).text($msgText).fadeIn($msgAnimateTime);
});
}
function msgChange($divTag, $iconTag, $textTag, $divClass, $iconClass, $msgText) {
var $msgOld = $divTag.text();
msgFade($textTag, $msgText);
$divTag.addClass($divClass);
$iconTag.removeClass("glyphicon-chevron-right");
$iconTag.addClass($iconClass + " " + $divClass);
setTimeout(function() {
msgFade($textTag, $msgOld);
$divTag.removeClass($divClass);
$iconTag.addClass("glyphicon-chevron-right");
$iconTag.removeClass($iconClass + " " + $divClass);
}, $msgShowTime);
}
});
DEMO
More Demos