I can't update the table after adding new values - html

I'm new to angular, and I'm trying to insert new values and display them in a table. Thus, I have three components, one for listing the information of a user user-list, one for creating the information raws user-form and one for the presentation of these information single-user.
My issue is when I try to insert a new information raw, the table liste doesn't update or refresh it self even I did the redirection to it, and I don't know the raison why.
May someone gives me any indication. thanks in advance.
User-list.component.ts:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Router } from '#angular/router';
import { UserService } from '../services/user.service';
import { Subscription, Observable } from 'rxjs';
import { User} from '../model/user.model';
#Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit, OnDestroy {
constructor(private router: Router, private userService : UserService ) { }
userSubscription: Subscription;
users: Observable<User[]>;
ngOnInit() {
this.reloadData();
}
reloadData(){
this.userSubscription = this.userService.getResource("/users").subscribe(
data =>{
this.users= data;
console.log(this.users);
},
error => { console.log(error);
}
);
}
ngOnDestroy() { this.userSubscription.unsubscribe(); }
}
User-list.component.html:
<div id="page-wrapper">
<div class="main-page">
<div class="tables">
<app-user-form></app-user-form>
<div class="table-responsive bs-example widget-shadow" data-example-
id="contextual-table">
<table class="table table-hover ">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Age</th>
<th>Action</th>
</tr>
</thead>
<tbody class="body">
<ng-container *ngFor="let u of users">
<tr class="active"
app-single-user
[IdUser] = "u.idUser"
[NameUser] = "u.nameUser"
[AgeUser] = "u.ageUser"
>
</tr>
</ng-container>
</tbody>
</table>
</div>
</div>
</div>
</div>
User-form-component.ts
#Component({
selector: 'app-user-form',
templateUrl: './user-form.component.html',
styleUrls: ['./user-form.component.css']
})
export class UserFormComponent implements OnInit {
userForm: FormGroup;
constructor(private formBuilder: FormBuilder,
private router: Router,
private userService: UserService
) { }
ngOnInit() {
this.initForm();
}
initForm() {
this.userForm = this.formBuilder.group({
nameUser: ['', Validators.required],
ageUser: ['', Validators.required]
});
}
reInitForm() {
this.userForm = this.formBuilder.group({
nameUser: '',
ageUser: ''
});
}
onSubmit(){
const formValue = this.userForm.value;
const newuser = new User(
formValue['nameUser'],
formValue['ageUser']
);
this.userService.postResource('/users', newUser).subscribe(
data =>{
console.log(data)
},
error=>{
console.log(error)
}
);
this.reInitForm();
this.router.navigate(['/users']);
}
}
user-form-component.html:
<div class="table-responsive bs-example widget-shadow" data-example-id="contextual-table">
<div class="main-page">
<form [formGroup]="userForm" (ngSubmit)="onSubmit()" class="form-inline">
<div class="form-group">
<input type="text" class="form-control" id="name"
formControlName="nameUser" name="name" required>
<input type="text" class="form-control" id="age"
formControlName="ageUser" name="age" required>
</div>
<button type="submit" class="btn btn-success"
[disabled]="userForm.invalid">Submit</button>
</form>
</div>
</div>
I tried the redirect to the same component this.router.navigate(['/users']); in oder to refresh the content of the table but it doesn't work.
I appreciate it if someone can give me some hints or indications to solve it. thanks

As mentioned in the comments, users should be of type User[] since you are assigning the subscribed value to it and navigating to the same component will not cause the component to rerender.
Instead you can use #Output to achieve this. Once you add the newUser, you refresh the data in your parent component(user-list.component.ts).
user-form-component.ts
#Output() submitted = new EventEmitter<void>();
Then on success of your POST API, emit the event
this.userService.postResource('/users', newUser).subscribe(
data => {
console.log(data);
this.submitted.emit();
},
error => {
console.log(error);
}
);
In your parent component's template, you need to add this event to your custom component.
user-list.component.html
<app-user-form (submitted)="onSubmit($event)"></app-user-form>
Then in your parent component.
user-list.component.html
onSubmit() {
this.reloadData();
}
For more information on how to use #Output, see the docs.

