Angular 4 load event with #HostListener - javascript

This is what I am trying to do:
import { Directive, HostListener, Input } from '#angular/core';
#Directive({
selector: '[appResizeWindow]'
})
export class ResizeWindowDirective {
#Input('appResizeWindow') line_ChartOptions: {};
constructor() { }
#HostListener('window:resize', ['$event']) onResize(event: Event) {
console.log('Yo');
if (event.target['innerWidth'] < 420)
this.line_ChartOptions['hAxis']['format'] = 'MMM';
else if (event.target['innerWidth'] < 760)
this.line_ChartOptions['hAxis']['format'] = 'MM. yy\'';
else this.line_ChartOptions['hAxis']['format'] = 'MMM d, yyyy';
}
#HostListener('load', ['$event']) onPageLoad(event: Event) {
console.log('loaded');
this.onResize(event.target['innerWidth']);
}
}
So 'window.resize' works perfect when I attack in in the template.
The problem is with load. I event tried onload
I want the page to execute when the page is loaded.
What am I missing here?

The load event has already happened before your component/directive is even initialized.
Just add your code to ngAfterViewInit()
If your component/directive is removed and re-added after it was first initialized, you need to take care yourself that the code isn't executed more than once by using a global service or a static variable to store the status.

try this one, this will work.
#HostListener('window:load',['$event'])
onPageLoad(event: Event) {
console.log('loaded',event);
}

i solved this using OnInit
import { Directive, HostListener, Input, OnInit } from '#angular/core';
inside your component class put this..
ngOnInit() {
// Code to be executed on Init
}

Related

How to use the "window" property in Angular?

I'm trying to implement this "Scroll back to top" button found here:
https://www.w3schools.com/howto/howto_js_scroll_to_top.asp
I'm new to Angular and my attempts to implement this keep getting me errors and type errors.
This is my code:
home.component.html
<div class="country-card-container">
<button (click)="topFunction()" class="scroll-top">TOP</button>
<app-country-card *ngFor="let country of displayCountries" [country]="country" class="country-cards"></app-country-card>
</div>
home.component.ts
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.sass']
})
export class HomeComponent {
mybutton = document.getElementsByClassName("scroll-top");
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = this.scrollFunction();
scrollFunction() {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
this.mybutton.style.display = "block";
} else {
this.mybutton.style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
topFunction() {
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
}
}
I'm getting the errors:
Unexpected keyword or identifier.ts(1434)
Member 'window' implicitly has an 'any' type.ts(7008)
Cannot find name 'scrollFunction'.ts(2304)
Property 'style' does not exist on type 'HTMLCollectionOf<Element>'.ts(2339)
I also tried putting
window.onscroll = this.scrollFunction();
in ngOnInit like this:
ngOnInit(){
window.onscroll = this.scrollFunction();
}
but that doesn't work either.
How do I implement this? What did I do wrong and how do you fix it?
Well, it looks like the problem is that you try to declare a window property of your component by doing this:
export class HomeComponent {
// this code is not valid, because you try to declare a class property here, not to get the window reference
window.onscroll = this.scrollFunction();
}
Angular has a directive made specially for those purposes, called #HostListener. I would recommend you to consider it.
#Component({...})
export class HomeComponent {
#HostListener('window:scroll', ['$event'])
onWindowScroll(event: Event) {
// do whatever you want here, including manipulations with the window object as it's available here
console.log(window);
}
}
Here is a reference to the official docs: https://angular.io/api/core/HostListener
Good luck :)

How to access function from parent component when in modal component?

