Change the value of checkbox to string - html

I already saw many questions but I still can't change the value of a checkbox to a string. I need to change the value according to true - false -> 'A' - 'B'. I am using reactive forms in angular.
I got this:
...
..*ngFor="let item of myForm.get('people')['controls'];
...
<mat-checkbox formControlName="check"
[checked]="item.get('check').value === 'A' ? true : false"
(change)="item.get('check').setValue($event.checked ? 'A' : 'B')">
</mat-checkbox>
It has to be in check true if the value that comes is 'A' and in false if it is 'B', I really don't see whydon't set that value on change. I need to send as a string the value of the checkbox

<form [formGroup]="form" (ngSubmit)="submit()">
{{form.value | json}} // just for to see the output
<ng-container formArrayName="people" *ngFor="let item of people.controls; let i = index">
<div [formGroupName]="i">
<mat-checkbox formControlName="check" [checked]="item.get('check').value === 'A' ? true : false"
(change)="setCheck($event.checked, i)">
</mat-checkbox>
</div>
</ng-container>
<button mat-button>submit</button>
</form>
import { FormArray } from '#angular/forms';
import { Component, OnInit } from "#angular/core";
import { FormBuilder, FormGroup } from '#angular/forms';
#Component({
selector: "app-test",
templateUrl: "./test.component.html",
styleUrls: ["./test.component.scss"],
})
export class TestComponent implements OnInit {
form: FormGroup
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.createForm();
}
createForm(){
this.form = this.formBuilder.group({
people: this.formBuilder.array([
this.createItem()
])
})
}
createItem(){
return this.formBuilder.group({
check: ''
})
}
addItem(){
this.people.push(this.createItem());
}
get people(){
return this.form.get("people") as FormArray;
}
setCheck(checked, index){
this.people.controls[index].get("check").setValue(checked ? 'A' : 'B');
}
submit(){
console.log(this.form.value);
}
}
and one more thing, try to use presentation logic in the component class.
style guide: Style 05-17.
link: https://angular.io/guide/styleguide#put-presentation-logic-in-the-component-class

First, if you create many many checkboxes inside a loop, and you set formControlName to a specific one, every checkbox will be bind to 1 control. (You will check and uncheck all of them with the same click.)
On second, you should use formControlName, in formGroup:
<div [formGroup]="myForm">
...
..*ngFor="let item of myForm.get('people')['controls'];"
...
<mat-checkbox formControlName="check"
[checked]="item.get('check').value === 'A' ? true : false"
(change)="item.get('check').setValue($event.checked ? 'A' : 'B')">
</mat-checkbox>
</div>
On Third, I suggest to use brackets in ngFor and '' to look for control name as string.
[formControlName]="'check'"
And finally, I suggest to use mat-checkbox's (change) event, and call a custom function, and do whatever you want on ts side:
<mat-checkbox [formControlName]="'check'" (change)="someFunction(item, $event)"></mat-checkbox>
And in ts:
someFunction(item, event){
...//Do your black magic here
}
By the way: If you use reactive form, and bind a controls to a checkbox, it's value always will be boolean, cuz it's logic... You should decide to map the value later to 'A' or 'B', but you shouldn't use the same time.
And backwards: The checkbox will always work with true or false, width FormControl.
Think about it: You want a Control to control true or false value, but you force 'A' or 'B' in it... It's illogic.
Please re-think your solution.

Related

Not mandatory option selection in Autocomplete Angular Material [duplicate]

