How to pass value from one component to another? (Angular) - html

I just recently started learning Angular and I have a question. I want to implement a search method to search for a product on my site, I made search.pipe.ts, which works, but the input for input is in the header.component.ts component, and the products array is in the car-list.component.ts component.
car-list.component.html
<div *ngFor="let car of cars | paginate: { itemsPerPage: pageNumber, currentPage: currentPg} | **search:searchStr**" class="col-md-3">
<div class="product box">
<img src="{{'data:image/jpg;base64,' + car.image }}" alt="">
<h3>{{ car.name }}</h3>
<div class="price">{{ car.price | currency:'USD' }}</div>
<button class="btn btn-primary btn-sm">Add to cart</button> <!--(click)="addToCart(tempProduct)"-->
</div>
<br>
</div>
header.component.html
<form class="d-flex me-5">
<input type="text" class="form-control me-2" placeholder="Search cars...">
</form>
header.component.ts
export class HeaderComponent implements OnInit {
searchStr: string = '';
constructor() {
}
ngOnInit(): void {
}
}
search.pipe.ts
#Pipe({
name: 'search'
})
export class SearchPipe implements PipeTransform {
transform(cars: any[], value: any) {
return cars.filter(car => {
return car.name.includes(value);
})
}
}
I want the input values ​​from the header component to be passed to the car-list component so that I can find the product I need.

In this case you can use a shared service where you can pass data from your header component and load that data in your products component.
For further reference - Angular 4 pass data between 2 not related components

use #Input and #Output decorators to communicate between components

Related

Angular 13 - How to open form without button and the button click

My angular component has a tree and several nodes. When I double click on a node the click event runs a web api and retrieves data for an id that will be used to create a dynamic form using npm package: #rxweb/reactive-dynamic-forms. Once the data request is 'completed' a button appears and when clicked it opens the form with appropriate fields for the id selected. I would like to eliminate the need for this secondary button click. I've tried several suggestions but just cannot get anything to work.
I'm using Infragistics controls and bootstrap for the form.
html:
<div class="column-layout my-pane-layout">
<div *ngIf = "isShowFormButton" >
<button #open igxButton="raised" igxRipple="white" (click)="form.open()">Run</button>
<igx-dialog #form [closeOnOutsideSelect]="true" >
<igx-dialog-title>
<div class="dialog-container">
<igx-icon>vpn_key</igx-icon>
<div class="dialog-title">Form</div>
</div>
</igx-dialog-title>
<form class="input-group-form" [formGroup]="dynamicForm.formGroup" (ngSubmit)="onSubmit()">
<div class="container">
<div class="controls" viewMode="horizontal" [rxwebDynamicForm]="dynamicForm" [uiBindings]="uiBindings">
</div>
<button igxButton="raised" type="submit" igxRipple class="button" [disabled]="!dynamicForm.formGroup.valid">
<igx-icon>
directions_run
</igx-icon>
<span>Submit</span>
</button>
</div>
</form>
<div igxDialogActions>
<!-- <button igxButton (click)="form.close()">CANCEL</button> -->
<button igxButton (click)="form.close()">Submit</button>
</div>
</igx-dialog>
</div>
<h6 class="h6">
Levels
</h6>
<igx-tree #tree class="tree" selection="None" >
<igx-tree-node *ngFor="let level1 of myData" [data]="level1">
{{ level1.Name }}
<igx-tree-node *ngFor="let level2 of level1.levels" [data]="level2">
{{ level2.Name }}
<igx-tree-node *ngFor="let level3 of level2.levelplus" [data]="level3" (dblclick)="onDoubleClick($event,level3)">
{{level3.Name }}
</igx-tree-node>
</igx-tree-node>
</igx-tree-node>
</igx-tree>
</div>
XYZ.component.ts:
export class XYZComponent implements OnInit {
#ViewChild('form') dialog: IgxDialogComponent;
myData: any[];
public tree: IgxTreeComponent;
public selectedNode;
public ID: number = 2;
isShowRunButton: boolean = false;
public dynamicForm!: DynamicFormBuildConfig;
public dynamicFormConfiguration!: DynamicFormConfiguration;
constructor(private dynamicFormBuilder:RxDynamicFormBuilder){}
ngOnInit() {
populate tree with data here ...
}
public onDoubleClick(event,node) {
console.log(node);
event.stopPropagation();
this.runParameters(node.Id);
}
public runParameters(Id) {
this.aSer.getApi(Id).subscribe({next:(data: any[]) => {this.myData = data;},
error: err => {console.log(err); },
complete: () => {
this.dynamicForm =
this.dynamicFormBuilder.formGroup(this.myData,this.dynamicFormConfiguration);
this.isShowFormButton = true;
//this.dialog.open();
}
});
}
public onSubmit() {
console.log(this.dynamicForm.formGroup);
this.isShowFormButton= false;
//this.dialog.open();
}
}
If I uncomment out the 'this.dialog.open()' the code throws the following error:
TypeError: Cannot read properties of undefined (reading 'open')
Many postings say that I need to use a #ViewChild but it seems that it cannot find that reference : #ViewChild('form') dialog: IgxDialogComponent;
Any help would be much appreciated. Code works fine with the 'Run' button click but I want to eliminate that extra step.

