Angular 9 ng-bootstrap 6.1 Modal component open method not working - angular9

I've written an Angular 9 modal dialog component that I am migrating from bootstrap to ng-bootstrap 6.1. Here's the template:
<ng-template #confirm let-modal tabindex="-1" aria-labelledby="confirmModalTitle">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" [innerHTML]="safeHeader"></h5>
<button type="button" (click)="onCancel()" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" [innerHTML]="safeBody">
</div>
<div class="modal-footer d-flex justify-content-between">
<button type="button" (click)="onCancel()" class="btn btn-primary" data-dismiss="modal">No</button>
<button type="button" (click)="onOK()" class="btn btn-secondary btn-danger">Yes</button>
</div>
</div>
</div>
</ng-template>
Here's the code:
import { Component, OnInit, Input, EventEmitter, Output, ViewChild, ElementRef, TemplateRef} from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
import { IqBaseComponent } from '../shared/iq-base.component';
import { ResponsiveState } from 'ngx-responsive';
import { NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { Template } from '#angular/compiler/src/render3/r3_ast';
declare var $: any;
#Component({
selector: 'my-confirm',
templateUrl: './confirm.component.html'
})
export class ConfirmComponent extends IqBaseComponent implements OnInit {
#Input() header: string;
#Input() body: string;
#Output() confirmationResult: EventEmitter<boolean> = new EventEmitter<boolean>();
#ViewChild('confirm', { static: false }) private confirm: TemplateRef<any>;
get safeHeader(): SafeHtml {
return this.domSanitizer.bypassSecurityTrustHtml(this.header);
}
get safeBody(): SafeHtml {
return this.domSanitizer.bypassSecurityTrustHtml(this.body);
}
constructor(private modalService: NgbModal, private domSanitizer: DomSanitizer, private responsiveState: ResponsiveState) {
super(responsiveState);
}
ngOnInit() {
}
show() {
this.modalService.open(confirm, { backdrop: true, size: 'sm', keyboard: true, centered: true });
}
onOK() {
this.modalService.dismissAll();
this.confirmationResult.emit(true);
}
onCancel() {
this.modalService.dismissAll();
this.confirmationResult.emit(false);
}
}
When the show() method is invoked and this.modalService.open(...) is called, I get the following run time exception:
core.js:6189 ERROR Error: Uncaught (in promise): Error: ASSERTION ERROR: Type passed in is not ComponentType, it does not have 'ɵcmp' property.
Error: ASSERTION ERROR: Type passed in is not ComponentType, it does not have 'ɵcmp' property.
at throwError (core.js:1335) [angular]
at assertComponentType (core.js:2934) [angular]
at ComponentFactoryResolver$1.resolveComponentFactory (core.js:33795) [angular]
at NgbModalStack._createFromComponent (ng-bootstrap.js:6196) [angular]
at NgbModalStack._getContentRef (ng-bootstrap.js:6178) [angular]
at NgbModalStack.open (ng-bootstrap.js:6118) [angular]
at NgbModal.open (ng-bootstrap.js:6290) [angular]
at ConfirmComponent.show (confirm.component.ts:46) [angular]
The component was instantiated in another component like so:
<my-confirm #saveDiscard [header]="'Confirm Discarding Changes'" [body]="'Are you sure you want to discard changes?'"></my-confirm>
and referenced in the code-behind like so:
#ViewChild('saveDiscard', { static: true }) public saveDiscardConfirmer: ConfirmComponent;
...
canDeactivate(): Observable<boolean> {
let retValue: Observable<boolean>;
if (this.myForm.isDirty) {
retValue = this.saveDiscardConfirmer.confirmationResult.asObservable();
this.saveDiscardConfirmer.show();
} else {
retValue = of(true);
}
return retValue;
}
Any ideas on how to fix this?