Related

How do I reload data after deletion?

I have created some posts in my app as html cards. I have a component called PostList, where I am displaying all these cards. On every card I have a delete button to delete that specific card, which works, but after I delete one card, it doesn't disappear from my post list until I manually refresh the page. This is my card:
<div class="card-body">
<h5 class="card-title cut_text">{{post.title}}</h5>
<p class="card-text cut_text" style="text-align: left;">
{{post.text}}
</p>
<span>Read more</span>
<button *appHasRole='["Admin"]' class="ml-5" (click)="deletePost(post.id)" type="button" style="box-shadow: 1px 1px grey;"><em class="fa fa-trash"></em></button>
</div>
And this is the delete function:
#Component({
selector: 'app-post-card',
templateUrl: './post-card.component.html',
styleUrls: ['./post-card.component.css']
})
export class PostCardComponent implements OnInit {
#Input() post: Post;
posts: Post[];
model: any = {};
user: User;
postId: number;
constructor(private postService: PostsService, private toastr: ToastrService,
private route: ActivatedRoute, public accountService: AccountService) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
console.log(params);
this.postId = params['id'];
});
}
deletePost(id: number) {
this.postService.deletePost(id).subscribe(() =>{
this.toastr.success('Deleted');
}, error => {
console.log(error);
this.toastr.error(error.error);
});
}
}
This is the html of the post list:
<div class=" container mt-3" >
<span *ngFor="let post of posts">
<app-post-card [post]="post" class="item" ></app-post-card>
</span>
</div>
And this is the method to load the posts:
export class PostListComponent implements OnInit {
posts: Post[];
post: Post;
pagination: Pagination;
postParams: PostParams = new PostParams();
constructor(private postService: PostsService) { }
ngOnInit(): void {
this.loadPosts();
}
loadPosts() {
this.postService.getPosts(this.postParams).subscribe(response => {
this.posts = response.result;
this.pagination = response.pagination;
});
}
}
I have tried calling the loadPosts() method after deleting a card, althought it is not very efficient, but it doesn't work, I still have to refresh the page. What can I do so that it automatically disappears after I am deleting it?
You could use #Output from the child component to send the id that was deleted and remove the element corresponding to this id from the posts variable in parent component.
post-card.component.ts
import { Component, Input, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'app-post-card',
templateUrl: './post-card.component.html',
styleUrls: ['./post-card.component.css']
})
export class PostCardComponent implements OnInit {
#Input() post: Post;
#Output() postRemoved = new EventEmitter(); // <-- custom event
posts: Post[];
model: any = {};
user: User;
postId: number;
constructor(private postService: PostsService, private toastr: ToastrService,
private route: ActivatedRoute, public accountService: AccountService) {}
ngOnInit(): void {
this.route.params.subscribe((params) => {
console.log(params);
this.postId = params['id'];
});
}
deletePost(id: number) {
this.postService.deletePost(id).subscribe(() =>{
this.toastr.success('Deleted');
this.postRemoved.emit(id); // <-- emit the id in the event
}, error => {
console.log(error);
this.toastr.error(error.error);
});
}
}
post-list.component.html
<div class=" container mt-3" >
<span *ngFor="let post of posts">
<app-post-card (postRemoved)="onPostRemoved($event)" [post]="post" class="item" ></app-post-card>
</span>
</div>
post-list.component.ts
onPostRemoved(id: any) {
this.posts = JSON.parse(JSON.stringify( // <-- assign a deep clone
this.posts.filter(post => post.id !== id)
));
}

"formGroup expects a FormGroup instance. Please pass one in." Error when trying to display table