The refreshTable() function is in the parent component. I need to trigger it whenever I updated information in my modal and closes it.
I am using #ng-bootstrap for my modal
For may parent.component.ts
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
constructor(
private ngbModal: NgbModal,
)
viewModal() {
const openModal = this.ngbModal.open(ModalComponent);
openModal .componentInstance.id = row.id;
}
refreshTable() {
//refresh code block here
}
For my modal.component.ts
import { NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
constructor(
private activeModal: NgbActiveModal,
)
updateParent() {
//update data to database code here
this.activeModal.close();
}
How to trigger refreshTable() from ModalComponent after closing the modal? Since there are changes in the data from database, data from parent is not updated accordingly when modal is closed.
Try to change to this
const openModal = this.ngbModal.open(ModalComponent);
openModal.componentInstance.id = row.id;
openModal.dismissed.subscribe(
_ => {
this.refreshTable();
}
)
in parent.component.ts
Pass it from the parent component to the child component as a prop.
Use bind or an arrow function to preserve the this value.
Add an output event to your modal component
#Output() onCLose: EventEmitter<any> = new EventEmitter();
When the user clicks close just call the emit() method
this.onCLose.emit(value); //value can be whatever you want to pass to the parent
Update your viewModal method in the parent to include a subscription to the close event
viewModal() {
const openModal = this.ngbModal.open(ModalComponent);
openModal.componentInstance.id = row.id;
openModal.componentInstance.onClose.subscribe(value =>
// handle the close event
this.refreshTable();
})
}
You could also do it any other way communication between components can be achieved:
service
state management (ngrx, etc)
ngBootstrap modals have a beforeDismiss event, to which you can add logic before you close the modal. You have to return a truthy value for the modal to actually close.
You could do it like this:
const openModal = this.ngbModal.open(ModalComponent, { beforeDismiss: () => this.updateParent() }); // if modal is not closing, your function is returning false.
Check here for info on that function (do use ctrl F to find the option if needeD)
Edit: #tom-fong's answer is also a good solution, but you'd have to check if you're using version > 8.0.0

Removing full screen event listener in ngOnDestroy

Can't remove fullscreenchange event listener in ngOnDestroy Angular 6
I've tried calling the .removeEventListener() in ngOnDestroy which doesn't remove the events. I have also tried calling the removeEventListeners in a function after a 10 second timeout, and the events still continue to be triggered after.
imports
import { DOCUMENT } from '#angular/common';
import { Component, HostBinding, Inject, OnInit, OnDestroy } from '#angular/core';
Component code
elem: any;
constructor(private framesService: FramesService, private route: ActivatedRoute,
#Inject(DOCUMENT) private document: Document) { }
ngOnInit() {
this.elem = this.document.documentElement;
this.document.addEventListener('fullscreenchange', this.onFullscreenChange.bind(this));
this.document.addEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this));
}
onFullscreenChange(event: Event) {
event.preventDefault();
console.log('Fullscreen event fired');
}
onViewFrame() {
if (this.elem.requestFullscreen) { // Chrome
this.elem.requestFullscreen();
} else if (this.elem.mozRequestFullScreen) { // Firefox
this.elem.mozRequestFullScreen();
}
}
ngOnDestroy() {
this.document.removeEventListener('fullscreenchange', this.onFullscreenChange.bind(this));
this.document.removeEventListener('mozfullscreenchange', this.onFullscreenChange.bind(this));
}
The onViewFrame() function is tied to a click event from a button on the page.
Every time this component is constructed, the events are added, but they are never removed. So if this component is loaded 3 times during a browsing session on the page, it will trigger the console.log three times every time full screen is initiated or the ESC key is used to exit full screen. Would like the events to be removed upon leaving so that they may be re-registered properly the next time.
this.onFullscreenChange.bind(this) creates a new reference to that function. You need to pass the same reference to addEventListener and removeEventListener.
elem: any;
fsEventHandler: any = this.onFullscreenChange.bind(this); // <- Here
ngOnInit() {
this.elem = this.document.documentElement;
this.document.addEventListener('fullscreenchange', this.fsEventHandler);
this.document.addEventListener('mozfullscreenchange', this.fsEventHandler);
}
ngOnDestroy() {
this.document.removeEventListener('fullscreenchange', this.fsEventHandler);
this.document.removeEventListener('mozfullscreenchange', this.fsEventHandler);
}
See MDN for more explanation.
Since you are using Angular you can use RxJS to achieve the same behavior.
You can create Observable using fromEvent
fromEvent(this.document, 'fullscreenchange');
To trigger some function you need to add .pipe() with tap operator, to activate it you also need to subscribe to it. Also save the subscription to be able to unsubscribe inside of ngOnDestroy()
ngOnInit() {
this.elem = this.document.documentElement;
console.log(this.document);
this.fullScreen = fromEvent(this.document, 'fullscreenchange').pipe(
tap(this.onFullscreenChange.bind(this))
).subscribe();
}
onFullscreenChange(event: Event) {
event.preventDefault();
console.log('Fullscreen event fired');
}
ngOnDestroy() {
this.fullScreen.unsubscribe();
}