To make this work, I ended up with an NgbActiveModal - NgbModal combo component:
import { Component, OnInit, Input, EventEmitter, Output, ViewChild, ElementRef, TemplateRef} from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
import { IqBaseComponent } from '../shared/my-base.component';
import { ResponsiveState } from 'ngx-responsive';
import { NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'my-confirm-content',
templateUrl: './confirm.component.html'
})
export class ConfirmContentComponent {
#Input() header: string;
#Input() body: string;
get safeHeader(): SafeHtml {
return this.domSanitizer.bypassSecurityTrustHtml(this.header);
}
get safeBody(): SafeHtml {
return this.domSanitizer.bypassSecurityTrustHtml(this.body);
}
constructor(public activeModal: NgbActiveModal, private domSanitizer: DomSanitizer) { }
}
#Component({
selector: 'my-confirm',
template: ''
})
export class ConfirmComponent extends IqBaseComponent implements OnInit {
#Input() header: string;
#Input() body: string;
#Output() confirmationResult: EventEmitter<boolean> = new EventEmitter<boolean>();
#ViewChild('confirm', { static: false }) private confirm: TemplateRef<any>;
constructor(private modalService: NgbModal, private responsiveState: ResponsiveState) {
super(responsiveState);
}
ngOnInit() {
}
async show() {
const modalRef = this.modalService.open(ConfirmContentComponent, { backdrop: true, keyboard: true });
modalRef.componentInstance.header = this.header;
modalRef.componentInstance.body = this.body;
this.confirmationResult.emit(await modalRef.result);
}
}
Where the ./confirm.component.html contains:
<div class="modal-header">
<h5 class="modal-title" [innerHTML]="safeHeader"></h5>
<button type="button" (click)="activeModal.close(false)" class="close" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" [innerHTML]="safeBody">
</div>
<div class="modal-footer d-flex justify-content-between">
<button type="button" (click)="activeModal.close(false)" class="btn btn-primary">No</button>
<button type="button" (click)="activeModal.close(true)" class="btn btn-secondary btn-danger">Yes</button>
</div>
and my app.module.ts includes:
entryComponents: [
ConfirmContentComponent
],

Wrap your component with a ng-template, like this:
<ng-template #myContent>
<my-dialog-component></my-dialog-component>
</ng-template>

Related

*ngFor a component but change source of image inside that component Angular

So I want to call a component multiple times with a *ngFor but inside each call I want each img to change their source attributes from a list of sources I have stored in child-component.ts
parent html
<app-thumbnail *ngFor="let video of video_ids;"></app-thumbnail>
child html
<div class="single-thumbnail-container">
<div class="separator"></div>
<img class="thumbnails" [ngClass]="{ selected: isSelected === true }"
[src]="thumbnails[index]" (click)="selectVideo()">
<div class="overlay"></div>
<div class="separator"></div>
</div>
parent TypeScript
import { Component, OnInit } from '#angular/core';
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
import { ThumbnailComponent } from './thumbnail/thumbnail.component';
#Component({
selector: 'app-youtube-videos',
templateUrl: './youtube-videos.component.html',
styleUrls: ['./youtube-videos.component.scss']
})
export class YoutubeVideosComponent implements OnInit {
url!: string;
video_ids!: string[];
ngOnInit() {
this.video_ids = ['xXOZiFmjSVE', 'i1QST3prI7Y', 'cgDZN44WpoE', 'tKD6yT9Jv-w', 'X6bXkv7Opg4', 'nVy0JdoLILU', 'vYH67L1x5qk', 'GReYTgrrdro', 'l9J9WcaI7b0', 'ieH1pPktlgg', 'oAAiRBGY-BI', 'SxKEB0MC3NE', 'fm4EP_tWmXs', 'MKHKu1krm1I', 'UgswO0nHsqA', 'wku7zvDDRk0', 'Qk13QMMHksc', 'httfJoffl9E', '0QcKISkrIaQ', 'KkN1son2i_c', 'CXIbfrwMRQI', 'VASpq7FU6Mo', 'SlBSwK_5xn8', '0o2kAz6cpxA', '00ff2UcGLu0', 'XO3UkRift0A', 'bThL2wlzEJc', 'OmnJpAppY9E', 'DCXfaSR8Ka8', '6dl_MEhdJqI', 'QS952qoqYLA', 'wp0IxPy32Ds'];
this.url = this.video_ids[0];
}
}
#Pipe({ name: 'safe' })
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl("https://www.youtube-nocookie.com/embed/" + url);
}
}
child TypeScript
import { Component, OnInit } from '#angular/core';
import { YoutubeVideosComponent } from '../youtube-videos.component';
#Component({
selector: 'app-thumbnail',
templateUrl: './thumbnail.component.html',
styleUrls: ['./thumbnail.component.scss']
})
export class ThumbnailComponent implements OnInit {
thumbnails!: string[];
isSelected!: boolean;
youtubeVideosComponent!: YoutubeVideosComponent;
index!: number;
ngOnInit(){
this.thumbnails = [];
for (let i = 0; i < this.youtubeVideosComponent.video_ids.length; i++){ this.thumbnails.push("https://img.youtube.com/vi/" + this.youtubeVideosComponent.video_ids[i] + "/0.jpg") }
this.isSelected = false;
}
selectVideo(){
if (this.isSelected === false){
this.isSelected = true;
}
else {
this.isSelected = false;
}
}
}
Spent few hours trying to find a solution but didn't, thanks for helping me out!
You could add an #Input to your child component that will be passed by the parent
child.ts
#Component({...})
export class ThumbnailComponent implements OnInit {
#Input() videoId!: string;
getThumbnail(): string {
return `https://img.youtube.com/vi/${this.videoId}/0.jpg`;
}
...
...
}
child.html
<div class="single-thumbnail-container">
<div class="separator"></div>
<img
class="thumbnails"
[ngClass]="{ selected: isSelected === true }"
[src]="getThumbnail()"
(click)="selectVideo()">
<div class="overlay"></div>
<div class="separator"></div>
</div>
parent.html
<app-thumbnail
*ngFor="let video of video_ids"
[videoId]="video"
>
</app-thumbnail>

