Uses of the hash symbol (#) in Angular? [duplicate] - html

I am trying to learn angular material 2 and came across this #auto attribute in autocomplete.I understand auto can be replaced with any text, but why there need a # here before auto and what is there any name of this attribute?
<md-input-container>
<input mdInput placeholder="State" [mdAutocomplete]="auto" [formControl]="stateCtrl">
</md-input-container>
<md-autocomplete #auto="mdAutocomplete">
^^^^ what is name of this property
<md-option *ngFor="let state of filteredStates | async" [value]="state">
{{ state }}
</md-option>
</md-autocomplete>

It is a template reference variable that allows us to get reference to html element or something else if we declare directive on this element.
We can declare template reference variable via (1)
#var
ref-var
#Default behavior
In most cases, Angular sets the reference variable's value to the html element on which it was declared (2) .
<div #divElem></div>
<input #inputEl>
<table #tableEl></table>
<form #formEl></form>
In the preceding all template reference variables will refer to the corresponding elements.
#divElem HTMLDivElement
#inputEl HTMLInputElement
#tableEl HTMLTableElement
#formEl HTMLFormElement
#Directives can change default behavior
But a directive can change that behavior and set the value to something else, such as itself.
Angular assigns references with empty value to component (3)
If we have component like:
#Component({
selector: '[comp]',
...
})
export class SomeComponent {}
and template as:
<div comp #someComp></div>
then #someComp variable will refer to component itself (SomeComponent instance).
Angular doesn't locate directives in references with empty value (4)
If we change #Component decorator to #Directive
#Directive({
selector: '[comp]',
...
})
export class SomeDirective {}
then #someComp variable will refer to HTMLDivElement.
How we can get SomeDirective instance in this case?
Fortunately, Template reference variable can have value (5)
#var="exportAsValue"
ref-var="exportAsValue"
We can define exportAs property within #Component/#Directive decorator (6):
exportAs is a name under which the component instance is exported in a
template. Can be given a single name or a comma-delimited list of
names.
#Directive({
selector: '[comp]',
exportAs: 'someDir',
...
})
export class SomeDirective {}
and then use exportAs value as value for template reference variable within template (7):
<div comp #someComp="someDir"></div>
After that #someComp will refer to our directive.
Now let's imagine we have several directives applied to this component. And we want to get specific directive instance.exportAs property is a good choice to solve this problem.
Let's go back to your code
If you open source code of MdAutocomplete component you can see:
#Component({
...
exportAs: 'mdAutocomplete'
})
export class MdAutocomplete {
...
Since in your template you have
#auto="mdAutocomplete"
Then #auto variable will refer to instance of MdAutocomplete component. This reference is used in MdAutocompleteTrigger directive:
#Directive({
selector: 'input[mdAutocomplete], input[matAutocomplete],' +
'textarea[mdAutocomplete], textarea[matAutocomplete]',
...
})
export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
#Input('mdAutocomplete') autocomplete: MdAutocomplete;
because you're passing auto variable to input within template
<input mdInput placeholder="State" [mdAutocomplete]="auto"
We can omit value and use only variable name in this case like
<md-autocomplete #auto>
but
assignment value to value of exportAs property precisely indicates us where to get the instance.
if md-autocomplete is a directive then auto variable will refer to HTMLElement.
So prefer specifying value for template reference variable if you doubt what it will refer to.

Related

How to pass Angular directive by reference?

In an existing component template I have this (simplified) element:
<input type="button" #refreshPrice />
This is picked up (I don't know the correct term) by this property so we can subscribe to it's click event and call a function when the input element is clicked.
I want to replace this input element with a component I've developed, which would make it look (simplified) like this:
<spinner-button #refreshPrice></spinner-button>
This child component has this as its (simplified) template:
<button>
<mat-spinner></mat-spinner>
</button>
So now the button element, in the child component template, needs to have the #refreshPrice hash attribute (?) attached.
To do this, perhaps the spinner-button element should take the name of the hash attribute as an attribute value. Here is the complete spinner component class file:
import { Component, Input, OnInit } from "#angular/core";
#Component({
selector: "spinner-button",
templateUrl: "./spinner-button.component.html",
styleUrls: ["./spinner-button.component.css"]
})
export class SpinnerButtonComponent implements OnInit {
constructor() {}
#Input() targetElement: string;
ngOnInit() {
}
}
In theory, the targetElement property can then be attached to the button element as a hash attribute - but how is this done?
the #Input() attribute here allows you to bind a value to a variable on your component, if you want to have the parent do something based on your components data, you might want to use #Output() and emit a custom event. If the requirement is just listen to a click event then adding a (click)=functionToBeCalled() should help your cause here.
You can refer to the official docs as well:
https://angular.io/guide/inputs-outputs