Angular filter posts using pipes

I'm trying to filter posts of a table in Angular using pipes, but I keep getting on the console this error: core.js:12689 Can't bind to 'ngForFilter' since it isn't a known property of 'a'.
I think the error is on filter: filterPost, but dont know how to fix it. Any clue?
My html code is the following.
<div class="form-group">
<label for="exampleFormControlInput1">Busca un reporte</label>
<input type="text" class="form-control" id="exampleFormControlInput1" name="filterPost" placeholder="Busca.." [(ngModel)]="filterPost">
</div>
<a *ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage }; let i = index;
filter: filterPost" class="list-group-item list-group-item-action flex-column align-items-start" [routerLink]="['/reporte-admin']"
routerLinkActive="router-link-active" (click)="onSubmit(report._id)">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Reporte #: {{report._id}}</h5>
<small>{{i+1}}</small>
</div>
<p class="mb-1">Comentario: {{report.comentario}}</p>
<small class="text-muted">Nombre: {{report.nombre}} {{report.apellido}}</small>
</a>
<br>
This is my filter.pipe.ts code:
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any, arg: any): any {
const resultPosts = [];
for(const report of value){
if(report._id.indexOf(arg) > -1){
resultPosts.push(report);
};
};
return resultPosts;
}
}
Pipe operator "|" expects some value to the left of it.
In your case, you added the pipe operator at the end after let i=index;
I believe you should do something like this
*ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage } | filter: filterPost; let i = index;"
and also dont forget to add in declarations in app module

Update component when input changes in Angular

<div class=" card-body">
<div class="row">
<div class=" font-icon-list col-lg-2 col-md-3 col-sm-4 col-xs-6 col-xs-6" routerLinkActive="active"
*ngFor="let subject of subjects">
<div class=" font-icon-detail">
<div (click)="setSubject(subject.title)" >
<i class="deep-icons {{ subject.icon }}"></i>
<p>{{ subject.title }}</p>
</div>
</div>
</div>
</div>
</div>
<subject-component [setSubjectService]="selectedSubject"></subject-component>
The code above is from my selector.component.html.
export class SubjectComponent implements OnInit {
#Input() public set setSubjectService(_subjectService: ISubjectService) {
this.subjectService = _subjectService;
}
public subjectService: ISubjectService;
constructor() {}
public ngOnInit(): void {
}
}
The code above is from my subject.component.ts
Right now subject-component gets rendered once when the application starts up, but whenever "selectedSubject" changes it does not update or re-render. How can I make this possible?
(Using Angular 8)
I think you want to use two way binding.
If so;
Create an output with eventemitter like;
#Input() myVariable: number;
#Output() myVariableChange = new EventEmitter(); //define it nameofyourvariable+Change
constructor() { }
ngOnInit() {}
changeMyVar(v: number) {
this.myVariable=v;
this.myVariableChange.emit(myVariable);
}
And use two way binding with parantheses. I mean like following:
<subject-component [(setSubjectService)]="selectedSubject"></subject-component>

How do I use the index value of an array and pass it to a HTML modal so I can show the data there without using a loop in angular 7