Attribute Directive with function in Angular4

I have the following attribute directive
import { Directive,HostListener,Input } from '#angular/core';
#Directive({
selector: `[appConfirmaction]`
})
export class ConfirmactionDirective {
#Input() appConfirmaction = () => {};
#Input() confirmMessage = 'Do you want to keep going?';
#HostListener('click', ['$event'])
confirmFirst() {
const confirmed = window.confirm(this.confirmMessage);
if(confirmed) {
this.appConfirmaction();
}
}
}
Then I'm using the above directive attribute in a button, such as
<button md-icon-button [appConfirmaction]="showSimpleMessage" >
The code of the function of the component is:
showSimpleMessage(){
alert("Hello");
}
This code works perfectly.
Now, suppose that I want to add a parameter to the function showSimpleMessage, such as
showSimpleMessage(name:string){
alert("Hello "+name);
}
What are the changes that I have to do to the attribute directive to support the new parameter without using a new #Input for the name parameter?
Also, Is this the proper way to call a function from an attribute directive with Angular4?
Cheers.
Use bind
<button [appConfirmaction]="showSimpleMessage.bind(null, 'Julia')" >
click me
</button>
You wouldn't have to change much. Just put argument to your calling of showSimpleMessage function in directive:
if(confirmed) {
this.appConfirmaction('some name');
}
If this doesn't work correctly you can use call() method on that function. This solution is if you want to call it from directive:
if(confirmed) {
this.appConfirmaction.call(null, 'some name');
}
First argument null is actually context this that you can provide to the function.
'some name' is the parameter of the function.
The other solution is to use bind() as suggested by #Julia

How to use RxJS in angular2?

Is there any way to write a code like that in angular 2?
var closeButton1 = document.querySelector('.close1');
var close1ClickStream = Rx.Observable.fromEvent(closeButton1, 'click');
I have tried many ways to put them in angular 2 component put it does not worked well!
I tried something like this
component.ts
#ViewChild('delete') closeButton1: ElementRef;
close1ClickStream = Observable.fromEvent(closeButton1, 'click');
component.html
<!-- this code is inside *ngFor -->
<li><a #delete [routerLink]="['/update', item.id]">delete</a></li>
The problem is that I can not access the element even if I used AfterContentInit. Moreover, if I could access it, can I use the Observable.fromEvent(...)?
Use directives to handle events
#Directive({
selector: '[click-handler]'
})
export class ClickHandler {
constructor(public elementRef: ElementRef,) {
}
#HostListener('click', ['$event'])
onClick(e) {
// do staff here
}
}
usage
<button click-handler> click </button>
Anyway if you want to do it using Observables you will need
elementRef.nativeElement which is available here , just implement OnInit method and you are good to go.
Yes you can do it :
import { Observable } from 'rxjs/Observable';
//...
#ViewChild('delete') closeButton1: ElementRef;
close1ClickStream = Observable.fromEvent(closeButton1, 'click');

Categories

Resources