Trying to understand how to solve this problem. I was following a tutorial and I seem to be doing everything properly but still getting this error.
My web API is working properly when I tested in Postman. I also was getting a error involving CORS which I solved but this is the last error I need solved. Sorry if this is too basic of a question but I cant seem to be able to find a solution online that i can understand.
Here is my HTML and TS file
HTML
<div class="myContent">
<form [formGroup]="viewClientsForm" (ngSubmit)="getClients(viewClientsForm)">
<div style="text-align:center;padding-left:20px;padding-right:20px">
<br />
<br />
<div class="table-responsive">
<table class="table table-bordered">
<tr style="background-color:rgba(220,230,242,1); font-size:12pt">
<th style="text-align:left;">First Name</th>
<th style="text-align:left;">Last Name</th>
<th style="text-align:left;">Phone Number</th>
<th style="text-align:left;">Amount</th>
<th style="text-align:left;">Status</th>
</tr>
<tr *ngFor="let clients of client" style="background-color:white">
<td> {{clients.FirstName }} </td>
<td> {{clients.LastName }} </td>
<td> {{clients.HomeNumber}} </td>
<td> {{clients.AssetValue}} </td>
<td> {{clients.AccountStatus }} </td>
</tr>
</table>
</div>
</div>
</form>
</div>
TS file
import { Component, OnInit } from '#angular/core';
import { IClient } from '../CPM-Interfaces/client';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '#angular/forms';
import { ClientService } from '../services/clientService/client.service';
#Component({
selector: 'app-view-clients',
templateUrl: './view-clients.component.html',
styleUrls: ['./view-clients.component.css']
})
export class ViewClientsComponent implements OnInit {
viewClientsForm: FormGroup;
client: IClient[];
errorMsg: string = null;
showMsgDiv: boolean = false;
constructor(private formBuilder: FormBuilder, private clientService: ClientService) { }
ngOnInit() {
this.getClients();
if (this.client == null) {
this.showMsgDiv = true;
}
}
getClients() {
this.clientService.GetClients().subscribe(
responseProductData => {
this.client = responseProductData;
this.showMsgDiv = false;
},
responseProductError => {
this.client = null;
this.errorMsg = responseProductError;
console.log(this.errorMsg);
}
);
}
}
In the template,
You have bonded viewClientsForm variable to formGroup property.
<form [formGroup]="viewClientsForm" (ngSubmit)="getClients(viewClientsForm)">
viewClientsForm is defined but the value is null. That's why angular is throwing errors.
You either have to define a FormGroup instance or remove the binding if it's not used
like:
<form (ngSubmit)="getClients(viewClientsForm)">
It's because viewClientsForm value is null
import { Component, OnInit } from '#angular/core';
import { IClient } from '../CPM-Interfaces/client';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '#angular/forms';
import { ClientService } from '../services/clientService/client.service';
#Component({
selector: 'app-view-clients',
templateUrl: './view-clients.component.html',
styleUrls: ['./view-clients.component.css']
})
export class ViewClientsComponent implements OnInit {
// HERE you can do viewClientsForm = this.formBuilder.group({...etc})
viewClientsForm: FormGroup;
client: IClient[];
errorMsg: string = null;
showMsgDiv: boolean = false;
constructor(private formBuilder: FormBuilder, private clientService: ClientService) { }
ngOnInit() {
this.getClients();
if (this.client == null) {
this.showMsgDiv = true;
}
}
getClients() {
this.clientService.GetClients().subscribe(
responseProductData => {
this.client = responseProductData;
this.showMsgDiv = false;
},
responseProductError => {
this.client = null;
this.errorMsg = responseProductError;
console.log(this.errorMsg);
}
);
}
}

I'm getting Cannot read property 'appendChild' of null(on chrome) and this.container is null(on firefox) errors when I started using material dialog

