(Angular 10 ) Test directive with Jasmine - javascript

I created a directive to detect when I click outside of an element. When it happens I emit a boolean. How can I test this using Jasmine?
import { Directive, ElementRef, HostListener, Output, EventEmitter } from '#angular/core';
#Directive({
selector: '[ocClickOutside]'
})
export class ClickOutsideDirective {
constructor(private elementRef: ElementRef) { }
#Output() public ocClickOutside: EventEmitter<any> = new EventEmitter();
#HostListener('document:click', ['$event.target'])
public onMouseEnter(targetElement: any): void {
const clickedInside = this.elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
this.ocClickOutside.emit(null);
}
}
}

Related

Trigger event on host from directive

I'm trying to automatically close an NG Bootstrap alert after a set period of time. The alert already has the close event which I'm using in the component. I'm adding the additional timeout functionality as a directive which should be able to trigger the close event itself. Something like this?
close-on-timeout.directive.ts
import { Directive, ElementRef, HostBinding, Input, OnInit } from '#angular/core';
#Directive({
selector: '[appCloseOnTimeout]'
})
export class CloseOnTimeoutDirective implements OnInit {
#Input() appCloseOnTimeout: number;
#HostBinding('close') close: CloseEvent;
constructor () {}
ngOnInit () {
setTimeout (() => this.close(), this.appCloseOnTimeout);
}
}
I want to be able to use the directive like this:
<ngb-alert
[dismissible]="alert.dismissible"
[type]="alert.type"
(close)="onClose(i)"
[appCloseOnTimeout]="1000"
>
What's the best way to access the host element's close event? I've tried using an ElementRef instead but still can't find a way to access the events.
Use something like...
import { Directive, ElementRef, HostBinding, Input, OnInit, Output, EventEmitter } from '#angular/core';
#Directive({
selector: '[appCloseOnTimeout]'
})
export class CloseOnTimeoutDirective implements OnInit {
#Input() appCloseOnTimeout: number;
#Output() close:EventEmitter<any> = new EventEmitter();
constructor () {}
ngOnInit () {
setTimeout (() => this.closeWrapp(), this.appCloseOnTimeout);
}
closeWrapp(){
this.close.emit()
}
}
Why not EventEmitter?
import {
Directive,
ElementRef,
HostBinding,
Input,
OnInit,
Output,
EventEmitter
} from '#angular/core';
#Directive({
selector: '[appCloseOnTimeout]'
})
export class CloseOnTimeoutDirective implements OnInit {
#Input() appCloseOnTimeout: number;
#Output() close: EventEmitter = new EventEmitter();
constructor() {}
ngOnInit() {
setTimeout(() => this.onClose(), this.appCloseOnTimeout);
}
onClose() {
console.log('local close');
this.close.emit();
}
}

Angular : Output a callback of my Custom directive event and subscribe to it in my component

Under my Angular app , i ve done a Custom directive:
#Directive({
selector: '[appCustomEdit]'
})
export class CustomEditDirective implements OnChanges {
#Input() appCustomEdit: boolean;
private element: any;
constructor(private el: ElementRef, private renderer: Renderer2) {
this.element = el.nativeElement;
}
ngOnChanges(changes: SimpleChanges) {
if (changes.appCustomEdit.currentValue) {
const btnElement = (<HTMLElement>this.element)
.querySelector('.dx-link-save');
this.renderer.listen(btnElement, 'click', () => {
alert('Buton was clicked')
});
}
}
}
in myComponent.html i m using this directive :
<div>
<input [appCustomEdit]=true></input>
</div>
i need now to implement some event / observable outputed from the directive so that i can subscribe to it in myComponent.ts and make some actions.
I wonder how to do it ?
Suggestions ?
Well, direct answer to your question would be something like the following:
import {Directive, EventEmitter, HostListener, Output} from '#angular/core';
#Directive({
selector: '[appCustomInput]'
})
export class CustomInputDirective {
#Output()
myCustomEvent = new EventEmitter();
#HostListener('click')
onClick() {
this.myCustomEvent.emit();
}
}
And then use it like this:
<div>
<input appCustomInput (myCustomEvent)="onMyCustomEvent()"></input>
</div>
However, it is not clear what are you trying to achieve with this, so I cannot really say if this is the way to go or not.

Angular - communication from child-component to parent

