How to close modal in angular 6 - angular6

I am trying to close modal from home component.my close button is in home component.If i click close button i want to close modal.If i click close button from home component how to set visible value is false from home component. How can i use service for that? or any other way is there? How do it?
dialog.component.html
<div [#dialog] *ngIf="visible" class="dialog">
<ng-content></ng-content>
<button *ngIf="closable" (click)="close()" aria-label="Close" class="dialog__close-btn">X</button>
<app-home></app-home>
</div>
<div *ngIf="visible" class="overlay" (click)="close()"></div>
home.component.ts:
<button (click)="showDialog = !showDialog" class="btn">Close</button>
Demo: https://stackblitz.com/edit/angular-7zdnwy?file=src%2Fapp%2Fdialog%2Fdialog.component.html

I followed this approach from Angular Documentation and it works ok.
You Parent is Dialog and child is app-home. So emitter is defined in child class like this
export class HomeComponent implements OnInit {
#Output() close = new EventEmitter<boolean>();
...
// <button (click)="onClose()" in html
onClose() {
this.close.emit(true)
}
}
and listen for the event in parent dialog class like this
// html
<app-home (close)="onCloseClick($event)"></app-home>
// Class code
export class DialogComponent implements OnInit {
...
onCloseClick(close: Boolean) {
if(close){
this.close()
}
}
...
}
Hope it helps.

Related

Angular Page becomes white after adding MatDialog code

I was trying to use MatDialog to open a dialog with information in it. I followed a tutorial and in the component, I put a button that would call a "openDialog()" method and in the typescript I added the method along with changing the contructor. After changing the constructor, the page became completely blank, not showing a thing.
Here is the typescript with the changed constructor and method. (This is in the same component as the button in the html)
export class InfoComponent implements OnInit {
constructor(private dialog: MatDialog) {}
openDialog() {
this.dialog.open(BenefitsPopupComponent);
}
ngOnInit(): void {
}
}
Here is the basic button html
<button (click)="openDialog()">test</button>
and here is the component html that it will open
<h2 mat-dialog-title> test </h2>
the typescript on the component that is being opened is empty
I've tried various tutorials and such but keep getting the same results. I believe it has to do with the constructor but im not entirely sure. Thanks for the help!
this is my first time answering a question so I will try my best.
I'm not really sure if you mean that you want the popup to open a seperate component but I would rather do it as follows:
My Appomponent.ts looks like this:
export class AppComponent implements OnInit {
constructor(private dialog: MatDialog) { }
#ViewChild('myDialog', {static: false}) myDialog!: TemplateRef<any>;
openDialog() {
this.dialog.open(this.myDialog);
}
ngOnInit(): void {
}
doSomeAction() {
console.log('log something')
this.dialog.closeAll()
}
}
And then my html code looks like this:
<button (click)="openDialog()">test</button>
<ng-template #myDialog>
<h2 matDialogTitle>Test</h2>
<mat-dialog-content>
<p>Add some text here
</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button matDialogClose>Cancel</button>
<button mat-button (click)="doSomeAction()">Do Something</button>
</mat-dialog-actions>
</ng-template>
This is just the way I would approach it, not sure if this actually helps you or not.

Angular 10. How to navigate to a component's sections via a different component's anchor link tag?

app.component.html
<!--I wish to keep this structure like this, because menu.component has position sticky at top: 0-->
<app-home></app-home>
<app-menu></app-menu>
<app-about></app-about>
<app-projects></app-projects>
<app-contact></app-contact>
<app-footer></app-footer>
menu.component.html
<!--On anchor link click, navigate to corresponding component-->
<nav>
<a>Home</a>
<a>About</a>
<a>Projects</a>
<a>Contact</a>
</nav>
home.component.html, about.component.html, projects.component.html, contact.component.html
<!--Basic structure-->
<section>
<p>component works!</p>
</section>
A Link to the basic structure of the web-site
https://stackblitz.com/edit/angular-ivy-ufce4g
I would have shared a link to the actual web-site(my personal web-site), but i don't know if i am allowed.
One solution would be to create a shared service between you menu component and your app component.
It would work like this:
Dispatch a notification when a navigation item is clicked in you menu component;
Listen for notification in your app component. When a new notification is received, scroll to the corresponding component on your page.
Something like this:
#Injectable({
providedIn: 'root'
})
export class NavigationService {
private _navigation$ = new BehaviorSubject<string>('home');
navigation$ = this._navigation$.asObservable();
constructor() { }
updateNavigation(item) {
this._navigation$.next(item);
}
}
In your menu component, call the updateNavigation method of NavigationService whenever a navigation item is clicked.
#Component({
selector: 'app-menu',
// ...
})
export class MenuComponent {
constructor(private navigationService: NavigationService) {}
// Call this method whenever one of your navigation items is clicked
// in your template.
//
// navigationItem could, for example, be a string/enum corresponding to
// the component that must be scrolled into view
handleNavigationItemClick(navigationItem: string) {
this.navigationService.updateNavigation(navigationItem);
}
}
Finally, in your app component, listen for a navigation item update and scroll to the component.
#Component({
// ...
})
export class AppComponent implements OnInit {
constructor(private navigationService: NavigationService) {}
ngOnInit() {
this.navigationService.navigation$.pipe(
distinctUntilChanged(),
).subscribe(navigationItem => this.scrollIntoView(navigationItem))
}
private scrollIntoView(component) {
// Scrolling logic ...
}
}