I have a table in my frontend that has a list of all my users from a MySQL database using a spring API. I wanted to create a material dialog that would open when clicking on a user but for some reason I'm getting a bunch of errors on firefox and chrome which are mentioned above and I haven't found anything online to help even though I followed many tutorials to create the angular dialog but i still got the same erros.
Here's my component html that has the list of users:
<div class="container-scroller">
<app-navbar></app-navbar>
<div class="container-fluid page-body-wrapper">
<app-sidebar></app-sidebar>
<div class="main-panel">
<div class="content-wrapper">
<div class="row">
<div class="col-lg-12 grid-margin stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title" style="font-weight: 600">Users List</h4>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
<th>Profile Picture</th>
<th>Username</th>
<th>Last Name</th>
<th>First Name</th>
<th>Email</th>
<th>Enabled</th>
<th>Registered Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let u of users" (click)="openDialog()" id="myId">
<td>{{u.id}}</td>
<td>{{u.profilePicture}}</td>
<td>{{u.username}}</td>
<td>{{u.lastName}}</td>
<td>{{u.firstName}}</td>
<td>{{u.email}}</td>
<ng-container *ngIf="u.enabled; else elseTemplate">
<td class="text-success">{{u.enabled}}</td>
</ng-container>
<ng-template #elseTemplate>
<td class="text-danger">{{u.enabled}}</td>
</ng-template>
<td>{{ u.registeredDate | date: shortDate }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
the .ts file:
import { Component, OnInit } from '#angular/core';
import { ViewEncapsulation } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { UserService } from '../user.service';
import { MatDialog, MatDialogConfig } from '#angular/material';
import { NewDialogComponent } from '../new-dialog/new-dialog.component';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['../app.component.scss', './dashboard.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DashboardComponent implements OnInit {
loginuser: any = {};
users: any[] = [];
constructor(private service: UserService, private dialog: MatDialog) {
this.loginuser = JSON.parse(localStorage.getItem('currentUser'));
this.service.getAllUsers(this.loginuser.token).subscribe(u => {
this.users = u;
console.log(this.users);
});
}
ngOnInit() {
}
openDialog() {
console.log('selected item: ', selectedItem);
const dialogConfig = new MatDialogConfig();
dialogConfig.disableClose = true;
dialogConfig.autoFocus = true;
dialogConfig.data = {
id: 1,
title: 'Angular for Beginners'
};
this.dialog.open(NewDialogComponent, dialogConfig);
const dialogRef = this.dialog.open(NewDialogComponent, dialogConfig);
}
}
and here's the new dialog html component:
<h2 mat-dialog-title>This is a Dialog title</h2>
<mat-dialog-content>
<p> Place content here </p>
</mat-dialog-content>
<mat-dialog-actions>
<button class="mat-raised-button" (click)="close()">Close</button>
</mat-dialog-actions>
and the .ts file:
import { Component, OnInit, Inject } from '#angular/core';
import { MatDialog, MAT_DIALOG_DATA, MatDialogRef } from '#angular/material';
#Component({
selector: 'app-new-dialog',
templateUrl: './new-dialog.component.html',
styleUrls: ['./new-dialog.component.scss']
})
export class NewDialogComponent implements OnInit {
description: string;
constructor(private fb: FormBuilder, private dialogRef: MatDialogRef<NewDialogComponent>,
#Inject(MAT_DIALOG_DATA) public data: any) {
this.description = data.description;
}
ngOnInit() {}
close() {
this.dialogRef.close();
}
}
At first glance, it looks like you're opening your dialog twice:
this.dialog.open(NewDialogComponent, dialogConfig);
const dialogRef = this.dialog.open(NewDialogComponent, dialogConfig);
Not sure if that is what is causing the exact error, but it's the first thing I noticed.
Update:
It looks now to me like this line is the error:
this.description = data.description;
I'm not seeing any property being set for "description"-- just 'id' and 'title'.

My CRUD Application In Angular Using API is not working as a Single Page Application(SPA) while updating

