Closing angular material dialog box - javascript

Learning angular2 material. I have the modal finally opening. But issue is when I click out side of modal it closes (not desired result right now) but thats not the current issue. When I click cancel the modal is not closing and throwing error. If I keep the this.dialogRef.close() commented out the app builds but when clicking the close button the modal does not close. If i uncomment that line the application does not build.
Any suggetions or what am I missing for this to work properly?
Thanks
Troy
Here is my componet(s) code:
import { Component, OnInit, Inject } from '#angular/core';
import { IGame } from './game/game';
import { Game } from './models/game.model';
import { GameService } from './services/game-service';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { MdSnackBar } from '#angular/material';
import { MdDialog, MdDialogRef, MD_DIALOG_DATA} from '#angular/material';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
games: any[] = [ ];
selectedRow: Object;
setClickedRow: Function;
myControl: FormControl = new FormControl();
animal: string;
name: string;
girl: string;
options = [
'Football',
'Basketball',
'Baseball',
'Lacrosse',
'Volleyball'
];
filteredOptions: Observable<string[]>;
constructor(private _gameService: GameService,public snackBar: MdSnackBar,
public dialog: MdDialog) {
this.filteredOptions = this.myControl.valueChanges
.startWith(null)
.map(val => val ? this.filter(val) : this.options.slice());
}
filter(val: string): string[] {
return this.options.filter(option =>
option.toLowerCase().indexOf(val.toLowerCase()) === 0);
}
onSelect(game: Game): void {
this.selectedGame = game;
}
openSnackBar(message) {
this.snackBar.open(message,null, {
duration: 2000,
});
}
openDialog(): void {
let dialogRef = this.dialog.open(DialogDataExampleDialog, {
width: '250px',
data: {
animal: this.animal,
girl:this.girl
}
});
dialogRef.afterClosed().subscribe(result => {
this.animal = result;
this.girl = result;
console.log('The dialog was closed: ' + result.animal + ' ' +
result.girl);
});
}
ngOnInit() {
return this._gameService.getGames()
.subscribe(
(gameData) => this.games = gameData,
(error) => this.openSnackBar("Something broke!"),
()=> this.openSnackBar("Data loaded successfully")
);
}
}
#Component({
selector: 'dialog-data-example-dialog',
template: `
<div md-dialog-content>
<p>What's your favorite animal?</p>
<md-form-field>
<input mdInput tabindex="1" [(ngModel)]="data.animal">
</md-form-field>
<p>Whos's your favorite white girl</p>
<md-form-field>
<input mdInput tabindex="2" [(ngModel)]="data.girl">
</md-form-field>
</div>
<div md-dialog-actions>
<button md-button [md-dialog-close]="data" tabindex="2">Ok</button>
<button md-button (click)="onNoClick()" tabindex="-1">No Thanks</button>
</div>
`,
})
export class DialogDataExampleDialog {
constructor(dialogRef: MdDialogRef<DialogDataExampleDialog>,
#Inject(MD_DIALOG_DATA) public data: any) {}
onNoClick(): void {
/*this.dialogRef.close();*/
}
}

Related

ERROR TypeError: Cannot read property 'first_name' of undefined

i get this error When i try to render the list to the view from a backend service,
am able to get the response data and log it to the console but it wont render on the view.
enter code here
import { Component, OnInit, Input } from '#angular/core';
import { StudentsService } from '../services/students.service';
import { Student } from '../interfaces/Student';
#Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
})
export class StudentComponent implements OnInit {
#Input() student: Student;
students: Student[];
constructor(private studentService: StudentsService) {}
ngOnInit() {
this.studentService.getStudents().subscribe((students) => {
(data) => {
this.students = data.json();
Array.of(this.students);
};
console.log(students);
});
}
}
export interface Student {
id: number;
first_name: string;
last_name: string;
date_of_birth: Date;
}
<div class="container mt-5">
<ul *ngFor="let student of students">
<li>{{student.first_name}}</li>
</ul>
</div>
(data) => {
this.students = data.json();
Array.of(this.students);
};
it shouldn't be a function. change it to something like this:
import { Component, OnInit, Input } from '#angular/core';
import { StudentsService } from '../services/students.service';
import { Student } from '../interfaces/Student';
#Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
})
export class StudentComponent implements OnInit {
#Input() student: Student;
students: Student[];
constructor(private studentService: StudentsService) {}
ngOnInit() {
this.studentService.getStudents().subscribe((students) => {
this.students = students; // students is response from server. if it is not Student[] you should map it to correct type.
});
}
}

