How to set an Input property without binding in Angular - html

I have a simple Angular component which takes a debounce time as an Input parameter. The parameter type is a number with a default value equals to 0. It is used later on as a debounceTime value.
input.component.ts
import { AfterViewInit, Component, Input } from '#angular/core';
import { debounceTime } from 'rxjs';
#Component({
selector: 'app-input',
templateUrl: './input.component.html',
styleUrls: ['./input.component.scss']
})
export class InputComponent implements AfterViewInit {
#Input() debounce: number = 0;
ngAfterViewInit(): void {
//(...).pipe(debounceTime(this.debounce)).subscribe(...);
}
}
I would like to pass the debounce value from the parent component without binding to the local variable or constant.
app.component.html
<app-input debounce="200"></app-input>
It doesn't work because debounce value comes as a string type from a template. It does work when I use binding to the local constant. A console error confirms the type.
Error: src/app/app.component.html:3:12 - error TS2322: Type 'string' is not assignable to type 'number'.
I can disable strict templates checks as this is a default for Angular 15 but rxjs "debounceTime" function won't accept a string parameter.
How can I pass a number directly from the template without using bindings?

You can just use [] for input to pass a number like this:
<app-input [debounce]="200"></app-input>
you'll now get a number.

Use a setter
debounce: number = 0;
#Input() set _debounce(value:any){
this.debounce=+value;
}
Or use
.pipe(debounceTime(+this.debounce)
NOTE: The + is a confortable way to parse a string to number

Related

Angular Mat-Select - openedChange returns undefined

I am setting css style using custom code when user opens mat-select. But it returns undefined error.
In console, when I print and check element values, could see panel:undefined.
Can someone please let me know How to get the panel value.
Error: Cannot read property 'nativeElement' of undefined
Html:
<mat-select #select (openedChange)="changeHeight($event,select)">
<mat-option>1</mat-option>
<mat-option>2</mat-option>
</mat-select>
component.ts:
import { Component, OnInit, Inject, Renderer2, ElementRef } from '#angular/core';
constructor(private renderer:Renderer2){}
changeHeight(event:any,element:any)
{
if (event)
{
const height = window.innerHeight||
document.documentElement.clientHeight||
document.body.clientHeight;
this.renderer.setStyle(element.panel.nativeElement,
'max-height',
(height-10-element.panel.nativeElement.getBoundingClientRect().y)+'px')
}
}
Add this
import { ViewChild } from "#angular/core";
import { MatSelect } from "#angular/material/select";
and this to your component:
#ViewChild('select') select: MatSelect;
Afterwards you can, if you need it, pass select as a parameter or just remove the parameter and call it directly.
set elementref for element top of constructor then set the same name in your template #name with your elementref name.

Data showing as undefined when I am trying to pass data from parent component to child components

I am trying to pass data from parent component to child components, but I am getting data is undefined,
In my below code
parent component
here part_data I have declared in service
this._PartService.GetDataValues(this.search.item, this.search.filter_type, release_part).subscribe(
result => {
this.resultData = result;
this._PartService.part_data = this.resultData.data
})
child component
Here I am using observer
this.searchService.observer.subscribe(search => {
this.part = search.item;
this.specification = this._PartService.part_data.partMasterDataCompleteList[0];
})
Here I am getting PartMasterDataCompleteList[0] is undefined
Use this as the child component:-
#Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
#Input() hero: Hero;
constructor() {}
ngOnInit() {}
}
When you need to feed data to the component, use the below code:-
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
The hero property is #Input which receives data from the outer environment.
For more information, refer to Angular tutorial:-
https://angular.io/tutorial/toh-pt3
You can pass your data in sub component and get using #Input method.
There is one other way to pass data from one component to other component.
Click here

Angular 4 - Custom two way binding

