Dialog box appear in bottom of page in angular - javascript

I want to show a dialog box in angular to confirm a delete action but the box does not appear and it appends to the end of the page
here is my dialog component ts file:
import { MatDialogRef, MAT_DIALOG_DATA } from '#angular/material/dialog';
export class DeleteBoxComponent implements OnInit {
constructor(private dialogRef: MatDialogRef<DeleteBoxComponent>,
#Inject(MAT_DIALOG_DATA) public data: CBookModel,
private service: BookService) { }
onNoClick(){
this.dialogRef.close();
}
onYesClick(){
this.service.delete(this.data.id).subscribe(response => {
this.dialogRef.close();
})
}
}
Here is html file of dialog component:
<div class="mat-container position-relative">
<h1 mat-dialog-title>DELETE</h1>
<mat-dialog-content class="mat-typography">
<p>Are you Sure you want to delete "{{data.title}}"</p>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button (click)="onNoClick()">No</button>
<button mat-button (click)="onYesClick()">Yes</button>
</mat-dialog-actions>
</div>
And here is another component that calls the dialog component:
import { DeleteBoxComponent } from './../delete-box/delete-box.component';
import { MatDialog } from '#angular/material/dialog';
export class BooksComponent implements OnInit {
constructor(private service: BookService,public router:Router, public dialog: MatDialog) { }
onClickDelete(book: CBookModel) {
const dialogRef = this.dialog.open(DeleteBoxComponent,
{width: '250px',backdropClass: 'backdropBackground', data: book});
dialogRef.afterClosed().subscribe( Response =>{
this.service.getAll()
.subscribe(data => this.books = data);
})
}
}

Based on your screenshot I think you have not configured Material styles.
Follow Getting Started and it will be set up.

Related

How to use same functionalities of function present in one component to another based on click to use same class binding in both components in angular