Angular 10 error NG8002 can't bind object

I'm getting the following error whenever I add the following line of code to an .html file:
Error: src/app/department/show-dep/show-dep.component.html:22:11 -
error NG8002: Can't bind to 'dep' since it isn't a known property of
'app-add-edit-dep'.
If 'app-add-edit-dep' is an Angular component and it has 'dep' input, then verify that it is part of this module.
If 'app-add-edit-dep' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component
to suppress this message.
To allow any property add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component.
22 [dep]="dep" *ngIf="ActivateAddEditDepComp">
~~~~~~~~~~~
src/app/department/show-dep/show-dep.component.ts:6:16
6 templateUrl: './show-dep.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component ShowDepComponent.
<app-add-edit-dep
[dep]="dep" *ngIf="ActivateAddEditDepComp">
</app-add-edit-dep>
Everything is fine up until I add this line. I'm passing a department object to my add-edit-department component so that it knows whether it needs to add a new department or edit an existing department. I've included everything I worked on involving the department object in question.
show-dep.component.html
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary float-right m-2"
data-bs-toggle="modal" data-bs-target="#exampleModal"
(click)="addClick()"
data-backdrop="static" data-keyboard="false">
Add Department
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{ModalTitle}}</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal" aria-label="Close"
(click)="closeClick()" >
</button>
</div>
<div class="modal-body">
<app-add-edit-dep
[dep]="dep" *ngIf="ActivateAddEditDepComp">
</app-add-edit-dep>
</div>
</div>
</div>
</div>
<table class = "table table-striped">
<thead>
<tr>
<th>DepartmentID</th>
<th>Department Name</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr *ngFor = "let dataItem of DepartmentList">
<td>{{dataItem.DepartmentID}}</td>
<td>{{dataItem.DepartmentName}}</td>
<td>
<button type="button" class = "btn btn-light mr-1">
Edit
</button>
<button type="button" class = "btn btn-light mr-1">
Delete
</button>
</td>
</tr>
</tbody>
</table>
show-dep.component.ts
import { Component, OnInit } from '#angular/core';
import { SharedService } from 'src/app/shared.service';
#Component({
selector: 'app-show-dep',
templateUrl: './show-dep.component.html',
styleUrls: ['./show-dep.component.css']
})
export class ShowDepComponent implements OnInit {
constructor(private service:SharedService) { }
DepartmentList:any=[];
ModalTitle:string | undefined;
ActivateAddEditDepComp:boolean = false;
dep:any;
ngOnInit(): void {
this.refreshDepList();
}
addClick() {
this.dep = {
DepartmentId:0,
DepartmentName:""
}
this.ModalTitle = "Add Department";
this.ActivateAddEditDepComp = true;
}
closeClick() {
this.ActivateAddEditDepComp = false;
this.refreshDepList();
}
refreshDepList(){
this.service.getDepList().subscribe(data=>{
this.DepartmentList=data;
});
}
}
add-edit-dep.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-add-edit-dep',
templateUrl: './add-edit-dep.component.html',
styleUrls: ['./add-edit-dep.component.css']
})
export class AddEditDepComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
Edit: I have added app.module.ts below.
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { DepartmentComponent } from './department/department.component';
import { ShowDepComponent } from './department/show-dep/show-dep.component';
import { AddEditDepComponent } from './department/add-edit-dep/add-edit-dep.component';
import { EmployeeComponent } from './employee/employee.component';
import { ShowEmpComponent } from './employee/show-emp/show-emp.component';
import { AddEditEmpComponent } from './employee/add-edit-emp/add-edit-emp.component';
import { SharedService } from './shared.service';
import {HttpClientModule} from '#angular/common/http';
import {FormsModule,ReactiveFormsModule} from '#angular/forms';
#NgModule({
declarations: [
AppComponent,
DepartmentComponent,
ShowDepComponent,
AddEditDepComponent,
EmployeeComponent,
ShowEmpComponent,
AddEditEmpComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule
],
providers: [SharedService],
bootstrap: [AppComponent]
})
export class AppModule { }
In the add-edit-dep.component.ts
Add #Input() sub: any; above the constructor
[dep] is used to pass data from the parent component to the child component
There is a quick fix to your problem. Just add schemas: [CUSTOM_ELEMENTS_SCHEMA] before your declarations array. Ideally your app should recognize the app-add-edit-dep element since the component is already declared inside declarations array. Indeed with given information this is the only solution I can think of now.

