Angular: Send element from HTML - html

Is there a way to send through HTML the element as an attribute? For example:
In HTML:
<ul>
<li *ngFor="let item of items">
<my-component [ngClass]="{'whatever': checkElement(my-component)}">
</li>
</ul>
In ts file:
checkElement(el): boolean {
// dummy code
const size = el.getBoundingClientRect();
return size.bottom > 100;
}
I know there are several ways to get that element, but this will be used in a huge loop and I would like to prevent searching the element in the DOM (if possible).
Thanks!

You can you a template reference variable to refer to my-component like so:
<my-component [ngClass]="{'whatever': checkElement(myComponentVariableName)}" #myComponentVariableName>
and pass that as an argument to the method checkElement(). Note that here the type of myComponentVariableName will be HTMLInputElement.
Another way to access that from the .ts file would be to use #ViewChild() like so:
#ViewChild('myComponentVariableName') myComponentVariable: ElementRef;`.
Then you can use this.myComponentVariable anywhere inside the component.
If you are worried about having multiple my-components as it is inside an *ngFor, you can convert the #ViewChild statement to make it a list like so:
#ViewChildren(my-component) myComponentList: QueryList<my-component>;
Also, track the *ngFor by index, and send the index along with the template reference variable like so:
<li *ngFor="let item of items; let i=index;">
<my-component [ngClass]="{'whatever': checkElement(myComponentVariableName, i)}" #myComponentVariableName>
</li>
Inside the checkElement() method, access the particular my-component like myComponentList[i].

Sure, very easy :
export class ParentComponent {
this = this;
}
<my-element [parentElement]="this">
now in your second component
#Input('parentElement') parentElement: ParentComponent;

Related

Is there any way to add href link for mat-chips component as property or attribute

I am trying to add a new icon and possibly a href on the mat-chip component but I want it as properties and not to hardcode into that.
So the idea is to have it as a component so I can call it from another component and give data.
For example links, and icons are on the left side and right sides.
Icons on left should be an edit icon and the right will be default remove.
But at the hovering, both of them need to be highlighted.
So let's say if from another component we define the left icon then it will be shown and if not then will be not shown.
Or can it be done within a directive too?
I have till now created like this but I think I need more to do on that.
See stackblitz.
Maybe instead of ngIf is any other way to use it.
But I want for example that in the child component to send the index so then I can use it into href.
But in the child, I cannot use the index so I can iterate through the components and use the href for each of them and I want to use this component for different data.
see components in stack blitz.
users and group components.
1 of them has a variable name and the other one has a username.
https://stackblitz.com/edit/angular-3vp4xw-a9jeot?file=src/app/chips-autocomplete-example.ts
What about somethin like that :
You create a component like 'mat-chip-link':
<mat-chip *ngFor="let fruit of fruits" (removed)="remove(fruit)">
<ng-content select="[.beforeLink]"></ng-content>
<a
[href]="link"
class="mat-standard-chip"
target="_blank"
style="margin: 0; padding: 0"
>My link</a
>
<ng-content select="[.afterLink]"></ng-content>
</mat-chip>
(I am not sure about the ng-content selector, check the doc here for more info. https://angular.io/guide/content-projection).
Which has an input like #Input link: string;
Then from the parent you can call this component like that
<mat-chip-link *ngFor="let fruit of fruits" (removed)="remove(fruit)" [link]="test">
<mat-icon matChipRemove class="beforeLink" *ngIf="editable">cancel</mat-icon>
<mat-icon matChipRemove class="afterLink" *ngIf="removable">cancel</mat-icon>
</mat-chip>
It might be done easier, for example (Typescript):
Template of custom component mat-chip-link
<mat-chip-link (click)="this.clickEventHandler($event)"/>
<mat-chip>
<ng-content>
</ng-content>
</mat-chip>
</mat-chip-link>
Component
private _href: string | null = null;
#Input('href') public set href(value: string | null) {
this._href = value;
}
public clickEventHandler(e: MouseEvent) {
if(this._href !== null) {
window.open(this._href, '_blank');
} else {
console.log('No href specifief');
}
}
Usage
<mat-chip-link [href]="https://www.stackoverflow.com">
Jump to StackOverflow 🙌🏼
</mat-chip-link>

How to pass a function with a parameter to an inner component in Angular

I have a child component that requires data from a parent component in order to call its function. How do I put this in code?
parent.html
<child-component>getDailyForeCast(element.symbol)</child-component>
child.html
<canvas id="canvas"> {{ getDailyForeCast(symbol) }}</canvas>
ChildComponent
getDailyForeCast(symbol){
...}
I think you do not need to pass the function to the child component.
You only want to pass your element.symbol to the child component, you can do this using #Input in your child.
<child-component [symbol]="element.symbol"> </child-component>
In your child component you can define the variable in .ts file:
#Input('symbol') symbol;
and simply use this symbol in your html file using {{symbol}}
You can use the Input decorator to bind a property from another component. Docs: https://angular.io/api/core/Input
Now you can use the symbol in your child component and do whatever with it.
parent.component.html
<child-component [symbol]='element.symbol'></child-component>
child.component.ts
#Input() symbol;
getDailyForeCast(){
// use this.symbol and return some output
...}
child.component.html
<canvas id="canvas"> {{ getDailyForeCast() }}</canvas>
PS: If multiple components are involved, you may consider using a service.