I'm using class binding to add and remove classes based on click of sidebar button to minimize and maximize the sidebar.
I need same functionality to add and remove class in footer component also to maximize and minimize width of the footer based on click made in sidebar component.
sidebar.component.html
<nav class="sidebar-container" [ngClass]="minimize ? 'minimize' : ''">
<ul>
<li class="sidebar-minimize">
<a (click)="clickEvent()">Minmax</a>
</li>
</ul>
</nav>
sidebar.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.scss']
})
export class SidebarComponent implements OnInit {
minimize: boolean = false;
ngOnInit(): void {
}
clickEvent() {
this.minimize = !this.minimize;
}
}
But i need same actions to be performed in footer component to add another CSS class through class binding followed by same clickEvent() method because in my situation sidebar component and footer components are interdependent on this clickEvent() function
For eg,
<footer (click)="clickEvent()" [ngClass]="minimize ? 'minimize':''">
<p>footer works</p>
</footer>
Is it possible to use same clickEvent() function in footer component for class binding
So in this case you can use a service. For example in your service you have a property like below:
#Injectable({
providedIn: 'root'
})
export class TestService {
private minimize: boolean;
public minimizeSubject: Subject<void>;
constructor() {
this.minimizeSubject = new Subject<void>();
this.minimize = false;
}
set setMinimize(minimize: boolean) {
this.minimize = minimize;
this.minimizeSubject.next();
}
Sidebar component should look like below:
export class SidebarComponent{
public minimize: boolean;
constructor(private testService: TestService) {
this.minimize = false;
}
public onClicked(): void {
this.minimize = !this.minimize;
this.testService.setMinimize = this.minimize;
}
In the end the footer component:
export class FooterComponent implements OnInit, OnDestroy {
private subscription: Subscription;
constructor(private testService: TestService) {
this.subscription = new Subscription();
}
ngOnInit(): void {
this.subscription = this.testService.minimizeSubject.subscribe(minimize => {
this.minimize = minimize;
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}

Render filter component in a dialog

I'm trying render filter(s) in a mat-dialog, I came to a point where it is rendered correctly, but functionally not usable and I'm not sure if this is the right way or not.
here is the code
here is how I create and open the dialog:
public lol(colDef: ColDef): void {
console.log(colDef);
this.gridApi?.getFilterInstance(colDef.field, (foo) => {
console.log(foo.getModel());
foo.setModel(foo.getModel());
this.dialog.open(FilterWrapperDialogComponent, {
data: {
filterHtml: foo.getGui()
},
panelClass: 'ag-custom-component-popup'
}).afterClosed().subscribe((applyOrNot) => {
if (applyOrNot) {
this.gridApi.onFilterChanged();
console.log(foo.getModel());
}
});
})
}
the dialog content:
<mat-dialog-content>
<div class="ag-theme-material ag-custom-component-popup" [innerHTML]="data.filterHtml?.innerHTML | safeUrl: 'html' "></div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button i18n [mat-dialog-close]="true" color="primary">Apply</button>
</mat-dialog-actions>
it renders correctly, but it looses functionality.
My goal is to set a filter without actually adding to the ag-grid table, just through a dialog and ag-grid API.
The problem was that I was using [innerHTML]="data.filterHtml?.innerHTML | safeUrl: 'html' " which strips any functionality for safety reasons ( XSS ).
The solutions was to give an id to the div and append the html from getGui()
Dialog HTML:
<mat-dialog-content>
<div class="ag-theme-material ag-custom-component-popup" id="second"></div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button i18n [mat-dialog-close]="true" color="primary">Apply</button>
</mat-dialog-actions>
Appending HTML to the div; dialog logic:
import { Component, ChangeDetectionStrategy, Inject, AfterViewInit } from '#angular/core';
import { MAT_DIALOG_DATA } from '#angular/material/dialog';
#Component({
selector: 'app-filter-wrapper-dialog',
templateUrl: './filter-wrapper-dialog.component.html',
styleUrls: ['./filter-wrapper-dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class FilterWrapperDialogComponent implements AfterViewInit {
constructor(
#Inject(MAT_DIALOG_DATA) public data: any
) {}
ngAfterViewInit(): void {
document.querySelector('#second').appendChild((this.data.filterHtml as HTMLElement));
}
}
With these changes I was able to render the filter correctly and functionally.

How to make NgbModal draggable with #angular/cdk

I have some difficulties with figuring out how to make my modals draggable. I have reusable modals with its own service which is called to create one inside components.
confirm.modal.service.ts
import { Injectable } from "#angular/core";
import { NgbModal } from "#ng-bootstrap/ng-bootstrap";
import { Observable, from, EMPTY, throwError } from "rxjs";
import { catchError, tap } from "rxjs/operators";
import { ConfirmModalComponent } from "./confirm-modal.component";
export interface ConfirmOptions {
title: string;
subtitle?: string;
errorOnClose?: boolean;
}
#Injectable({ providedIn: "root" })
export class ConfirmModalService {
constructor(private modalService: NgbModal) {}
confirm(options: ConfirmOptions): Observable<boolean> {
const modalRef = this.modalService.open(ConfirmModalComponent, {
centered: true
});
modalRef.componentInstance.title = options.title || "Are you sure?";
modalRef.componentInstance.subtitle = options.subtitle || null;
return from(modalRef.result).pipe(
tap(),
catchError(err =>
options.errorOnClose
? throwError(err || "not confirmed")
: EMPTY
)
);
}
}
confirm.modal.module.ts
import { NgModule } from "#angular/core";
import { CommonModule } from "#angular/common";
import { DragDropModule } from "#angular/cdk/drag-drop";
import { ConfirmModalComponent } from "./confirm-modal.component";
#NgModule({
imports: [
CommonModule,
DragDropModule
],
declarations: [ConfirmModalComponent],
exports: [ConfirmModalComponent]
})
export class ConfirmModalModule {}
confirm.modal.component.ts
import { Component, Input } from "#angular/core";
import { NgbActiveModal } from "#ng-bootstrap/ng-bootstrap";
#Component({
selector: "app-confirm-modal",
templateUrl: "./confirm-modal.component.html",
styleUrls: ["./confirm-modal.component.scss"]
})
export class ConfirmModalComponent {
#Input() title: string;
#Input() subtitle: string;
constructor(public activeModal: NgbActiveModal) {}
public accept(): void {
this.activeModal.close(true);
}
public dismiss(): void {
this.activeModal.close(false);
}
}
confirm.modal.component.html
<div class="modal-body">
<div class="modal-body__header">
<span>{{ title }}</span>
</div>
<div *ngIf="subtitle" class="modal-body__text">
<span>{{ subtitle }}</span>
</div>
<div class="modal-body__button-row">
<button class="btn btn-primary" (click)="accept()">Yes</button>
<button class="btn btn-light" (click)="dismiss()">Cancel</button>
</div>
</div>
So I want to make the whole modal be draggable with Angular built-in DragDropModule, hence I should add cdkDrag inside element with class='modal-content' but I don't how to achieve that with current setup. NgbModalOptions provides functionality to add class only but not attribute directive.
I know that there is easier solution with JQuery draggable, but I would like to avoid that.
I was thinking about using #ViewChildren for each page but it doesn't seem to the best solution for me.
Thanks for any help!
Just wrap your modal inside a container and add the cdkDragRootElement to it as per the documentation. You will also have to add this class as an option when you open the dialog from the component.ts.
<ng-template #content
let-modal>
<div
cdkDrag
cdkDragRootElement=".your-custom-dialog-class">
<div class="modal-header">
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
</div>
</div>
</ng-template>
The code for the component.ts
const options: NgbModalOptions = {
windowClass: 'your-custom-dialog-class'
};
this.modalService.open(this.content, options);

Viewchild undefined with material angular matsidenav

I'm using Material with angular, and I want to toggle the Sidenav from another component, using viewchild, but i get undefined when i try to get the mat-sidenav element. Heres mi code
sidenav.component.html
<mat-sidenav-container class="example-container">
<mat-sidenav #sidenav class="example-sidenav">
Sidenav content goes here!
</mat-sidenav>
<div class="sidenav-container">
123
</div>
</mat-sidenav-container>
sidenav.component.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import {MatSidenav} from '#angular/material/sidenav';
#Component({
selector: 'app-sidemenu',
templateUrl: './sidemenu.component.html',
styleUrls: ['./sidemenu.component.scss']
})
export class SidemenuComponent implements OnInit {
#ViewChild('sidenav') sidenav;
constructor() { }
ngOnInit() {
}
openSideNav(){
console.log(this.sidenav)
this.sidenav.open();
}
}
And this is the component from where i try to toggle the sidenav
header.component.ts
import { Component, OnInit } from '#angular/core';
import { SidemenuComponent } from '../sidemenu/sidemenu.component';
#Component({
providers:[SidemenuComponent],
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
constructor(private sm: SidemenuComponent) { }
ngOnInit() {
}
openSideNav(){
this.sm.openSideNav()
}
}
header.component.html
<mat-toolbar color="primary">
<mat-toolbar-row>
<div class="navbar-brand">
<img class="img-fluid" src="./assets/icons/logo_femsa_blanco.png"/>
</div>
<button class="buton-menu" mat-icon-button (click)="openSideNav()">
<img class="img-fluid menu-icon" src="./assets/icons/icons8-menu-filled-50.png"/>
</button>
<span class="toolbar-spacer"></span>
<div class="font-weight-light text-right user-name">
Hola Mundo!
</div>
</mat-toolbar-row>
</mat-toolbar>
Hope someone can help. I's starting with angular. Sorry for bad english
base on your sample, i have create Service to manage communication between component.
Goal is to have, from anywhere on your code, API to ask menu to open / close / toggle.
Functional step :
1/ From anywhere (button click, custom things), you want to make action on your side-nav. You call public function from your service, exemple : this.menuService.open()
2/ if needed, your service will next new menu state by Observable.
3/ Component who manage your sidenav will subscribe to any change on this state and do "open/close" if needed.
State is manage by Subject and internal service flag
export class MenuService {
private menuIsOpen$ : Subject<boolean>;
private menuIsOpen: boolean = false;
constructor() {
this.menuIsOpen$ = new Subject<boolean>();
}
/**
* If menu is open, let close it
**/
public open() {
if(!this.menuIsOpen) {
this.menuIsOpen = true;
this.menuIsOpen$.next(false);
}
}
/**
* Both silence open and close is use by navbar output, to silence switch internal flag.
**/
public silenceOpen() {
this.menuIsOpen = true;
}
public silenceClose() {
this.menuIsOpen = false;
}
/**
* If menu is close, let open it
**/
public close() {
if(this.menuIsOpen) {
this.menuIsOpen = false;
this.menuIsOpen$.next(false);
}
}
public toggle() {
this.menuIsOpen = !this.menuIsOpen;
this.menuIsOpen$.next(this.menuIsOpen);
}
public asObservable()
{
return this.menuIsOpen$.asObservable();
}
}
then your Component who embed sidenav :
export class SidemenuComponent implements OnInit {
#ViewChild('sidenav') sidenav: MatSidenav;
constructor(private menuService: MenuService)
{
}
ngOnInit() {
/**
When you reveive order to open / close sidenav.
**/
this.menuService.asObservable().subscribe((isOpen: boolean) => {
if(isOpen) {
this.sidenav.close();
}
else{
this.sidenav.open();
}
});
}
onOpenedChange() {
this.menuService.silenceOpen();
}
onClosedChange() {
this.menuService.silenceClose();
}
}
Html side :
Sample : https://stackblitz.com/edit/angular-2faa8z

Angular 5 Dynamic template in MatDialog

in my component I open a MatDialog and pass data to it. In my object data.obj is under this.data.obj.html html-code stored.
In electron I would use a webview to display the html-site.
How do I display the html-code in proper way in my MatDialog in angular 5? Its possible to create the template dynamically or is there any smoother way?
#Component({
selector: 'dialog-popup',
template:`
<h1 mat-dialog-title>Content-HTML</h1>
<mat-dialog-content>
{{this.data.obj.html}}
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button>Complain</button>
<button mat-button (click)=onNoClick()>Cancel</button>
</mat-dialog-actions>
`
})
export class DialogOverview {
constructor(
public dialogRef: MatDialogRef<DialogOverview>,
#Inject(MAT_DIALOG_DATA) public data: any) { }
ngOnInit() {
console.log(this.data.obj.html);
}
onNoClick(): void {
this.dialogRef.close();
}
}
You can bind it to the [innerHtml] property of a html element
<mat-dialog-content>
<div [innerHtml]="data.obj.html | keepHtml"></div>
</mat-dialog-content>
You can use dom sanitizer and write a html pipe like below to escape html sanitizing
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'keepHtml', pure: false })
export class KeepHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(content) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}

Categories

Resources