How do I obtain a HTML Label's runtime value for use in TypeScript (in Angular)?

I have the following label with an i18n (internationalization) element:
<label i18n="##replacingValue">Default value</label>
At runtime, the "Default value" text of this label is replaced with the value given by its i18n element, and I need to obtain that value for usage in my TypeScript code, but how?
I've tried to pass it from the HTML to TypeScript through #Input, as such:
In the .HTML file:
<label i18n-[labelValue]="##replacingValue" i18n="##replacingValue">Default value</label>
In the .TS file:
#Input('labelValue') labelValue: string;
But the variable I tried to store it in remains "undefined". How do I get the correct value if, for example, I want to do this in TypeScript:
console.log(this.labelValue)
You can use ViewChild to manipulate dom elements:
html file:
<label #myLabel i18n="##replacingValue">Default value</label>
ts file:
#ViewChild('myLabel') el: ElementRef;
ngAfterViewInit() {
console.log(this.el.nativeElement);
}
After getting the elements you can iterate the attributes and handle i18n however you want

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.

Two way data binding without ngmodel directive angular

I see in console ngmodel is deprecated and will be removed on angular 7. and i have a directive using it for do a two way databinding, how i can do it wihout [(ngmodel)]?
import {Directive, ElementRef, HostListener} from '#angular/core';
#Directive({
selector: '[onlyFloat]'
})
export class OnlyFloatDirective {
private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g);
private specialKeys: Array<string> = [ 'Backspace', 'Tab', 'End', 'Home', '-' ];
constructor(private el: ElementRef) {
}
#HostListener('keydown', [ '$event' ])
onKeyDown(event: KeyboardEvent) {
if (this.specialKeys.indexOf(event.key) !== -1) {
return;
}
let current: string = this.el.nativeElement.value;
let next: string = current.concat(event.key);
if (next && !String(next).match(this.regex)) {
event.preventDefault();
}
}
}
HTML:
<div class="ui-g-12 ui-md-6">
<label >Valor da Venda</label><br>
<input type="text" pInputText onlyFloat [(ngModel)]="produtoAgilForm.controls['ValorVenda'].value" placeholder="Valor Venda" formControlName="ValorVenda">
</div>
Just for clarity, note that ngModel is only deprecated when used with Reactive forms. That has been the recommendation for a while ... but now it is deprecated in v6 and will be removed in v7.
See this part of the docs for more information: https://angular.io/api/forms/FormControlName
And in case that part of the docs is removed when ngModel is removed:
Support for using the ngModel input property and ngModelChange event
with reactive form directives has been deprecated in Angular v6 and
will be removed in Angular v7.
Now deprecated:
<form [formGroup]="form"> <input
formControlName="first" [(ngModel)]="value"> </form>
this.value = 'some value';
This has been deprecated for a few reasons.
First, developers have found this pattern confusing. It seems like the
actual ngModel directive is being used, but in fact it's an
input/output property named ngModel on the reactive form directive
that simply approximates (some of) its behavior. Specifically, it
allows getting/setting the value and intercepting value events.
However, some of ngModel's other features - like delaying updates
withngModelOptions or exporting the directive - simply don't work,
which has understandably caused some confusion.
Here is the recommended change per the above referenced docs:
To update your code before v7, you'll want to decide whether to stick
with reactive form directives (and get/set values using reactive forms
patterns) or switch over to template-driven directives.
After (choice 1 - use reactive forms):
<form [formGroup]="form">
<input formControlName="first">
</form>
this.form.get('first').setValue('some value');
And to answer your question ... you shouldn't need ngModel here. Your binding should be handled by your use of the formControlName. And to set the value, use the above shown code.
Is your directive not working? If not, could you provide a stackblitz to demonstrate?

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.