Angular 9 component Interaction

I have two components in my angular project that I need a data in one component to get from the other component.seat-modal is where my data is.following is seat-modal.ts.
import { Component, OnInit } from '#angular/core';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
import {FormBuilder, FormGroup, Validators} from '#angular/forms';
import { SocketService} from '../../_services/socket.service';
#Component({
selector: 'app-seat-modal',
templateUrl: './seat-modal.component.html',
styleUrls: ['./seat-modal.component.less']
})
export class SeatModalComponent implements OnInit {
formRequestSeat: FormGroup;
socket;
public seat;
showModal: boolean;
public screenName: string;
constructor(private socketService: SocketService,
private modalService: NgbModal,
private formBuilder: FormBuilder) { }
ngOnInit(){
this.formRequestSeat = this.formBuilder.group({
seatRequest: ['', Validators.required]
});
}
hide(){
this.modalService.dismissAll();
}
join(seat){
const userToken = localStorage.getItem('userToken');
const tableToken = localStorage.getItem('tableToken');
this.socket = this.socketService.init(userToken);
const displayName = this.formRequestSeat.controls.seatRequest.value;
if (!displayName){
alert('Please enter a display name');
return;
}
this.socket.emit('join', {tableToken, displayName, seat}, (data) => {
// data.forEach((index, value) => {
// // this.seatsFormGroup.controls['seat-' + index].value(value);
// });
console.log(data.screenName);
this.screenName = data.screenName;
});
this.hide();
}
}
Follow is seat-modal.html
<div class="modal" id="{{seat.id}}" [style.display]="showModal ? 'block' : 'none'">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Seat{{seat.id}}</h4>
<button type="button" class="close" data-dismiss="modal" (click)="hide()">×</button>
</div>
<!-- Modal body -->
<div class="modal-body">
<form [formGroup]="formRequestSeat" (submit)="join(seat.id)">
<div class="form-group col-6">
<label for="name">Your Name</label>
<input formControlName="seatRequest" type="text"/>
</div>
<div>
<button type="submit" class="button-request-seat">Request The Seat</button>
</div>
</form>
</div>
</div>
</div>
</div>
<app-play-game [parentData]="screenName"></app-play-game>
Follow is my other component ts
import {Component, Input, OnInit} from '#angular/core';
import {AlertService} from '../../_services/alert.service';
import {SocketService} from '../../_services/socket.service';
import { FormBuilder, FormGroup, FormArray, FormControl,
ValidatorFn}
from '#angular/forms';
import { of } from 'rxjs';
import {NgbModal} from '#ng-bootstrap/ng-bootstrap';
import {SeatModalComponent} from '../../_components/seat-modal/seat-
modal.component';
#Component({
selector: 'app-play-game',
templateUrl: './play-game.component.html',
styleUrls: ['./play-game.component.less']
})
export class PlayGameComponent implements OnInit {
#Input() public parentData;
seatsFormGroup: FormGroup;
seats = [];
showModal: boolean;
public seatModalRef;
private socket;
constructor(private socketService: SocketService,
private formBuilder: FormBuilder,
private modalService: NgbModal) {
this.seatsFormGroup = this.formBuilder.group({
'seat-0': [''],
'seat-1': [''],
'seat-2': [''],
'seat-3': [''],
'seat-4': [''],
'seat-5': [''],
'seat-6': [''],
'seat-7': [''],
'seat-8': [''],
'seat-9': ['']
});
for (let i = 0; i < 10; i++) {
this.seats.push( 'seat-' + i);
}
}
ngOnInit(){
console.log('name=' + this.parentData);
}
sit(seat){
this.seatModalRef = this.modalService.open(SeatModalComponent);
this.seatModalRef.componentInstance.seat = seat;
this.seatModalRef.componentInstance.showModal = true;
}
}
I have tried a console.log(this.parentData) but it is undefined. Please help with codes I'm a begginer in angular.
your seat component should be change from
export class SeatModalComponent implements OnInit {public screenName: 'Sahan';}
to
export class SeatModalComponent implements OnInit {public screenName: string = 'Sahan';}
Currently you have given it Sahan string as a type not a value. Colon (:) is used to give a type where equals(=) is used to assign a value.
Please fix the SeatModalComponent with below.
public screenName: String = 'Sahan';