Angular 10 scrollTo from parent component to an element in child component html

parent html:
<div>
<button type="button" (click)="scroll(childelementTwo)">TO CHILD</button>
</div>
<div>
<app-child>
</div>
child html:
<div>
<div #childelementOne>
lot of stuff
</div>
<div #childelementTwo>
another lot of stuff
</div>
</div>
if all this html code were in the "same" component.html I would use this function, but not:
scroll(el: HTMLElement) {
el.scrollIntoView();
}
So: How can I scroll to an html element in child component ?
You can use #ViewChildren for this.
List-Item:
#Component({
selector: 'app-list-item',
templateUrl: './list-item.component.html',
styleUrls: ['./list-item.component.css']
})
export class ListItemComponent implements OnInit {
#Input() list;
constructor(private elRef: ElementRef) { }
ngOnInit() {
}
scrollIntoView() {
this.elRef.nativeElement.scrollIntoView();
}
}
List-Component:
#ViewChildren(ListItemComponent) viewChildren!: QueryList<ListItemComponent>;
list = new Array(1000).fill(true)
scrollTo() {
this.viewChildren.toArray()[100].scrollIntoView()
}
HTML:
<button (click)="scrollTo()">scroll to 100</button>
<app-list-item *ngFor="let item of list">
list works!
</app-list-item>
stackblitz: https://stackblitz.com/edit/angular-ivy-6ccaav?file=src%2Fapp%2Fapp.component.html
Mat, your "elements" are in child and you want control in parent. So, first make access to the elements in child using ViewChild
//in your child.component
#ViewChild("childelementOne") childelementOne;
#ViewChild("childelementTwo") childelementTwo;
Then in parent you can do
<div>
<button type="button" (click)="scroll(childComponent.childelementTwo)">
TO CHILD
</button>
</div>
<div>
<!--see that use a template reference variable to the childComponent-->
<app-child #childComponent></app-child>
</div>
scroll(el: ElementRef) {
el.nativeElement.scrollIntoView();
}
See how, in the .html we are using childComponent.childelementTwo. childComponentis the own component app-child, childComponent.childelementTwo is the "variable" that we get in the #ViewChild. By defect is an ElementRef. You get to the HTMLElement using el.nativeElement. Yes, using a template reference we can access to all the public variables and public function of your child.component
I create a stackblitz that is looks like the stackblitz in enno's answer, but see that is complety different
NOTE. You can also use the same referenceVariable in the child.component and use ViewChildren, so you can pass to the function the QueryList and the index

How can we create modal pop-up in angular from scratch