I'm trying to implement the autocomplete component from Angular Material:
https://material.angular.io/components/autocomplete/overview
It works well for letting the user select a particular item from the suggested list but I also want to allow the user to add items not in the list.
So lets say the suggested list has the following items:
Cats
Birds
Dogs
And the user starts typing "Do" and the autocomplete shows "Dogs" as the suggested option (because I'm also filtering the list based on what they type). But then the user continues typing "Dolls" and now nothing is displayed in the autocomplete suggestions. Then the user hits enter and it gets added to the list.
Current behavior is that if what the user typed doesn't exist in the list then they are unable to add the item.
If you add an enter key listener to the input field, you can process the entered value and add it to the options if it doesn't exist. You can also dynamically add whatever the user enters to the list of filtered options as an "add new item" option, or add an "add" icon to the field (e.g. as a matSuffix). Or you can do all three:
Stackblitz
HTML
<form class="example-form">
<mat-form-field class="example-full-width">
<input matInput placeholder="Item" aria-label="Item" [matAutocomplete]="auto" [formControl]="itemCtrl" (keyup.enter)="addOption()">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelected($event.option)">
<mat-option *ngFor="let item of filteredItems | async" [value]="item">
<span>{{ item }}</span>
</mat-option>
</mat-autocomplete>
<button *ngIf="showAddButton && itemCtrl.value" matSuffix mat-button mat-icon-button (click)="addOption()"><mat-icon matTooltip='Add "{{itemCtrl.value}}"'>add</mat-icon></button>
</mat-form-field>
</form>
TS
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { startWith } from 'rxjs/operators/startWith';
import { map } from 'rxjs/operators/map';
/**
* #title Autocomplete with add new item option
*/
#Component({
selector: 'autocomplete-overview-example',
templateUrl: 'autocomplete-overview-example.html',
styleUrls: ['autocomplete-overview-example.css']
})
export class AutocompleteOverviewExample {
itemCtrl: FormControl;
filteredItems: Observable<any[]>;
showAddButton: boolean = false;
prompt = 'Press <enter> to add "';
items: string[] = [
'Cats',
'Birds',
'Dogs'
];
constructor() {
this.itemCtrl = new FormControl();
this.filteredItems = this.itemCtrl.valueChanges
.pipe(
startWith(''),
map(item => item ? this.filterItems(item) : this.items.slice())
);
}
filterItems(name: string) {
let results = this.items.filter(item =>
item.toLowerCase().indexOf(name.toLowerCase()) === 0);
this.showAddButton = results.length === 0;
if (this.showAddButton) {
results = [this.prompt + name + '"'];
}
return results;
}
optionSelected(option) {
if (option.value.indexOf(this.prompt) === 0) {
this.addOption();
}
}
addOption() {
let option = this.removePromptFromOption(this.itemCtrl.value);
if (!this.items.some(entry => entry === option)) {
const index = this.items.push(option) - 1;
this.itemCtrl.setValue(this.items[index]);
}
}
removePromptFromOption(option) {
if (option.startsWith(this.prompt)) {
option = option.substring(this.prompt.length, option.length -1);
}
return option;
}
}
It's weird that the user can add an item in the suggested list. The list is suggested to the user by someone who knows what to suggest. But anyway...
The user can type anything in the field and ignore the suggestions. By ignoring the suggested Dogs and typing Dolls, user can press an "Add" button which will add whatever is typed in (Dolls) to the options array.
For example, you can do it by listening to the submit event on the form:
(ngSubmit)="options.push(myControl.value); myControl.reset()"
Here's the complete demo as well.

How do you set the value of a select-options value now that ngModel is deprecated