I have performed the CRUD Application In Angular Using API and it is working fine but the problem is that when I am updating the values it is not showing the updated value instantly, I have to reload the page.
This is my app.component.ts:
import {Component} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Employee} from './employees';
import {EditComponent} from './edit/edit.component';
import {AppService} from './app.service';
import {Router} from '#angular/router';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [AppService]
})
export class AppComponent {
form:any = {}
msg: string = null;
employees: Employee[];
constructor(
public http: HttpClient,private appService:AppService,private router: Router
){}
onSubmit(){
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
this.http.post('http://127.0.0.1:8000/api/employee',this.form,httpOptions)
.subscribe(employee=>{
employee = employee;
this.msg = 'Updated successfully!';
this.getEmployee();
});
}
ngOnInit() {
this.getEmployee();
}
getEmployee():void{
this.appService.getEmployees().subscribe(employees=>(this.employees = employees))
}
delete(employee: Employee): void{
if(confirm("Are you sure want to delete ?")) {
console.log("user details delete successfully!!");
this.employees = this.employees.filter(h =>h !== employee);
this.appService.deleteEmployees(employee.id).subscribe();
this.msg = 'Employee details delete successfully!!';
}else{
}
}
public editComponent: boolean = false;
loadMyChildComponent($id)
{
this.editComponent = true;
this.appService.setCurrentId($id);
}
}
This is my edit.component.ts:
import {Component, OnInit, Input} from '#angular/core';
import {AppService} from '../app.service';
import {Employee} from '../employees';
import {Router} from '#angular/router';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {NgForm} from '#angular/forms';
import {Observable} from 'rxjs';
import { ActivatedRoute } from '#angular/router';
import {FormBuilder, FormGroup, Validators} from "#angular/forms";
#Component({
selector: 'app-edit',
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.css']
})
export class EditComponent implements OnInit {
#Input() employee: Employee[];
form:any = {}
msg: string = null;
constructor(public http: HttpClient,private appService:AppService,private router: Router,private route: ActivatedRoute) { }
ngOnInit(){
this.editEmployees();
}
editEmployees():void{
const id = this.appService.getCurrentId();
this.appService.editEmployees(id).subscribe(employee => {
this.employee = employee;
this.editEmployees();
});
}
onformSubmit()
{
this.appService.updateEmployees(this.employee).subscribe(employee=>{
this.employee = employee;
this.msg = 'Updated successfully!';
});
}
}
This is my employees.ts:
export interface Employee{
id: number;
username:string;
email:string;
mobile:string;
password:string;
}
This is my app.component.html: where I am showing the values and edit button.
<table class="table">
<tr>
<th>Id</th>
<th>User Name</th>
<th>Email</th>
<th>Mobile</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<tr *ngFor="let employee of employees">
<td>{{employee.id}}</td>
<td>{{employee.username}}</td>
<td>{{employee.email}}</td>
<td>{{employee.mobile}}</td>
<td><button (click)="loadMyChildComponent(employee.id);" class="btn btn-primary" [routerLink]="['/edit',employee.id]">Edit</button></td>
<td><button class="btn btn-danger" (click)="delete(employee)" > Delete</button></td>
</table>
This is my edit.component.html:
<div class="mydiv22">
<p class="msg_success">{{ msg }}</p>
<h2>Update Form</h2>
<div class="row">
<div class="col-md-12">
<form name="form" (ngSubmit)="f.form.valid && onformSubmit()" #f="ngForm" novalidate>
<div class="form-group">
<label for="username">User Name</label>
<input type="text" class="form-control" name="username" [(ngModel)]="this.employee.username" #username="ngModel"
[ngClass]="{'is-invalid': f.submitted && username.invalid}" required id="username"/>
<div *ngIf="f.submitted && username.invalid" class="invalid-feedback">
<div *ngIf="username.errors.required">>> required</div>
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" [(ngModel)]="this.employee.email" #email="ngModel" [ngClass]="{'is-invalid': f.submitted && email.invalid}"
required email placeholder="Enter your email address" id="email"/>
<div *ngIf="f.submitted && email.invalid" class="invalid-feedback">
<div *ngIf="email.errors.required">>> required</div>
<div *ngIf="email.errors.email">>> must be a valid email address</div>
</div>
</div>
<div class="form-group">
<label for="mobile">Mobile</label>
<input type="number" class="form-control" name="mobile" [(ngModel)]="this.employee.mobile" #mobile="ngModel"
[ngClass]="{'is-invalid': f.submitted && mobile.invalid}" required placeholder="Enter your mobile" pattern="[789][0-9]{9}" minlength="10" id="mobile"/>
<div *ngIf="f.submitted && mobile.invalid" class="invalid-feedback">
<div *ngIf="mobile.errors.required">>> required</div>
<div *ngIf="mobile.errors.pattern">>>Please enter a valid mobile number</div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" [(ngModel)]="this.employee.password" #password="ngModel"
[ngClass]="{'is-invalid':f.submitted && password.invalid}" required minlength="6" placeholder="Create your password" id="password"/>
<div *ngIf="f.submitted && password.invalid" class="invalid-feedback">
<div *ngIf="password.errors.required">>> required</div>
<div *ngIf="password.errors.minlength">>> must be at least 6 characters</div>
</div>
</div>
<div class="form-group">
<button routerLink="/edit" class="btn btn-success">Update</button>
</div>
</form>
</div>
</div>
</div>
The flow is that: when i click the edit button in app.component.html, It will take the id and go to app.component.ts. From app.component.ts, it will go to app.service.ts where it will fetch the values from the API using particular Id. From the app.service.ts, it will pass the values to the edit.component.ts and using edit.component.ts, it will pass the values to edit.component.html.
It is performing every thing fine like when adding the value it is showing instantly, I don't have to reload the page but while updating the values we have to reload the page, it is not showing instantly like SPA.
I want to show the updated values instantly without updating the page. Any help is much appreciated.
You have three components in same page, it is something about component interactions.
Add Output event property in to EditComponent, emit an event after editing of employee , like this:
import { Output, EventEmitter } from '#angular/core'
export class EditComponent {
#Output() updated = new EventEmitter<Employee>();
onFormSubmit() {
this.appService.updateEmployees(this.employee).subscribe(employee=>{
this.employee = employee;
this.msg = 'Updated successfully!';
// fire an updated event after edit employee.
this.updated.emit(employee)
});
}
}
Then, subscribe to the event in app.component.html, like this:
<app-edit (updated)="onUpdated()"></app-edit>
And then, call getEmployee in onUpdated method to reload the employees list , like this:
export class AppComponent {
onUpdated() {
this.getEmployee();
}
}
For more, please refer to https://angular.io/guide/component-interaction
You can add the similar logic to RegisterComponent to get a reload.