AngularJS : Custom component won't show up (Toast)

I made a custom Toast component, which is called at each query error by a notification service (called by an http interceptor).
Here is what my custom toast component looks like :
toast.component.html
<div class="wrapper mx-auto shadow-max" *ngIf="toasts.length">
<div [#toast] *ngFor="let toast of toasts" class="mw-100" [ngClass]="getToastClass(toast)" role="alert">
<div class="toast-header">
{{ 'notify.header.' + getToastType(toast) | translate }}
<button
type="button"
class="close"
data-dismiss="alert"
aria-label="Close"
(click)="removeToast(toast)"
>
<i class="icon" aria-hidden="true">close</i>
</button>
</div>
<div class="toast-body">
<p>{{ 'notify.body.' + toast.message | translate }}</p>
<p>{{ toast.detailsMessage }}</p>
</div>
</div>
</div>
toast.component.ts
import { animate, style, transition, trigger } from '#angular/animations';
import { Component, Input, OnInit } from '#angular/core';
import { ToastType } from '../../enums/toast-type.enum';
import { Toast } from '../../model/toast.model';
import { Utils } from '../../utils/utils';
import { ToasterService } from './toaster.service';
#Component({
selector: 'bigdata-toaster',
moduleId: module.id,
templateUrl: './toast.component.html',
//styleUrls: ['./toast.component.scss'],
animations: [
trigger('toast', [
transition('void => *', [style({ transform: 'scale3d(.3, .3, .3)' }), animate(200)]),
transition('* => void', [animate(200, style({ transform: 'scale3d(.0, .0, .0)' }))])
])
]
})
export class ToastComponent implements OnInit {
#Input() id: string;
toasts: Toast[] = [];
constructor(private readonly toastService: ToasterService) {}
ngOnInit() {
this.toastService.getToast(this.id).subscribe((toast: Toast) => {
if (!toast.message) {
// clear alerts when an empty alert is received
this.toasts = [];
return;
}
// add alert to array
this.toasts.push(toast);
setTimeout(() => this.removeToast(toast), 5000);
});
}
removeToast(toast: Toast) {
this.toasts = this.toasts.filter(x => x !== toast);
}
getToastType(toast: Toast) {
return Utils.enumToString(ToastType, toast.type).toLocaleLowerCase();
}
getToastClass(toast: Toast) {
if (!toast) {
return;
}
switch (toast.type) {
case ToastType.Success:
return 'toast toast-success fade show';
case ToastType.Error:
return 'toast toast-danger fade show';
case ToastType.Info:
return 'toast toast-info fade show';
case ToastType.Warning:
return 'toast toast-warning fade show';
}
}
}
toaster.service.ts
import { Injectable } from '#angular/core';
import { NavigationStart, Router } from '#angular/router';
import { Observable, Subject } from 'rxjs';
import { filter } from 'rxjs/operators';
import { ToastType } from '../../enums/toast-type.enum';
import { Toast } from '../../model/toast.model';
#Injectable({
providedIn: 'root'
})
export class ToasterService {
private readonly subject = new Subject<Toast>();
private keepAfterRouteChange = false;
constructor(private readonly router: Router) {
// clear alert messages on route change unless 'keepAfterRouteChange' flag is true
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
if (this.keepAfterRouteChange) {
// only keep for a single route change
this.keepAfterRouteChange = false;
} else {
this.clear();
}
}
});
}
getToast(toastId?: string): Observable<any> {
return this.subject.asObservable().pipe(filter((x: Toast) => x && x.toastId === toastId));
}
success(message: string, detailsMessage?: string) {
this.toast(new Toast({ message, type: ToastType.Success, detailsMessage }));
}
error(message: string, detailsMessage?: string) {
this.toast(new Toast({ message, type: ToastType.Error, detailsMessage }));
}
info(message: string, detailsMessage?: string) {
this.toast(new Toast({ message, type: ToastType.Info, detailsMessage }));
}
warn(message: string, detailsMessage?: string) {
this.toast(new Toast({ message, type: ToastType.Warning, detailsMessage }));
}
toast(toast: Toast) {
this.keepAfterRouteChange = toast.keepAfterRouteChange;
this.subject.next(toast);
}
clear(toastId?: string) {
this.subject.next(new Toast({ toastId }));
}
}
My notification service looks like this :
import {HttpErrorResponse} from '#angular/common/http';
import { Injectable } from '#angular/core';
// import { ActiveToast, IndividualConfig, ToastrService } from 'ngx-toastr';
import { ActiveToast, IndividualConfig } from 'ngx-toastr';
import {ToastComponent} from '../../components/toast/toast.component';
import {ToasterService} from '../../components/toaster/toaster.service';
/**
* Toaster Notification Component
*/
#Injectable()
export class NotificationService {
private readonly DEFAULT_TOASTR_SETTINGS: Partial<IndividualConfig> = {
closeButton: true,
positionClass: 'toast-top-right',
toastComponent: ToastComponent, // custom toast
toastClass: 'toast',
progressBar: true,
tapToDismiss: false,
disableTimeOut: true,
enableHtml: true
};
constructor(private toastrService: ToasterService) {
}
showErrorNotification(err: HttpErrorResponse) {
this.toastrService.success('approve_success');
}
}
I declared my notification service in my app.module.ts :
providers: [
NotificationService,
{
provide: HTTP_INTERCEPTORS, useClass: AppHttpInterceptor, multi: true
}
]
And my HTTP interceptor :
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '#angular/common/http';
import {Injectable} from '#angular/core';
import {ToastrService} from 'ngx-toastr';
import {Observable, of} from 'rxjs';
import {catchError} from 'rxjs/operators';
import {NotificationService} from './shared/services/notifications/notifications.service';
#Injectable()
export class AppHttpInterceptor implements HttpInterceptor {
// constructor(public toastr: ToastrService) {
// }
constructor(public notif: NotificationService) {
}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError((err: any) => {
if (err instanceof HttpErrorResponse) {
// this.notif.showNotification(MESSAGE_TYPE.Error, err.message, err.status.toString(), {disableTimeOut: true});
this.notif.showErrorNotification(err);
}
return of(err);
}));
}
}
My HTTP interceptor is working, I can log something.
But I don't have anything on my UI. Anything in the console too. I've been widely inspired from another code, so I think I get something wrong.
Please what am I doing wrong here ? Thanks.
I had a similar problem using primeng toast sent in ngOnInit won't appear, since the component is not rendered yet.
Tryp to wrap the toast request within a setTimeout call, this helped in my case.
Example:
success(message: string, detailsMessage?: string) {
setTimeout( () => this.toast(new Toast({ message, type: ToastType.Success, detailsMessage }));
}
See https://stackblitz.com/edit/angular-primeng-toast-oninit for details.
The reason for this workaround is explained in Call setTimeout without delay

Call modal from one sibling component to other angular

I have this Angular6 component arquitecture in my app
Main component
<app-navbar></app-navbar>
<app-dashboard></app-dashboard>
Dashboard component
<app-meseros>
</app-meseros>
<app-ultimospedidos></app-ultimospedidos>
<app-modal></app-modal>
I want to call modal from navbar.component, my modal is on dashboard on component modal.component
This is what i have tried
<!--navbar.component.html -->
<a class="nav-link btn btn-primary" (click)="openModal()">Crear pedido</a>
<!--navbar.component.ts -->
import { Component, OnInit } from '#angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
constructor(public bootstrapService: BootstrapService) {}
ngOnInit() {}
openModal() {
this.bootstrapService.toggle();
}
}
I created a service so i can communicate between my navbar.component and modal.component, this is my service
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class BootstrapService {
isOpen: any = false;
constructor() {}
toggle() {
console.log(!this.isOpen);
return (this.isOpen = !this.isOpen);
}
}
Then in modal.component.ts i want to subscribe to these changes so i can launch modal on boolean value change.
import { Component, OnInit } from '#angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
import { NgbModal, ModalDismissReasons } from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
isOpen;
closeResult: string;
modalname: string;
constructor(
public modalService: NgbModal,
public bootstrapService: BootstrapService
) {}
open(content) {
// console.log(this.bootstrapService.popup);
this.modalService
.open(content, { ariaLabelledBy: 'modal-basic-title' })
.result.then(
result => {
this.closeResult = `Closed with: ${result}`;
},
reason => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
}
);
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
ngOnInit() {
this.bootstrapService.toggle().subscribe(isOpen => {
this.isOpen = isOpen;
console.log(isOpen);
});
}
}
Im not even able to subscribe to the change from bootstrapService, i get following error,
RROR in src/app/components/modal/modal.component.ts(41,36): error TS2339: Property 'subscribe' does not exist on type 'boolean'.
if i try to subscribe to value on service like this
this.bootstrapService.isOpen.subscribe(isOpen => {
this.isOpen = isOpen;
console.log(isOpen);
});
i get error on console from browser which says
DashboardComponent.html:1 ERROR TypeError: this.bootstrapService.isOpen.subscribe is not a function
i hope someone can shade some light on this approach, and if this is the best approach to take on this kind of implementations, thanks in advance!
Solved it, i was calling wrong EventEmitter from wrong library, this is updated working code
first i call service from component where i want to call my modal
import { Component, OnInit } from '#angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
constructor(public bootstrapService: BootstrapService) {}
ngOnInit() {}
openModal() {
this.bootstrapService.toggle();
}
}
Then i emit my changes so i can subscribe from modal component
import { Injectable, Output, EventEmitter } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class BootstrapService {
isOpen: any = 'isOpen';
#Output() change: any = new EventEmitter();
constructor() {}
toggle() {
this.change.emit(this.isOpen);
console.log(this.isOpen);
}
}
i reference my template with `#ViewChild('crearpedido') modalInstance;`
and finally subscribe to changes, call modal on subscribe changes.
import { Component, OnInit, ViewChild } from '#angular/core';
import { BootstrapService } from '../../services/bootstrap.service';
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
isOpen;
closeResult: string;
#ViewChild('crearpedido') modalInstance;
constructor(
public modalService: NgbModal,
public bootstrapService: BootstrapService
) {}
ngOnInit() {
this.bootstrapService.change.subscribe(isOpen => {
this.isOpen = isOpen;
console.log(this.isOpen);
this.modalService.open(this.modalInstance);
});
}
}
Here is working repo!!
https://github.com/soyisraelortiz/componentscommunication