Now that ngModel is deprecated in Angular, how do you set the value of the select-options on entering a page.
I'm using a reusable form:
constructor(public formBuilder: FormBuilder) {
this.createProfileForm = this.formBuilder.group({
gender: new FormControl('', [Validators.required]),
})
}
ngOnInit() {
this.createProfileForm.patchValue({
gender: 'Man'
})
console.log('form', this.createProfileForm.value);
}
<form [formGroup]="createProfileForm">
<ion-card>
<ion-select formControlName="gender" placeholder="*Gender">
<ion-select-option data-cy="gender-dropdown" *ngFor="let genOption of genderOptions"> {{genOption}}</ion-select-option>
</ion-select>
<ion-button class="submit" expand="full" (click)="addProfile()" [disabled]="!createProfileForm.valid">Submit</ion-button>
</form>
I can't use ngModel so I'm trying to patch the value but that value doesn't appear on the selection even though I can see the patch value in the console.log
{bio: '', gender: 'Man', education: '', smoking: '', drinking: '', …}
bio: ""
dateOfBirth: ""
drinking: ""
education: ""
gender: "Man"
smoking: ""
So I can customize the options I have the select options as an input on the form component:
#Input('genderOptions') genderOptions: string[];
On the page that actually uses the form I'm sending in the genderOptions in the following:
genderOptions: string[] = ['Woman', 'Man', 'Transgender Woman', 'Transgender Man', 'Non-binary'];
<app-profile-form [genderOptions]="genderOptions" (profile)="onSubmit($event)"></app-profile-form>
So when I load the profile page I need to set the value of the gender.
This is one attempt to resolve the issue to no avail:
<ion-select formControlName="gender" placeholder="*Gender" (change)="valueChanging($event)" [value]='{{Opt}}'>
<ion-select-option data-cy="gender-dropdown" *ngFor="let genOption of genderOptions"> {{genOption}}</ion-select-option>
</ion-select>
How exactly do you set the value without using ngModel?
You can set the value of a select element with the help of reactiveforms in Angular.
Below is my attempt to illustrate the following :
How to retrieve the selected value via 'Event Change' and 'Reactive Forms'
How to set the value of a dropdown using 'Reactive Forms' in Angular.
app.component.html
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<form [formGroup]="exampleFormGroup" (ngSubmit)="onSubmit(exampleFormGroup)">
<select formControlName="exampleSelect" (change)="onChange($event)">
<option *ngFor="let item of itemList" [value]="item">{{item}}
</option>
</select>
<p>{{selectedValue}}</p>
<button type="submit">Submit</button>
</form>
app.component.ts
import { Component, VERSION } from '#angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
exampleFormGroup: FormGroup;
selectedValue: any = '';
constructor(public formBuilder: FormBuilder) {
this.exampleFormGroup = this.formBuilder.group({
exampleSelect: new FormControl('', [Validators.required]),
})
}
onChange(event:any){
console.log(event.target.value);
}
itemList=["item1","item2","item3","item4"];
onSubmit(formData){
console.log('Form has been submitted!');
//get the selected value
console.info(this.exampleFormGroup.controls['exampleSelect'].value);
//set the value
this.exampleFormGroup.controls['exampleSelect'].setValue('item4');
}
}
For getting the selected value on 'Event change of a drop down' ,
please refer 'onChange()' method.
To get and set the value of a dropdown via reactive form please refer 'onSubmit()' method.
Let me know if this will help by providing your feedback, so that others will get benefitted as well.
I have created a sample project which can be accessed from here!

how to disable dropdown selection?