Need to create a modal popup on button click,
is there any way to make it from scratch without adding any extra dependency for it,
with the below method, I am getting the fully functional modal, but have no confidence whether this is a good way in angular or not,
please suggest
HTML
<button class="hl-sort" (click)="openSortingModal()">
Sort
</button>
<div class="modal-container" *ngIf="modalContent">
<h1>i am modal content</h1>
<button (click)="closeModal()">Close</button>
</div>
components.ts
modalContent = false;
openSortingModal(){
this.modalContent = true;
console.log('clicked')
}
closeModal(){
this.modalContent = false;
}
If you don't want to add any extra dependency, I suggest you create a re-usable component using HTML + CSS as follows:
import { Component, OnInit, ViewChild, ElementRef } from '#angular/core';
#Component({
selector: 'app-modal',
template: `
<div #myModal class="container">
<div class="content">
<p>Some content here...</p>
<button (click)="close()">Close</button>
</div>
</div>
`,
styleUrls: ['./modal.component.css']
})
export class ModalComponent {
#ViewChild('myModal', {static: false}) modal: ElementRef;
open() {
this.modal.nativeElement.style.display = 'block';
}
close() {
this.modal.nativeElement.style.display = 'none';
}
}
Then use it in your container:
import { Component, ViewChild } from '#angular/core';
import { ModalComponent } from './modal/modal.component';
#Component({
selector: 'my-app',
template: `
<app-modal #modal></app-modal>
<p>
Open a Pure HTML + CSS with Angular
</p>
<button (click)="openModal()">Open Modal</button>
`,
styleUrls: []
})
export class AppComponent {
#ViewChild('modal', {static: false}) modal: ModalComponent
openModal() {
this.modal.open();
}
}
See a working example here: https://stackblitz.com/edit/angular-modal-html-css
I hope it helps!
If you do not want to reinvent the wheel, you can use this
https://ng-bootstrap.github.io/#/components/modal/examples
well, if you want to "re-invent the wheel", don't forget close the modal when you click outside
improving the Luixaviles's answer, the component modal can be like
<div #myModal class="container" (click)="tryClose()">
<div #content class="content">
<ng-content></ng-content>
</div>
</div>
Well, you see that I make a function "tryClose" if you click on the div "myModal", this function check if we click but we don't click inside "content"
tryClose() {
const clickTarget = event.target as HTMLElement;
if (!(this.content.nativeElement as HTMLElement).contains(clickTarget))
this.close();
}
Using <ng-content> allow us write in app.component some like
<app-modal #modal>
<p>Some content here...</p>
<button (click)="modal.close()">Close</button>
</app-modal>
<p>
Open a Pure HTML + CSS with Angular
</p>
<button (click)="modal.open()">Open Modal</button>
The rest of code in modal component is simple:
export class ModalComponent {
#ViewChild("myModal", { static: false }) modal: ElementRef;
#ViewChild("content", { static: false }) content: ElementRef;
open() {
this.modal.nativeElement.style.display = "block";
}
close() {
this.modal.nativeElement.style.display = "none";
}
}
See the Luixaviles's forked stackblitz
Update a simple stopPropagation makes the thinks easer
<div #myModal class="container" (click)="close()">
<div (click)="$event.stopPropagation()" class="content">
<ng-content></ng-content>
</div>
</div>
Obviously it is a good idea to create your own component rather using a third party. Just make sure, your popup must be a reusable or dynamic popup.

Conditionally toggle class in angular 2

I need to toggle a class "active" on in app-component whenever a button in "app-header" component is clicked.
Here is my app-component.html,
<div class="off-canvas">
<app-header><app-header>
<app-home></app-home>
<app-footer></app-footer>
</div>
app-header.html
<div>
<!--Some code-->
<button></button>
</div>
How can I do this using only angular since the div and button are in 2 different components????please help I am new to angular!!!
You can bind your object to the [ngClass] directive:
<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">
To share data between components, see this answer: https://stackoverflow.com/a/45371025/1791913
You can use EventEmitter.
app-header.html
<div>
<!--Some code-->
<button (click)="emitClick()"></button>
</div>
app-header.ts
#Output() _clickEvent:EventEmitter<any>=new EventEmitter();
constructor(){
}
ngOnInit(){
}
emitClick($event){
this.clickEvent.emit()
}
app-component.html
<div class="off-canvas" [ngClass]="{'someClassName':active}">
<app-header (_clickEvent)="toggleActive($event)"><app-header>
<app-home></app-home>
<app-footer></app-footer>
</div>
app-component.ts
active:boolean=false;
constructor(){
}
ngOnInit(){
}
toggleActive($event){
// Insert click event handling here
}
You should declare active variable in your app-component.ts and initialized it to Boolean. Every click will cause the active to toggle between true and false.
A class named 'someClassName' will be added by the ngClass whenever the 'active' variable it true.
You can create a common service and store a variable as public, example:
#Injectable()
export class DataService{
foo:string;
}
Then use variable in the both components as a shared variable, example:
#Component({...})
export class FooComponent{
constructor(private dataService:DataService){}
foo():void{
console.log(this.dataService.foo);
}
}