How to show heading based on value in angular?

I am trying to change the title based on item._id .i stored item in component.
this is my html
<h1 mat-dialog-title>{{item._id ? "Update" : "Add"}} animal</h1>
below is my dialog-overview-example.ts
import {Component, Inject} from '#angular/core';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '#angular/material';
/**
* #title Dialog Overview
*/
#Component({
selector: 'dialog-overview-example',
templateUrl: 'dialog-overview-example.html',
styleUrls: ['dialog-overview-example.css'],
})
export class DialogOverviewExample {
animal: string;
name: string;
item:string;
constructor(public dialog: MatDialog) {}
openDialog(): void {
item =[{"_id": "2","animal":"lion","weiht":"100"}];
let dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
data: { name: this.name, animal: this.animal,item: this.item }
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed');
this.animal = result;
});
}
}
#Component({
selector: 'dialog-overview-example-dialog',
templateUrl: 'dialog-overview-example-dialog.html',
})
export class DialogOverviewExampleDialog {
constructor(
public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
#Inject(MAT_DIALOG_DATA) public data: any) { }
onNoClick(): void {
this.dialogRef.close();
}
}
Demo
if _id is there in item heading should show update animal otherwise it should show Add animal in our case id already there in item so it should show update animal ..help me out
I could see that you have defined the item inside the component as an array. So you have to use the following code in HTML
<h1 mat-dialog-title>{{item[0]._id ? "Update" : "Add"}} animal</h1>

Angular2 call function from another component

I have two components: NgbdAlertCloseable and AlertCtrl. Also I have AppComponent as parent component. What I want is to click a button in AlertCtrl component and create the alert on NgdbAlertCloseable component.
addSuccess() function adds an alert to the view and it worked well while I call it inside of its component. However, I tried to use an EventEmitter to call this function from another component (as suggested here: https://stackoverflow.com/a/37587862/5291422) but it gives this error:
ORIGINAL EXCEPTION: TypeError: self._NgbdAlertCloseable_2_4.addSuccess is not a function
Here are my files:
ngbd-alert-closeable.component.ts
import { Input, Component } from '#angular/core';
#Component({
selector: 'ngbd-alert-closeable',
templateUrl: './app/alert-closeable.html'
})
export class NgbdAlertCloseable {
#Input()
public alerts: Array<IAlert> = [];
private backup: Array<IAlert>;
private index: number;
constructor() {
this.index = 1;
}
public closeAlert(alert: IAlert) {
const index: number = this.alerts.indexOf(alert);
this.alerts.splice(index, 1);
}
public static addSuccess(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'success',
message: 'This is an success alert',
});
this.index += 1;
}
public addInfo(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'info',
message: 'This is an info alert',
});
this.index += 1;
}
}
interface IAlert {
id: number;
type: string;
message: string;
}
alert-ctrl.component.ts
import { EventEmitter, Output, Component } from '#angular/core';
import { NgbdAlertCloseable } from './ngbd-alert-closeable.component';
#Component({
selector: 'alert-ctrl',
template: '<button class="btn btn-success" (click)="addSuccessMsg()">Add</button>'
})
export class AlertCtrl {
#Output() msgEvent = new EventEmitter();
public addSuccessMsg(){
this.msgEvent.emit(null);
}
}
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '<div class="col-sm-4"><alert-ctrl (msgEvent)="ngbdalertcloseable.addSuccess()"></alert-ctrl><ngbd-alert-closeable #ngbdalertcloseable></ngbd-alert-closeable>'
})
export class AppComponent { }
Am I using it wrong? How can I fix that?
Check that the addSuccess function is static and is using non static properties.
Should be:
public addSuccess(alert: IAlert) {
this.alerts.push({
id: this.index,
type: 'success',
message: 'This is an success alert',
});
this.index += 1;
}
And in your view you must pass the IAlert value in this example we'll send that value when we call msgEvent.emit(IAlert).
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '<div class="col-sm-4"><alert-ctrl (msgEvent)="ngbdalertcloseable.addSuccess($event)"></alert-ctrl><ngbd-alert-closeable #ngbdalertcloseable></ngbd-alert-closeable>'
})
export class AppComponent { }
Then you must send that IAlert, I'll change your AlertCtrl just for demo purpose.
import { EventEmitter, Output, Component } from '#angular/core';
import { NgbdAlertCloseable } from './ngbd-alert-closeable.component';
#Component({
selector: 'alert-ctrl',
template: '<button class="btn btn-success" (click)="addSuccessMsg()">Add</button>'
})
export class AlertCtrl {
currentAlert:IAlert = {id: 0, type: 'success', message: 'This is an success alert'};
#Output() msgEvent = new EventEmitter<IAlert>();
public addSuccessMsg(){
this.msgEvent.emit(this.currentAlert);
}
}
Good luck and happy coding!

Categories

Resources