I have a dropdown with 2 options:
I want the user to be able to see both options (Cips, Projects); however, I do not want to allow the user to choose a different item.
How do we allow the user to click on the dropdown and see all the options, but disable choosing any other option?
This dropdown is defined like so:
<p-dropdown [(ngModel)]="editRagColumns.BaseObjectType"
name="RagBasicType"
type="text"
class="form-control"
id="RagBasicType"
[options]="baseObjectTypes"
optionLabel="BaseObjectTypeName"
[style]="{'width':'100%', 'border-color':'transparent'}"
>
</p-dropdown>
As per the documentation:
https://www.primefaces.org/primeng/showcase/#/dropdown
You can use this optionDisabled
You have to add the following property to your "p-dropdown" component.
optionDisabled="BaseObjectTypeName"
This is my ts and html file that I have done to confirm that it works.
ts file
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-question1',
templateUrl: './question1.component.html',
styleUrls: ['./question1.component.sass']
})
export class Question1Component implements OnInit {
BaseObjectTypeName: string = "BaseObjectTypeName";
baseObjectTypes: any[] = [
{ BaseObjectTypeName: "tab1" },
{ BaseObjectTypeName: "tab2" },
];
constructor() { }
ngOnInit(): void {
}
}
html file
<p-dropdown
name="RagBasicType"
type="text"
class="form-control"
id="RagBasicType"
[options]="baseObjectTypes"
optionLabel="BaseObjectTypeName"
[style]="{'width':'100%', 'border-color':'transparent'}"
optionDisabled="BaseObjectTypeName"
>
</p-dropdown>
I hope I've helped you.
If you are using primeng 11.0.0 and onwards, then optionDisabled property is the way to go, as others have already mentioned.
In case if you are using previous versions, then you have to ensure following points:
The value passed to options must be of SelectItem[ ] type or at least have label, value and disabled properties from SelectItem type.
label would be the dropdown option text
value can be of any type i.e an object or simply a string
disabled would be of boolean type, setting it to true will disable the dropdown option
p-dropdown optionLabel should not be used
In your case baseObjectTypes should be something as below:
baseObjectTypes = [
{ label: 'Projects', value: 'Projects', disabled: true }, // <--- value can be object too
{ label: 'Cips', value: 'Cips', disabled: true
]

Angular 2+: Input decorator not reflecting checkbox

I have a component
timeBoxSelector
HTML:
<input type="checkbox" [(ngModel)]="selected">
TS:
#Component({
...
})
export class TimeboxComponent implements OnInit {
#Input() selected: boolean;
constructor() {}
ngOnInit() {
console.log('Selected: ', this.selected);
}
}
Now, when I create
<app-timebox selected="false"><app-timebox/>
<app-timebox selected="true"><app-timebox/>
In both cases, the checkbox initially appears as selected. Why is this the case, and how can I fix it?
In both cases, you are binding non empty strings, which are truthy values. Use the brackets notation to tell Angular that the bound value is to be evaluated as a Javascript expression:
<app-timebox [selected]="false"><app-timebox/>
<app-timebox [selected]="true"><app-timebox/>

How to declare a variable in a template in Angular