I don't get i, how to communicate between components and services.. :(
I have read and tried a lot about even if some examples somehow work, I do not understand why (?)
what I want to achieve:
I have one parent and two child-components:
dashboard
toolbar
graph
in the toolbar-component I have a searchfield, which gets it's result from a external source (works via service).. when the result arrives, I need to trigger the updateGraph()-Method in the graph-component
toolbar.component.ts
import { Component, OnInit, Output, EventEmitter } from '#angular/core';
import { FormControl } from '#angular/forms';
import { WebsocketsService } from '../../../services/websockets/websockets.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'toolbar',
templateUrl: './toolbar.component.html',
styleUrls: ['./toolbar.component.scss'],
providers: [WebsocketsService, DataService]
})
export class ToolbarComponent implements OnInit {
#Output() newGraphData: EventEmitter<boolean> = new EventEmitter();
searchField: FormControl;
search: string;
private isNewGraph = false;
constructor(private _websocketsService: WebsocketsService, private _dataService: DataService) {
}
ngOnInit() {
this.searchField = new FormControl();
this.searchField.valueChanges
.subscribe(term => {
this.search = term;
});
}
private applySearch() {
const res = this._websocketsService.sendQuery(this.search);
this._dataService.setGraphData(res);
this.newGraphData.emit(true);
this.search = '';
this.searchField.reset();
}
}
graph-component.ts
import { Component, OnInit} from '#angular/core';
import { HttpService } from '../../../services/http/http.service';
import { DataService } from '../../../services/data/data.service';
#Component({
selector: 'graph',
templateUrl: './graph.component.html',
styleUrls: ['./graph.component.scss'],
providers: [HttpService, DataService]
})
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
ngOnInit() {
}
public renderResult() {
console.log( this._dataService.getGraphData() );
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
#Injectable()
export class DataService {
private graphData: Subject<string> = new Subject<string>();
public setGraphData(data) {
this.graphData.next( data );
}
public getGraphData() {
return this.graphData;
}
constructor() { }
}
I simply want ´renderResult()´to be executed after the searchresult has been written to ´graphData´. please help i am confused.
If I understand, you want communication between components and service.
A[component] (make a information) -----(notification)-----> B[service] ----(send)----> C[component] (consume the information)
It's correct? Let's go.
You need create a subscription of graphData(data.service.ts) in GraphComponent.
import { Subscription } from 'rxjs/Subscription';
export class GraphComponent implements OnInit, AfterViewInit {
constructor( private _httpService: HttpService, private _dataService: DataService ) {
}
private subscription: Subscription;
ngOnInit() {
this.subscription = this._dataService.getGraphData().asObservable().subscribe((data) => {
console.log(data);
});
}
}
Look here to help you.
http://jasonwatmore.com/post/2016/12/01/angular-2-communicating-between-components-with-observable-subject
Short answer, I think you need to subscribe to the getGraphData subject, something like this (NOT RECOMMENDED):
public renderResult() {
this._dataService.getGraphData().subscribe(d => {
console.log(d)
});
}
It is not recommended as per the lead of RxJS says: https://medium.com/#benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93
Better answer, create an observable in your service and subscribe to that instead.
data.service.ts
graphObservable = this.graphData.asObservable();
graph-component.ts
public renderResult() {
this._dataService.graphObservable().subscribe(d => {
console.log(d)
});
}

Why is there is no FormArrayDirective in #angular forms?

According to the latest version of angular, the #angular/forms export the following things:
export {FormControlDirective} from './directives/reactive_directives/form_control_directive';
export {FormControlName} from './directives/reactive_directives/form_control_name';
export {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
export {FormArrayName} from './directives/reactive_directives/form_group_name';
export {FormGroupName} from './directives/reactive_directives/form_group_name';
FormContolName and FormControlDirective, FormGroupName and FormGroupDirective, but FormArrayName with no FormArrayDirective, why?
I think that it's unnecessary. Well, you can create the directive, some like
#Directive({
selector: '[formArrayName]'
})
export class FormArrayDirective implements OnInit {
formArray: FormArray;
constructor(
private el: ElementRef,
#Host() #Optional() public form: FormGroupDirective
) {}
ngOnInit() {
this.formArray = this.form
? (this.form.form.get(
this.el.nativeElement.getAttribute('formArrayName')
) as FormArray)
: null;
}
}
Update before in form we has the FormGroupDirective, I think it's better to have the FormGroup
The new Directive
#Directive({
selector: '[formArrayName]'
})
export class FormArrayDirective implements OnInit {
formArray: FormArray;
form:FormGroup;
constructor(
private el: ElementRef,
#Host() #Optional() private formDirective: FormGroupDirective
) {}
ngOnInit() {
this.formArray = this.formDirective
? (this.formDirective.form.get(
this.el.nativeElement.getAttribute('formArrayName')
) as FormArray)
: null;
this.form=this.formDirective?this.formDirective.form:null
}
}
This directive exposes two properties: form and formArray, but be careful, you only can access this properties from a component that has a #ViewChild(FormArrayDirective) in ngAfterViewInit
Curiosity, what is the aim to get it?

In Angular2 With Bootstrap - Tooltip, Tooltip Need setup by executing javascript, How to do it?

Angular2 (2.0.0-rc.4)
I use Bootstrap's Tooltip, Tooltip need execute follow javascript when ready:
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
In Angular2,how to execute it?
That worked for me:
import { Directive, ElementRef, Input, HostListener, OnDestroy } from '#angular/core';
declare var $: any;
#Directive({
selector: '[appTooltip]'
})
export class TooltipDirective implements OnDestroy {
#Input()
public appTooltip: string;
constructor(private elementRef: ElementRef) { }
#HostListener('mouseenter')
public onMouseEnter(): void {
const nativeElement = this.elementRef.nativeElement;
$(nativeElement).tooltip('show');
}
#HostListener('mouseleave')
public onMouseLeave(): void {
const nativeElement = this.elementRef.nativeElement;
$(nativeElement).tooltip('dispose');
}
ngOnDestroy(): void {
const nativeElement = this.elementRef.nativeElement;
$(nativeElement).tooltip('dispose');
}
}
registering:
Importing it in in app.module.ts
Adding it in declarations on #NgModule (file app.module.ts)
And using it like this:
<button title="tooltip tilte" [appTooltip]></button>
<div data-toggle="tooltip" #tooltip></div>
class MyComponent {
#ViewChild('tooltip') tooltip:ElementRef;
ngAfterViewInit() {
this.tooltip.nativeElement.tooltip();
}
}

Categories

Resources