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 = {};
}
}
Related
I created an email authentication based registration page in my angular app, added the code with submission functionality (onSubmit) to register.component.html and the methods & services in register.component.ts & UserService.ts files.
Problem:
After adding the code as shared below, the registration page (register.component.html) itself does not load when I click the corresponding router link;
the issue is not with routing as it all worked fine until I added the methods & services.
No error thrown at time of compilation.
Pls suggest what to do.
Showing my respective files in register component:
register.component.html
<style>
.form-container {
display: flex;
align-items: center;
justify-content: center;
height: 50vh;
flex-wrap: wrap;
margin-top:25px;
}
.form-row {
display: flex;
flex-wrap: nowrap;
}
.form-group {
flex: 1;
margin: 20px;
}
</style>
<div class="registrationForm" type="FormGroup">
<form (ngSubmit)="onSubmit()">
<div class="form-row">
<div class="form-group">
<label for="exampleInputUsername">Username</label>
<input type="text" class="form-control" id="exampleInputUsername" placeholder="eg. Niti Sara">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Email:</label>
<input type="email" [(ngModel)]="email" name="email" required class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="eg. john#doe.com">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="exampleInputPhone">Phone No.</label>
<input type="number" class="form-control" id="exampleInputPhone" placeholder="eg. +1300 400 5000" >
</div>
<div class="form-group">
<label for="exampleInputUrl">Website URL</label>
<input type="link" class="form-control" id="exampleInputUrl" placeholder="eg. https://example.com/">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="exampleInputCname">Your Organisation</label>
<input type="text" class="form-control" id="exampleInputCname" placeholder="eg. Enter Your Organisation Name">
</div>
</div>
<div class="form-row">
<label>Password:</label>
<input type="password" [(ngModel)]="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary" style="margin-left:220px;margin-top:20px;">Submit</button>
</form>
</div>
register.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { UserService } from 'src/app/register/UserService'; //import the user service
import { FormBuilder, FormGroup, Validators } from '#angular/forms'; //import form modules
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.less']
})
export class RegisterComponent implements OnInit {
registrationForm: FormGroup;
email:string ='';
password:string ='';
submitted = false;
constructor(
private formBuilder: FormBuilder,
private router: Router,
private userService: UserService,
)
{
this.registrationForm = this.formBuilder.group({});
}
ngOnInit() {
this.registrationForm = this.formBuilder.group({
email: [this.email, [Validators.required, Validators.email]],
password: [this.password, [Validators.required, Validators.minLength(6)]],
});
}
// convenience getter for easy access to form fields
get f() { return this.registrationForm.controls; }
onSubmit() {
this.submitted = true;
if (this.registrationForm.invalid) {
return;
}
//call the user service to register the user
this.userService.register(this.registrationForm.controls['email'].value, this.registrationForm.controls['password'].value)
.subscribe(data => {
// handle the response
});
//error handling can b introduced
}
}
UserService.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserService {
private baseUrl = 'http://localhost:8080/'; // replace with your backend URL
constructor(private http: HttpClient) { }
//check the use of 'Observable'
register(email: string, password: string): Observable<any> {
const data = {
email: email,
password: password
};
return this.http.post(`${this.baseUrl}/register`, data);
}
}
This is what my browser console says:
ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[FormBuilder -> FormBuilder -> FormBuilder]:
NullInjectorError: No provider for FormBuilder!
Just import HttpClientModule in your app.module.ts. That's the only problem I can see here.
The problem was due to not adding FormsModule & ReactiveFormsModule in both app.module.ts & register.component.spec.ts
app.module.ts
import { FormsModule } from '#angular/forms';
import { ReactiveFormsModule } from '#angular/forms';
imports: [
FormsModule,
ReactiveFormsModule
],
register.component.spec.ts
import { FormsModule } from '#angular/forms';
import { ReactiveFormsModule } from '#angular/forms';
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RegisterComponent ],
imports: [
FormsModule, // << ----- add this line
ReactiveFormsModule // << ----- add this line
]
})
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 started working on Angular 9 and I am using the Reactive Form in Angular 9 but the problem is that the validators and errors are not working for the form.
This is my app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
This is my app.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '#angular/forms';
import { MustMatch } from './_helpers/must-match.validator';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'my-assignment';
submitted = false;
show: boolean;
profileForm: FormGroup;
constructor(private fb: FormBuilder) {
this.show = true;
}
ngOnInit() {
this.profileForm = this.fb.group({
email: ['', [Validators.required, Validators.pattern('[a-z0-9.#]*')]],
password: ['', [Validators.required, Validators.minLength(8)]],
confirmpassword: ['', Validators.required],
}, {
validator: MustMatch('password', 'confirmpassword')
});
}
get f() { return this.profileForm.controls; }
onSubmit() {
// TODO: Use EventEmitter with form value
console.warn(this.profileForm.value);
}
// click event function toggle
password() {
this.show = !this.show;
}
}
This is my app.component.html:
<div class="jumbotron">
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
<form style="margin-top: 100px;" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="firstName">Email: </label>
<input type="text" placeholder="Email" formControlName="email">
<div *ngIf="f.email.hasError('pattern')">
Oops, wrong pattern buddy!
</div>
</div>
<div class="form-group">
<label for="password">Password: </label>
<input [type]="show ? 'text' : 'password'" placeholder="Password" formControlName="password">
<div *ngIf="submitted && f.password.errors" class="invalid-feedback">
<div *ngIf="f.password.errors.required">Password is required</div>
<div *ngIf="f.password.errors.minlength">Password must be at least 6 characters</div>
</div>
</div>
<div class="form-group">
<label for="confirmpassword">Confirm Password: </label>
<input type="password" placeholder="Confirm Password" formControlName="confirmpassword" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.confirmPassword.errors }" />
<div *ngIf="submitted && f.confirmpassword.errors" class="invalid-feedback">
<div *ngIf="f.confirmpassword.errors.required">Confirm Password is required</div>
<div *ngIf="f.confirmpassword.errors.mustMatch">Passwords must match</div>
</div>
</div>
<button (click)="password()">Show Password</button>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
</form>
</div>
</div>
</div>
</div>
This is my must-match.validator.ts:
import { FormGroup } from '#angular/forms';
// custom validator to check that two fields match
export function MustMatch(controlName: string, matchingControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const matchingControl = formGroup.controls[matchingControlName];
if (matchingControl.errors && !matchingControl.errors.mustMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
if (control.value !== matchingControl.value) {
matchingControl.setErrors({ mustMatch: true });
} else {
matchingControl.setErrors(null);
}
};
}
core.js:6185 ERROR TypeError: Cannot read property 'errors' of undefined
Any help is much appreciated.
You have a typo : confirmPassword ( *ngIf="f.confirmPassword.errors.required").
It's confirmpassword everywhere else.
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();
});
}
so I have this html code.. i tried using (click) function, and its still like this
<div class="container">
<h1><a [routerLink]="['/databuku']"><img src="images/images.png" width="42" height="42"></a>
Add New Book</h1>
<div class="row">
<div class="col-md-6">
<form (ngSubmit)="saveBuku()" #bukuForm="ngForm">
<div class="form-group">
Judul
<input type="text" class="form-control" [(ngModel)]="buku.judul" name="judul" required>
</div>
<div class="form-group">
Author
<input type="text" class="form-control" [(ngModel)]="buku.author" name="author" required>
</div>
<div class="form-group">
Description
<textarea class="form-control" [(ngModel)]="buku.description" name="description" required cols="40" rows="5"></textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success" [disabled]="!bukuForm.form.valid">Save</button>
</div>
</form>
</div>
</div>
</div>
here is my ts file
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-tambah-buku',
templateUrl: './tambah-buku.component.html',
styleUrls: ['./tambah-buku.component.css']
})
export class ComponentTambahBuku implements OnInit {
buku = {};
constructor(private http: HttpClient, private router: Router) { }
ngOnInit() {
}
saveBuku() {
this.http.post('http://localhost:8080/buku', this.buku)
.subscribe(res => {
let id = res['id'];
this.router.navigate(['/detail-buku/', id]);
}, (err) => {
console.log(err);
}
);
}
}
no errors found when I open localhost:4200, its just when i press the save button, its like the button doesn't working, not saving and not going to 'detail-buku' page