I have the following template :
<div>
<span>{{aVariable}}</span>
</div>
and would like to end up with :
<div "let a = aVariable">
<span>{{a}}</span>
</div>
Is there a way to do it ?
Update
We can just create directive like *ngIf and call it *ngVar
ng-var.directive.ts
#Directive({
selector: '[ngVar]',
})
export class VarDirective {
#Input()
set ngVar(context: unknown) {
this.context.$implicit = this.context.ngVar = context;
if (!this.hasView) {
this.vcRef.createEmbeddedView(this.templateRef, this.context);
this.hasView = true;
}
}
private context: {
$implicit: unknown;
ngVar: unknown;
} = {
$implicit: null,
ngVar: null,
};
private hasView: boolean = false;
constructor(
private templateRef: TemplateRef<any>,
private vcRef: ViewContainerRef
) {}
}
with this *ngVar directive we can use the following
<div *ngVar="false as variable">
<span>{{variable | json}}</span>
</div>
or
<div *ngVar="false; let variable">
<span>{{variable | json}}</span>
</div>
or
<div *ngVar="45 as variable">
<span>{{variable | json}}</span>
</div>
or
<div *ngVar="{ x: 4 } as variable">
<span>{{variable | json}}</span>
</div>
Plunker Example Angular4 ngVar
See also
Where does Angular 4 define "as local-var" behavior for *ngIf?
Original answer
Angular v4
div + ngIf + let
{{variable.a}}
{{variable.b}}
div + ngIf + as
view
<div *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
<span>{{variable.a}}</span>
<span>{{variable.b}}</span>
<span>{{variable.c}}</span>
</div>
component.ts
export class AppComponent {
x = 5;
}
If you don't want to create wrapper like div you can use ng-container
view
<ng-container *ngIf="{ a: 1, b: 2, c: 3 + x } as variable">
<span>{{variable.a}}</span>
<span>{{variable.b}}</span>
<span>{{variable.c}}</span>
</ng-container>
As #Keith mentioned in comments
this will work in most cases but it is not a general solution since it
relies on variable being truthy
See update for another approach.
You can declare variables in html code by using a template element in Angular 2 or ng-template in Angular 4+.
Templates have a context object whose properties can be assigned to variables using let binding syntax. Note that you must specify an outlet for the template, but it can be a reference to itself.
<ng-template #selfie [ngTemplateOutlet]="selfie"
let-a="aVariable" [ngTemplateOutletContext]="{ aVariable: 123 }">
<div>
<span>{{a}}</span>
</div>
</ng-template>
<!-- Output
<div>
<span>123</span>
</div>
-->
You can reduce the amount of code by using the $implicit property of the context object instead of a custom property.
<ng-template #t [ngTemplateOutlet]="t"
let-a [ngTemplateOutletContext]="{ $implicit: 123 }">
<div>
<span>{{a}}</span>
</div>
</ng-template>
The context object can be a literal object or any other binding expression. Other valid examples:
<!-- Use arbitrary binding expressions -->
<ng-template let-sum [ngTemplateOutletContext]="{ $implicit: 1 + 1 }">
<!-- Use pipes -->
<ng-template let-formatPi [ngTemplateOutletContext]="{ $implicit: 3.141592 | number:'3.1-5' }">
<!-- Use the result of a public method of your component -->
<ng-template let-root [ngTemplateOutletContext]="{ $implicit: sqrt(2116) }">
<!--
You can create an alias for a public property of your component:
anotherVariable: number = 123;
-->
<ng-template let-aliased [ngTemplateOutletContext]="{ $implicit: anotherVariable }">
<!--
The entire context object can be bound from a public property:
ctx: { first: number, second: string } = { first: 123, second: "etc" }
-->
<ng-template let-a="first" let-b="second" [ngTemplateOutletContext]="ctx">
Ugly, but:
<div *ngFor="let a of [aVariable]">
<span>{{a}}</span>
</div>
When used with async pipe:
<div *ngFor="let a of [aVariable | async]">
<span>{{a.prop1}}</span>
<span>{{a.prop2}}</span>
</div>
update 3
Issue https://github.com/angular/angular/issues/2451 is fixed in Angular 4.0.0
See also
https://github.com/angular/angular/pull/13297
https://github.com/angular/angular/commit/b4db73d
https://github.com/angular/angular/issues/13061
update 2
This isn't supported.
There are template variables but it's not supported to assign arbitrary values. They can only be used to refer to the elements they are applied to, exported names of directives or components and scope variables for structural directives like ngFor,
See also https://github.com/angular/angular/issues/2451
Update 1
#Directive({
selector: '[var]',
exportAs: 'var'
})
class VarDirective {
#Input() var:any;
}
and initialize it like
<div #aVariable="var" var="abc"></div>
or
<div #aVariable="var" [var]="'abc'"></div>
and use the variable like
<div>{{aVariable.var}}</div>
(not tested)
#aVariable creates a reference to the VarDirective (exportAs: 'var')
var="abc" instantiates the VarDirective and passes the string value "abc" to it's value input.
aVariable.var reads the value assigned to the var directives var input.
I would suggest this: https://medium.com/#AustinMatherne/angular-let-directive-a168d4248138
This directive allow you to write something like:
<div *ngLet="'myVal' as myVar">
<span> {{ myVar }} </span>
</div>
Here is a directive I wrote that expands on the use of the exportAs decorator parameter, and allows you to use a dictionary as a local variable.
import { Directive, Input } from "#angular/core";
#Directive({
selector:"[localVariables]",
exportAs:"localVariables"
})
export class LocalVariables {
#Input("localVariables") set localVariables( struct: any ) {
if ( typeof struct === "object" ) {
for( var variableName in struct ) {
this[variableName] = struct[variableName];
}
}
}
constructor( ) {
}
}
You can use it as follows in a template:
<div #local="localVariables" [localVariables]="{a: 1, b: 2, c: 3+2}">
<span>a = {{local.a}}</span>
<span>b = {{local.b}}</span>
<span>c = {{local.c}}</span>
</div>
Of course #local can be any valid local variable name.
In case if you want to get the response of a function and set it into a variable, you can use it like the following in the template, using ng-container to avoid modifying the template.
<ng-container *ngIf="methodName(parameters) as respObject">
{{respObject.name}}
</ng-container>
And the method in the component can be something like
methodName(parameters: any): any {
return {name: 'Test name'};
}
If you need autocomplete support from within in your templates from the Angular Language Service:
Synchronous:
myVar = { hello: '' };
<ng-container *ngIf="myVar; let var;">
{{var.hello}}
</ng-container>
Using async pipe:
myVar$ = of({ hello: '' });
<ng-container *ngIf="myVar$ | async; let var;">
{{var.hello}}
</ng-container>
A simple solution that worked for my requirement is:
<ng-container *ngIf="lineItem.productType as variable">
{{variable}}
</ng-container>
OR
<ng-container *ngIf="'ANY VALUE' as variable">
{{variable}}
</ng-container>
I am using Angular version: 12. It seems it may work with other version as well.
I liked the approach of creating a directive to do this (good call #yurzui).
I ended up finding a Medium article Angular "let" Directive which explains this problem nicely and proposes a custom let directive which ended up working great for my use case with minimal code changes.
Here's the gist (at the time of posting) with my modifications:
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core'
interface LetContext <T> {
appLet: T | null
}
#Directive({
selector: '[appLet]',
})
export class LetDirective <T> {
private _context: LetContext <T> = { appLet: null }
constructor(_viewContainer: ViewContainerRef, _templateRef: TemplateRef <LetContext <T> >) {
_viewContainer.createEmbeddedView(_templateRef, this._context)
}
#Input()
set appLet(value: T) {
this._context.appLet = value
}
}
My main changes were:
changing the prefix from 'ng' to 'app' (you should use whatever your app's custom prefix is)
changing appLet: T to appLet: T | null
Not sure why the Angular team hasn't just made an official ngLet directive but whatevs.
Original source code credit goes to #AustinMatherne
For those who decided to use a structural directive as a replacement of *ngIf, keep in mind that the directive context isn't type checked by default. To create a type safe directive ngTemplateContextGuard property should be added, see Typing the directive's context. For example:
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core';
#Directive({
// don't use 'ng' prefix since it's reserved for Angular
selector: '[appVar]',
})
export class VarDirective<T = unknown> {
// https://angular.io/guide/structural-directives#typing-the-directives-context
static ngTemplateContextGuard<T>(dir: VarDirective<T>, ctx: any): ctx is Context<T> {
return true;
}
private context?: Context<T>;
constructor(
private vcRef: ViewContainerRef,
private templateRef: TemplateRef<Context<T>>
) {}
#Input()
set appVar(value: T) {
if (this.context) {
this.context.appVar = value;
} else {
this.context = { appVar: value };
this.vcRef.createEmbeddedView(this.templateRef, this.context);
}
}
}
interface Context<T> {
appVar: T;
}
The directive can be used just like *ngIf, except that it can store false values:
<ng-container *appVar="false as value">{{value}}</ng-container>
<!-- error: User doesn't have `nam` property-->
<ng-container *appVar="user as user">{{user.nam}}</ng-container>
<ng-container *appVar="user$ | async as user">{{user.name}}</ng-container>
The only drawback compared to *ngIf is that Angular Language Service cannot figure out the variable type so there is no code completion in templates. I hope it will be fixed soon.
With Angular 12 :
<div *ngIf="error$ | async as error">
<span class="text-warn">{{error.message}}</span>
</div>
I am using angular 6x and I've ended up by using below snippet.
I've a scenerio where I've to find user from a task object. it contains array of users but I've to pick assigned user.
<ng-container *ngTemplateOutlet="memberTemplate; context:{o: getAssignee(task) }">
</ng-container>
<ng-template #memberTemplate let-user="o">
<ng-container *ngIf="user">
<div class="d-flex flex-row-reverse">
<span class="image-block">
<ngx-avatar placement="left" ngbTooltip="{{user.firstName}} {{user.lastName}}" class="task-assigned" value="28%" [src]="user.googleId" size="32"></ngx-avatar>
</span>
</div>
</ng-container>
</ng-template>
I was trying to do something similar and it looks like this has been fixed in newer versions of angular.
<div *ngIf="things.car; let car">
Nice {{ car }}!
</div>
<!-- Nice Honda! -->
Short answer which help to someone
Template Reference variable often reference to DOM element within a
template.
Also reference to angular or web component and directive.
That means you can easily access the varible anywhere in a template
Declare reference variable using hash symbol(#)
Can able to pass a variable as a parameter on an event
show(lastName: HTMLInputElement){
this.fullName = this.nameInputRef.nativeElement.value + ' ' + lastName.value;
this.ctx.fullName = this.fullName;
}
*However, you can use ViewChild decorator to reference it inside your component.
import {ViewChild, ElementRef} from '#angular/core';
Reference firstNameInput variable inside Component
#ViewChild('firstNameInput') nameInputRef: ElementRef;
After that, you can use this.nameInputRef anywhere inside your Component.
Working with ng-template
In the case of ng-template, it is a little bit different because each template has its own set of input variables.
https://stackblitz.com/edit/angular-2-template-reference-variable
I'm the author of https://www.npmjs.com/package/ng-let
Structural directive for sharing data as local variable into html component template.
Source code:
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core';
interface NgLetContext<T> {
ngLet: T;
$implicit: T;
}
#Directive({
// tslint:disable-next-line: directive-selector
selector: '[ngLet]'
})
export class NgLetDirective<T> {
private context: NgLetContext<T | null> = { ngLet: null, $implicit: null };
private hasView: boolean = false;
// eslint-disable-next-line no-unused-vars
constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<NgLetContext<T>>) { }
#Input()
set ngLet(value: T) {
this.context.$implicit = this.context.ngLet = value;
if (!this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef, this.context);
this.hasView = true;
}
}
/** #internal */
public static ngLetUseIfTypeGuard: void;
/**
* Assert the correct type of the expression bound to the `NgLet` input within the template.
*
* The presence of this static field is a signal to the Ivy template type check compiler that
* when the `NgLet` structural directive renders its template, the type of the expression bound
* to `NgLet` should be narrowed in some way. For `NgLet`, the binding expression itself is used to
* narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgLet`.
*/
static ngTemplateGuard_ngLet: 'binding';
/**
* Asserts the correct type of the context for the template that `NgLet` will render.
*
* The presence of this method is a signal to the Ivy template type-check compiler that the
* `NgLet` structural directive renders its template with a specific context type.
*/
static ngTemplateContextGuard<T>(dir: NgLetDirective<T>, ctx: any): ctx is NgLetContext<Exclude<T, false | 0 | '' | null | undefined>> {
return true;
}
}
Usage:
import { Component } from '#angular/core';
import { defer, Observable, timer } from 'rxjs';
#Component({
selector: 'app-root',
template: `
<ng-container *ngLet="timer$ | async as time"> <!-- single subscription -->
<div>
1: {{ time }}
</div>
<div>
2: {{ time }}
</div>
</ng-container>
`,
})
export class AppComponent {
timer$: Observable<number> = defer(() => timer(3000, 1000));
}
Try like this
<ng-container
[ngTemplateOutlet]="foo"
[ngTemplateOutletContext]="{ test: 'Test' }"
></ng-container>
<ng-template #foo let-test="test">
<div>{{ test }}</div>
</ng-template>
original answer by #yurzui won't work startring from Angular 9 due to - strange problem migrating angular 8 app to 9.
However, you can still benefit from ngVar directive by having it and using it like
<ng-template [ngVar]="variable">
your code
</ng-template>
although it could result in IDE warning: "variable is not defined"
It is much simpler, no need for anything additional. In my example I declare variable "open" and then use it.
<mat-accordion class="accord-align" #open>
<mat-expansion-panel hideToggle="true" (opened)="open.value=true" (closed)="open.value=false">
<mat-expansion-panel-header>
<span class="accord-title">Review Policy Summary</span>
<span class="spacer"></span>
<a *ngIf="!open.value" class="f-accent">SHOW</a>
<a *ngIf="open.value" class="f-accent">HIDE</a>
</mat-expansion-panel-header>
<mat-divider></mat-divider>
<!-- Quote Details Component -->
<quote-details [quote]="quote"></quote-details>
</mat-expansion-panel>
</mat-accordion>