I am trying to implement a custom two way binding between two of my components.
I did read about the naming convention saying that you have to define a #Input() like "test" and then define a #Output() named "testChange".
I couldn't find anything about whether this is still up-to-date or not and I can't get my binding to work.
Some code within parentComponent:
<my-comp [(userGroupIds)]="userGroups"></my-comp>
MyComponent (child):
export class MyComponent implements OnInit, OnDestroy{
#Input() userGroupIds: number[];
#Output() userGroupIdsChange = new EventEmitter<number[]>();
updateValues(){
//here I am iterating through the rows of a table within my component
this.userGroupIds = this.tableRows.map(item => {return item['id']});
this.userGroupdIdsChange.emit(this.userGroupIds);
}
}
parentComponent:
export class parentComponent implements OnInit, OnChanges, OnDestry{
userGroups: number[];
constructor(){
this.userGroups = [];
}
ngOnChanges(changes: SimpleChanges){
if(changes['userGroups']){
// this is never show, ngOnChanges doesn't get fired;
console.log(this.userGroups);
}
}
}
Is there something I am missing? Did the Angular-Team change anything?
Afaik the binding does something like
[userGroupsIds]="userGroups" (userGroupsIdsChange)="userGroupIds=$event"
So I tried setting this myself, but no update either. Only thing that work was passing a function to the eventEmitter.
Your binding works like a charm, it does not trigger the ngOnchanges method, which is the expected behavior.
from the Angular docs :
OnChanges
Lifecycle hook that is called when any data-bound property of a directive changes.
as userGroups is not an #Input() it cannot be a "data-bound property" , its value changing internally will not run the ngOnChanges hook.

Access constant in HTML in Ionic 3

My project is in Ionic 3. I have a data provider class for storing constants.
ex
export const CONST1 = 1;
export const CONST2 = 2;
#Injectable()
export class DataProvider {
constructor() {
}
}
In my Display Page, I want to use the constant data. So If I do
import * as Data from './../../providers/data/data';
I can directly access Data.CONST1 in my Display.TS file.
How do access the values in my Display.HTML file? There Data.CONST1 is not working.
One way to do it would be by assigning the Data object to a public property of that component:
import * as Data from './../../providers/data/data';
// ...
#Component({
selector: 'page-display,
templateUrl: 'display.html'
})
export class DisplayPage {
public constants = Data;
// ...
}
And then in the view
<p>{{ constants.CONST1 }}</p>
EDIT:
I want to use it as an input parameter and <ion-input
maxLength="constants.CONST1"></ion-input> does not work.
That's actually because you need to use attribute binding, to let angular know that the expression between "" must be interpreted:
<ion-input [attr.maxLength]="constants.CONST1"></ion-input>

Angular2 binding throws an error "Expression has changed after it was checked"

As i having parent and child component as follows,
Child Component (RWTaxComponent)
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
#Component({
selector: 'rw-tax',
templateUrl: 'rw.tax.component.html'
})
export class RWTaxComponent implements OnInit {
#Input() hsn: string = '';
#Input() srno: string = '';
#Input() taxPercent: number;
#Output() taxPercentChange: any = new EventEmitter();
constructor(
) { }
ngOnInit() {
}
ngOnChanges(event) {
console.log('HSN:: '+this.hsn);
console.log('SRNO:: '+this.srno);
if (this.hsn && this.srno) {
// Doing my logic here to find taxPercent
this.taxPercentChange.emit(this.taxPercent);
}
}}
Child component template (rw.tax.component.html) is,
<p>{{taxPercent | number:'1.2-2'}}</p>
And i invoked the above child component in my parent component as follows,
<rw-tax [(hsn)]="lineItem.hsn" [(srno)]="lineItem.srno" [(taxPercent)]="lineItem.taxPercent"></rw-tax>
I want to change taxpercent whenever hsn/srno is changed, these hsn/srno is not changed in RWTaxComponent itself, it is changed by parent component.
So i used ngOnChanges() event to detect that hsn/srno is changed and it getting invoked when ever i change hsn and srno in my parent component.
But the problem is after doing my logic to find taxpercent am trying to update the value in parent component by this.taxPercentChange.emit(this.taxPercent); and getting error "Expression has changed after it was checked"
Am i wrongly understood the Angular2 lifecycle ?
Please suggest a right way to do it...
This issue occurs when there is a change in input of the component and on that change if we are trying to change or emit any property.
Solution 1:
try promises resolve the changes and in then block emit the output event.
Solution 2 : (may not work)
Try setTimeout method on emitting the value