Adding a Popup Window with Angular TypeScript

Basically, I would like for a Popup window to appear when I click on this button:
<a (click)="open()" class='btn btn-primary m-r-5px'>
<span class='glyphicon glyphicon-eye-open'></span> View
</a>
To do this, I used the following example.
Here's how I applied the example to my app:
This is my popup HTML code:
<div class="modal-header">
<h4 class="modal-title">Challenge Details</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!-- HTML table for displaying a challenge details -->
<table class='table table-hover table-responsive table-bordered'>
<tr>
<td class="w-40-pct">Name</td>
<td>{{challenge?.name}}</td>
</tr>
<tr>
<td>Duration</td>
<td>${{challenge?.duration}}</td>
</tr>
<tr>
<td>Description</td>
<td>{{challenge?.description}}</td>
</tr>
<tr>
<td>Quiz</td>
<td>{{challenge?.Quiz.title}}</td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="activeModal.close('Close click')">Close</button>
</div>
Here's it's typescript file view-one-challenge.component.ts:
import { Component, OnInit, Input } from '#angular/core';
import {NgbModal, NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-view-one-challenge',
templateUrl: './view-one-challenge.component.html',
styleUrls: ['./view-one-challenge.component.css']
})
export class ViewOneChallengeComponent implements OnInit {
#Input() name;
#Input() duration;
#Input() description;
#Input() title;
constructor(public activeModal: NgbActiveModal) { }
ngOnInit() {
}
}
And here's the typescript file of the component where I want the popup to appear chalist.component.ts:
import {Component, OnInit, Output, EventEmitter, NgModule} from '#angular/core';
import {Challenge} from '../../_models/challenge';
import { Quiz } from '../../_models/quiz';
import {User} from '../../_models/user';
import {ChallengeService} from '../../_services/challenge.service';
import {BrowserModule} from '#angular/platform-browser';
import {CommonModule, Location} from '#angular/common';
import {AlertService} from '../../_services';
import { QuizService } from '../../_services/quiz.service';
import { ViewOneChallengeComponent } from '../view-one-challenge/view-one-challenge.component';
import {FormGroup, FormBuilder, Validators} from '#angular/forms';
import {ActivatedRoute, Params, Router} from '#angular/router';
import { NgbModal, NgbModule } from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-chalist',
templateUrl: './chalist.component.html',
styleUrls: ['./chalist.component.css'],
providers: [ChallengeService, QuizService],
})
#NgModule({
entryComponents: [ViewOneChallengeComponent]
})
export class ChalistComponent implements OnInit {
challenge_list: Array<Challenge>;
challenge: Challenge;
create_challenge_form: FormGroup;
show_create_challenge_html=false;
quizzes: Array<Quiz>;
constructor(
private challengeService: ChallengeService,
private alertService: AlertService,
private route: ActivatedRoute,
private router: Router,
formBuilder: FormBuilder,
private _location: Location,
private modalService: NgbModal) {
}
ngOnInit() {
console.log("inside ngOnInit...");
this.challengeService.getChallenges().subscribe(
data => {
this.challenge_list = data;
this.alertService.success('Récupération des challenges OK', true);
},
error => {
this.alertService.error(error);
});
}
viewChallenge(id: number) {
if (id > 0) {
this.challengeService.getChallengeById(id).subscribe(
data => {
this.challenge = data;
},
error => {
this.alertService.error(error);
});
}
}
// user clicks 'create' button
createChallenge(){
this.show_create_challenge_html = !this.show_create_challenge_html;
}
readOneChallenge(id) {}
updateChallenge(id) {}
deleteChallenge(id) {}
open() {
const modalRef = this.modalService.open(ViewOneChallengeComponent);
modalRef.componentInstance.name = 'World';
}
}
The method that should open the popup once a user clicks on the button is open(), and the button in question is this one:
<a (click)="open()" class='btn btn-primary m-r-5px'>
<span class='glyphicon glyphicon-eye-open'></span> View
</a>
However, when I run the app and clicks on the link that contains the button, i get the following error in my browser's console:
"StaticInjectorError(AppModule)[ChalistComponent -> NgbModal]: \n StaticInjectorError(Platform: core)[ChalistComponent -> NgbModal]: \n NullInjectorError: No provider for NgbModal!"
The example that I'm following clearly states that:
You can pass an
existing component as content of the modal window. In this case
remember to add content component as an entryComponents section of
your NgModule.
So what I did was, I added the ViewChallengeComponent as an entrypoint to my #NgModule in my chalist.component.ts file, still that didn't solve the problem.
Could anyone please tell me what am I doing wrong here?
Your ngbModal should be provided in the providers.
Change your code to this in chalist.component.ts
#Component({
selector: 'app-chalist',
templateUrl: './chalist.component.html',
styleUrls: ['./chalist.component.css'],
providers: [ChallengeService, QuizService, NgbModal],
})
If you want to use this module throughout your application, then it is better that you provide it in app.module.ts
You have to import it and supply it in the providers list. So instead of doing it in chalist.component.ts or any other component individually, you can provide it globally so that all components under app.module can use it.