How to check if element exists in an Object?

How to use *ngIf to check if an element exists in an Object?
.ts file
this.data = ["cat", "dog"];
I want to check, in my html file, if cat exists in the object this.data or not. Can I do that with an *ngIf ?
you can create a function in your ts file to check if the wanted string exists in the array or not like this :
doesExist(animal: string): boolean {
return this.data.includes(animal);
}
and then call it in your html file :
<div *ngIf="doesExist('cat')"> [...] </div>
<div *ngIf="data.includes('cat')">hello world</div>
I hope this will help.
You can use ngFor first to iterate every element in a loop and then use ngIf to check if value exist or not.
for example:
<div *ngFor="let element of data">
<div *ngIf="element.cat">
</div>
</div>
Another method is make seperate function for this but I think this is easy way to do.I hope it will help you.:)

Passing data to nested component with ngFor

I have a parent component (ParentComponent) whose html has several child components (ChildComponent). The number of child components displayed depends on the length of an array using an ngFor. I'm trying to figure out how to set a property on each of the child components in the template.
Here is my ParentComponent html:
<div>
<p-panel header="Parent Component Manager">
<p-panel header="ChildComponents">
<childComponent *ngFor="let cComponent of cComponentsArray" [name]="childComponentTitle">
</childComponent>
</p-panel>
</p-panel>
</div>
My ParentComponent.component.ts file contains (I want to stop using this and use string values from cComponentsArray:
childComponentTitle: string = "This text is passed to child."
My ChildComponent html:
<p-accordion [multiple]="true">
<p-accordionTab header="ChildComponent name: {{name}}">
<h4>Random text</h4>
<h4>Random text</h4>
</p-accordionTab>
</p-accordion>
My ChildComponent.component.ts file contains:
#Input() name: string;
With the current code above this will set EACH of the child components "name" property to the same thing. I would like to set it according to a string value contained within cComponent of cComponentsArray.
I've tried using in ParentComponent.html
[name] = {{cComponent.name}}
without any luck. Could someone explain to me what I'm doing wrong and how to properly implement this?
[] and {{}} can never be used together.
Just use
[name]="cComponent.name"

angular2 custom directives inputs syntax

I create a custom directive and set the selector value to be "[unless-directive]".
The directive get a Boolean and use it to change the view as so:
import {Directive, TemplateRef, ViewContainerRef} from 'angular2/core';
#Directive({
selector: '[unless-directive]',
inputs: ['givenBoolean : myDirectiveFunction']
})
export class UnlessDirective {
private _templateRef: TemplateRef;
private _viewContainerRef: ViewContainerRef;
constructor(_templateRef: TemplateRef, _viewContainerRef: ViewContainerRef) {
this._templateRef = _templateRef;
this._viewContainerRef = _viewContainerRef;
}
set myDirectiveFunction(condition: boolean) {
!condition ? this._viewContainerRef.createEmbeddedView(this._templateRef)
: this._viewContainerRef.clear();
}
}
In my template I tried to pass the condition like so:
<div name="customDirective">
<h2>Custom Directive</h2>
<div>
Enter true or false:
<br/>
<input type="text" #condition (keyup)="0"/>
<div *unless-directive [givenBoolean]="condition.value != 'false'">
Only shown if 'false' wad enterded!
</div>
</div>
</div>
When I running the code I get this error:
EXCEPTION: Template parse errors: Can't bind to 'givenBoolean' since
it isn't a known native property (" ... Only shown if 'false' wad enterded!"): StructualDirectivesComponent#47:39
I guess my syntax is wrong, but I can't find where or why?
I looked it up on Angular2 Docs, but the example use the same name for the input and the selector, the thing that I'm trying to avoid.
Can anyone know a better way or can find my syntax problem?
Thanks.
The * prefix syntax is only a syntatic sugar. It expands the directive declaration.
The * prefix syntax is a convenient way to skip the <template> wrapper tags and focus directly on the HTML element to repeat or include. Angular sees the * and expands the HTML into the <template> tags for us.
This is documented in * and <template> and Directive decorator/Lifecycle hooks.
So, in your case, the [givenBoolean] property is not expected to be in the directive. In other words, this:
<div *unless-directive [givenBoolean]="condition.value != 'false'">
Only shown if 'false' wad enterded!
</div>
Becomes, actually:
<template [unless-directive]="">
<div [givenBoolean]="condition.value != 'false'">
Only shown if 'false' wad enterded!
</div>
</template>
And since givenBoolean is not a property in the component (not the directive), the error appears.
So if you want custom behavior, I suggest you experiment using the expanded version and only after it works you go to the * syntax, it will be simpler to reason about.