How do I open my BsModel on page load in Angular 8

I'm trying to open my BsModel on page load on my Angular 8 Project. I have tried lot. But, Couldn't open my model. Here is my code:
HTML:
<ng-template #showPrivacyPop>
<div class="modal-header">
<h4 class="modal-title pull-left">Create Pluck User</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
jhgjhg
</div>
</ng-template>
And my TS File:
import { Component, OnInit, ViewChild, TemplateRef, ElementRef, ViewRef } from '#angular/core';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
#Component({
selector: 'app-filemanager',
templateUrl: './filemanager.component.html'
})
export class FilemanagerComponent implements OnInit {
#ViewChild('showPrivacyPop') public privacyPopup: TemplateRef<any>;
modalRef: BsModalRef;
config = {
animated: true
};
constructor(private modalService: BsModalService) {
}
ngOnInit() {
console.log(this.privacyPopup);
}
openModal(template: TemplateRef<any>) {
console.log(template);
this.modalRef = this.modalService.show(template, this.config);
}
}
I don't know, how do I trigger the HTML to show on page load. Anyone please solve my problem.
You can drop OnInit method. privacyPopup will only be available on AfterViewInit hook. If it still gives you trouble, you can put it inside of a setTimeout with a delay of 0 just to throw it to the end of the line on the event loop queue.
Also, in angular 8, #ViewChild needs an extra argument ({static: boolean}). In Angular 9 it's optional as it defaults to static: false. Basically it tells the runtime to run the query after (static: false) or before (static: true) the first change detection cycle. Usually, you'll want it to be false, unless the query has any dependency that would be resolved only after the change detection runs.
export class FilemanagerComponent implements AfterViewInit {
#ViewChild('showPrivacyPop', {static: false})
public privacyPopup: TemplateRef<any>;
...
ngAfterViewInit() {
this.openModal(this.privacyPopup);
}

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.