How do I use the index value of an array and pass it to a HTML modal so I can show the data there without using a loop in angular 7
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../services/api.service';
import { movieModel } from '../models/movie';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.less']
})
export class HomeComponent implements OnInit {
movies:movieModel[];
constructor(public api:ApiService) { }
ngOnInit() {
this.loadMovies();
}
loadMovies(): void {
this.movies = [];
this.api.getMovies().subscribe(
data =>
{
this.movies = data.results;
this.movies = this.movies.slice(0 , 5);
console.log(this.movies);
}
);
}
}
<h1>Top 5 Movies by the New York Times</h1>
<div class="uk-child-width-1-3#s uk-grid-match" uk-grid>
<div *ngFor="let movie of movies; let i = index">
<div class="uk-card uk-card-hover uk-card-body">
<h3 class="uk-card-title">{{movie.display_title}}</h3>
<span>Headline: {{movie.headline}}</span><br/>
<span>Summary: {{movie.summary_short | characters:150 }}</span><br/><button class="uk-button uk-button-default" uk-toggle="target: #my-id">Read More</button><br/>
<p>By: {{movie.byline}}<br/>Rating:{{mpaa_rating || NA}}<br/>Date of Release: {{movie.publication_date | date: 'dd/MM/yyyy'}}</p>
</div>
</div>
</div>
<div id="my-id" uk-modal>
<div class="uk-modal-dialog uk-modal-body">
<h2 class="uk-modal-title">Summary</h2>
{{movie.summary_short}}
<button class="uk-modal-close uk-button uk-button-default" type="button">Close</button>
</div>
</div>
Can someone please explain to me how i get the value for movie.summary_short to work in the dialog box I have the for loop index done but cant figure out how to pass it to the other HTML element
Declare another property like summary_short in component.ts.
bind on (click) of 'Read More' button to assign movie.summary_short to summary_short.
component.html
<button (click)="saveSummary(movie.summary_short)" class="uk-button uk-button-default" uk-toggle="target: #my-id">
Read More
</button>
...
<div id="my-id" uk-modal>
<div class="uk-modal-dialog uk-modal-body">
<h2 class="uk-modal-title">Summary</h2>
{{summary_short}}
<button class="uk-modal-close uk-button uk-button-default" type="button">Close</button>
</div>
</div>
...
component.ts
...
summary_short
...
saveSummary(summary_short) {
this.summary_short = summary_short
}
...
Add a function to Read More button, something like this:
<button class="uk-button uk-button-default" uk-toggle="target: #my-id" (click)="readMore(movie.summary_short)">Read More</button>
Then in .ts, declare a var modalText and each time this button is clicked:
readMore(text: string){
this.modalText = text;
}
Finally, in modal, call {{ modalText }}.

How do I get the count of the selected checkboxes and display the count in Angular 2?

I need help displaying the count of a list of checkboxes into the value of a dropdown box. Where do I need to get my count from? The checkboxes are being passed dynamically as an array.
Here is my current code.
DropDownBox Component
<div ngbDropdown class="d-inline-block" [autoClose]="false">
<button class="btn btn-outline-primary" id="dropdownMenu1" ngbDropdownToggle{{title}}`(need to display the count here)`
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
<input type="text" placeholder="{{searchPlaceholder}}" class="searchBox" />
<div *ngFor="let data of datas">
<cst-checkbox [checkBoxValue] = "data" [ngModel]="data.selected"></cst-checkbox>
</div>
</div>
</div>
Checkbox component
<div class="checkbox">
<input type="checkbox" value="{{checkBoxValue}}" />
<label>{{checkBoxValue}}</label>
</div>
The checkbox component is <cst-checkbox> in the dropdown component.
You can create your Custom Pipe to get selected values only, by filtering them up
#Pipe({
name: 'getSelcted',
pure: false
})
#Injectable()
export class GetSelectedPipe implements PipeTransform {
transform(items: any[]): any {
// take out only selected values
return items.filter(item => item.selected === true);
}
}
Usage
{{(datas: getSelcted)?.length || 0}}
Note: Make sure GetSelectedPipe has been injected in declarations of AppModule's #NgModule declartions array.