Detect changes in HTML of child component from parent component in Angular - javascript

So I have a parent component say
#Component({
selector: 'parent-comp'
template: '<child-comp [inputData]="responseData"></child-comp>
})
export class ChildComponent {
public responseData: any;
getData() {
this.responseData = getDataFromSomeService();
}
- - - - -
}
My child component is something like this
#Component({
selector: 'child-comp'
templateUrl: 'someUrl'
})
export class ChildComponent {
#Input
inputData: any;
- - - - -
}
My child component html has a select box
<select>
<option disabled
value=""
selected> Select
</option>
<option *ngFor="let val of values"
[value]="val.key"> {{val.name }}
</option>
</select>
So every time an "option" is selected in "select" I want to get different data from parent component as an input to child component. That is the "responseData" to be sent as input to child component is different for different "option" selected.
In my scenario parent component is kind of data transformer which sends different data based on the options selected in child component.
So how do I detect that a different "option" in "select" box is selected and send the key attached with "option" to parent component to get different "responseData"

in the child component, add the output decorator as follows:
#Component({
selector: 'child-comp'
templateUrl: 'someUrl'
})
export class ChildComponent {
#Input
inputData: any;
#Output onSelectChange = new EventEmitter<string>();
onSelectedOptionChanged($event) {
// trigger the event to parent.
this.onSelectChange.emit($event.target.value);
}
- - - - -
}
and in the child component template
<select (change)='onSelectedOptionChanged($event)'>
<option disabled
value=""
selected> Select
</option>
<option *ngFor="let val of values"
[value]="val.key"> {{val.name }}
</option>
</select>
in parent .ts code
#Component({
selector: 'parent-comp'
template: '<child-comp [inputData]="responseData"
(onSelectChange)='changeResponseData(data)></child-comp>
})
export class ChildComponent {
public responseData: any;
getData() {
this.responseData = getDataFromSomeService();
}
changeResponseData(newDate) {
console.log('new selected option is', newData);
}
- - - - -
}

Related

How to solve no value in select when ngModel changes?

A project contains a component and a service.
Component injects the service and uses services field filter. There is a select in the components hmtl. [(ngModel)] of the select is binded to filter.sizes.width.
The component:
#Component({
selector: 'app-facet-sizes-static',
templateUrl: './facet-sizes-static.component.html',
styleUrls: ['./facet-sizes-static.component.scss']
})
export class FacetSizesStaticComponent implements OnInit {
constructor(
private Search: SearchService
) {
this.filter = Search.filter;
}
clearFilter() {
this.filter.sizes.width = 0;
}
}
Its template:
<div (click)="clearFilter()"></div>
<!-- Comment_01 -->
{{filter.sizes.width}}
<div *ngIf="filter.sizes">
<select name="width"
[(ngModel)]="filter.sizes.width">
<option [ngValue]="null">~</option>
<option *ngFor="let item of facet.sizes[0].parts.width; let x = index"
[ngValue]=item>
{{ item }}
</option>
</select>
</div>
The service:
export class SearchService {
filter: SearchServiceFilter = null;
constructor() {
this.filter = {
sizes: {
width: 0
},
};
}
}
When I change option in select it changes filter.sizes.width as I exapt. But there are two problems:
when component is inited there is no value in the select but filter.sizes.width has 0 value. I can check it watching the string {{filter.sizes.width}} under Comment_01
when the method clearFilter() changes filter.sizes.width there is becomes again no value in the select.
How do I solve it?
It sounds like your facet.sizes[0].parts.width array does not contain a value === 0. I see your option with a value of null, but null does not equal 0 and will not be selected. If you add an option with a value === 0; it should select it.

Angular: Filter Service via API request

I am using a filter and need to read the value in order to send an API request with the values in the url.
I use this API. I am able to filter both of the categories. After selecting two, we wanna send an API request with both selected values in the url.
We generated a backend-side script to filter, all I need to do is sending a request with the modified url.
app.component.ts
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe(lines => {
this.lines = lines;
this.filteredLines = [...this.lines];
});
}
filter() {
this.filteredLines = [
...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
];
}
/** Here I need a script onClick button that reads the selected values and sending a get-request of API link above added with the filtered values:
With click on the submit-button, I want to send the API request.
If api.com/data is the link, the request link would be like api.com/data?line=A&workCenter=1
The "?" is for category Line, and "&" for workCenter.
**/
}
}
app.component.html
<select>
<option>Line</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.line}}
</option>
</select>
<select>
<option>Work Center</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.workCenter}}
</option>
</select>
<form action="" method="post">
<input type="submit" name="request" value="Submit" />
</form>
I have created a Stackblitz project for better understanding.
From your example, you need to add [(ngModel)] which will bind to the selected value.
You can find more info on how to properly use a select here More info
<select [(ngModel)]="selectedLine">
<option>Line</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.line}}
</option>
</select>
<select [(ngModel)]="selectedWorkCenter">
<option>Work Center</option>
<option *ngFor="let dropdown of filteredLines" (keyup)="filter()">
{{dropdown.workCenter}}
</option>
</select>
<form action="" method="post">
<input type="submit" name="request" value="Submit" (click)="Submit()" />
</form>
Then in your ts file, declare the select variable and access value as in the click function Submit.
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
selectedLine; // For first select
selectedWorkCenter; // For second select
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe(lines => {
this.lines = lines;
this.filteredLines = [...this.lines];
});
}
filter() {
this.filteredLines = [
...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
];
}
requestAnDieAPI() {
console.log(this.filteredLines); // hier muss mein API post request hin
}
Submit() {
var baseUrl = `https://api.mocki.io/`;
var url = `${baseUrl}data?line=${this.selectedLine}&workCenter=${
this.selectedWorkCenter
}`;
this.http.get(url).subscribe(response => {
// response
});
}
}
It is not clear for me if you want to send multiple { line, workCenter } objects to the API call, but from how you setted up the Stackblitz project I will assume you want to send just a single one.
Never seen a (keyup) on an <option> element, use [(ngModel)] on the <select> instead:
<select [(ngModel)]="selected.line">
<option [value]="null">Line</option>
<option *ngFor="let dropdown of filteredLines" [value]="dropdown.line">
{{dropdown.line}}
</option>
</select>
<select [(ngModel)]="selected.workCenter">
<option [value]="null">Work Center</option>
<option *ngFor="let dropdown of filteredLines" [value]="dropdown.workCenter">
{{dropdown.workCenter}}
</option>
</select>
<!-- the use of the form in this case is not required -->
<!-- since you are using requestAnDieAPI to do the api call -->
<form action="" method="post" (submit)="requestAnDieAPI()">
<input type="submit" name="request" value="Submit" />
</form>
<!-- You can also use just a simple button -->
<button (click)="requestAnDieAPI()">Submit</button>
Then your component (model) should contain a selected variable that map the interface (view)
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
lines: any[];
filteredLines: any[];
filterBy;
selected = {
line: null,
workCenter: null
};
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get("https://api.mocki.io/v1/26fce6b9").subscribe((lines: any[]) => {
this.lines = lines;
// this.filteredLines = [...this.lines];
// better:
this.filteredLines = this.lines.slice();
// or either this.filter() directly
});
}
filter() {
// this.filteredLines = [
// ...this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
// ];
// this is redundant, better:
this.filteredLines = this.lines.filter(dropdown => dropdown.name.includes(this.filterBy))
}
requestAnDieAPI() {
if (this.selected.line != null && this.selected.workCenter != null) {
let apiUrl = "https://api.com/data?line=" + this.selected.line +
"&workCenter=" + this.selected.workCenter
this.http.get(apiUrl).subscribe(/* Your optional response callback/subscriber here */);
}
}
}

Angular send data from another component

I woudlike to send data selected from my another component (variable in file .ts)
.html :
<div class="liste">
<select class="form-control" name="Container" (change)="selectChangeHandler($event)">
<option disabled selected value> -- select an Container -- </option>
<option *ngFor="let v of values;let i = index" [value]="i">
{{v.Name}}
</option>
</select>
</div>
<div class="tableau" *ngIf="show" >
<table align="center">
<tr align="center"><b>{{selectedValue.Name}}</b></tr>
<tr align="center"><td>Matricule: {{selectedValue.Matricule}}</td></tr>
<tr align="center"><td>Material: {{selectedValue.Material}}</td></tr>
<div class="modal-body">
<app-heat-local> </app-heat-local>
</div>
How can I get value for this component with using to send my data in this component ?
another component .html (heat-local):
<h6 class="container-name">{{selectedValue.Name}}</h6>
my file .ts :
import {Component, OnDestroy, OnInit} from '#angular/core';
import {Cell} from 'app/data/cell';
#Component({
selector: 'app-heat-global',
templateUrl: './heat-global.component.html',
styleUrls: ['./heat-global.component.css'],
providers: [HeatService]
})
export class HeatGlobalComponent implements OnInit{
selectedValue = {
Name: '',
Matricule: '',
Material:'',
Quantity:'',
Coordonates:'',
}
values = [{
Name: "Container A",
Matricule: "ABC",
From the question it seems that it could be possible to solve it this way.
You can set value of a selected option to property inside of selectChangeHandler()
selectChangeHandler(event) {
this.currentValue = event.target.value;
}
To get it inside of app-heat-local
<div class="modal-body">
<app-heat-local [value]="currentValue"> </app-heat-local>
</div>
To be able to set [value] attribute you need to define #Input() property inside of HeatLocalComponent
You could use #Input() to achieve this.
import {Component, Input} from '#angular/core';
#Component({
selector: 'app-heat-local',
templateUrl: './heat-local.component.html',
styleUrls: ['./heat-local.component.scss']
})
export class HeatLocalComponent {
#Input() value: number;
}
To display the value in heat-local.component.html you can you use interpolation
<h6 class="container-name">{{value}}</h6>
You can read more about component interaction
Update
To receive name instead of index just change value from i which is index to v.Name.
{{v.Name}}
Or you can provide the whole object
<option *ngFor="let v of values;let i = index" [value]="v">
{{v.Name}}
</option>
Becareful with type you specify in here. In previous part there is number type specified so it won't take anything else than number
import {Component, Input} from '#angular/core';
#Component({
selector: 'app-heat-local',
templateUrl: './heat-local.component.html',
styleUrls: ['./heat-local.component.scss']
})
export class HeatLocalComponent {
#Input() value: string // <== Here you can specify the type by TS type
}
string will be used just when value of an option is string, if you want to send whole object then change it to this #Input() value: any or define your own interface

angular 6: trying loop throw an object (via *ngFor) after choosing a value of a 'select'

I'm trying to build a "quick order" component for ordering movies.
The first element is a 'select'. i get the results via http request and then render the options.
When the user is choosing an option of a movie, i need to display him another select which shows available dates. i need to render the select according to an object who got string dates as his keys.
e.g:
{
"2018-07-19": {
"00:10": "5b4f445da2c93e36c4f1a1ca",
"01:00": "5b4f355ab6334b27fc031adb",
"13:44": "5b4f43fda2c93e36c4f1a1c9"
},
"2018-07-25": {
"23:00": "5b4f357db6334b27fc031adc"
}
}
everything is working fine with the rendering of the movieList select and with retrieving the dates object. but when i add the html code of the second select (id=selectDate), i get an error.
Here is my code:
ts:
import { Component, OnInit } from '#angular/core';
import { MoviesService } from '../services/movies.service';
import { ShowService } from '../services/show.service';
import { Observable } from 'rxjs';
import * as moment from 'moment';
#Component({
selector: 'app-quick-order',
templateUrl: './quick-order.component.html',
styleUrls: ['./quick-order.component.css']
})
export class QuickOrderComponent implements OnInit {
movieList: any;
movieShowsSchedule: any;
selectedMovie: any;
selectedDate: any;
constructor(private moviesService: MoviesService, private showService: ShowService) { }
ngOnInit() {
this.movieList = this.moviesService.getMovies();
}
onChangeSelectMovie() {
this.movieShowsSchedule = this.showService.getMovieSchedule(this.selectedMovie).subscribe(res => {
alert("we got movie successfully");
console.log(res);
}, err => {
alert("we did not get movie");
});
}
onChangeSelectDate() {
}
}
html:
<div class="form-group">
<label for="selectMovie">Movie:</label>
<select id="selectMovie" [(ngModel)]="selectedMovie" (change)="onChangeSelectMovie()">
<option *ngFor="let movie of movieList | async" value="{{movie._id}}" >{{movie.title}} </option>
</select>
<label for="selectDate">Date:</label>
<select id="selectDate" [(ngModel)]="selectedDate" (change)="onChangeSelectDate()">
<option *ngFor="let date in movieShowsSchedule | async" value="{{date}}" >{{date}}</option>
</select>
</div>
Anybody knows what is the problem? and how can make this code work?
Many thanks!
There are several issues.
Since you're using async, you should set moveShowSchedule to the result of the Observable not the Subscription, or easier still, don't use async.
You can use map to convert movieShowSchedule into a usable model for your view.
You should replace in with of in the *ngFor.
COMPONENT
movieShowsSchedule = [];
onChangeSelectMovie() {
this.showService.getMovieSchedule(this.selectedMovie).subscribe(x => {
this.moveShowSchedule = [];
for (let key in x) {
this.moveShowSchedule.push({ key, date: x[key].date });
}
});
}
HTML
<option *ngFor="let x of movieShowsSchedule" [ngValue]="x.date">
{{x.date}}
</option>
I didn't want to refactor your whole code, but if you created an Observable bound to the change event you could then use switchMap to update a movieShowSchedule Subject.

Angular 2 - Get passed object to component via inputs

On my parent page I have a link here:
<a (click)="showPermissionsRates(5757);">Link</a>
The function sets it:
showPermissionsRates(item) {
this.currentEventPoolId = item;
}
With a child component on the parent page here:
<app-event-pools-permissions-rates [eventPoolId]="currentEventPoolId "></app-event-pools-permissions-rates>
And then in my child component TS file I use:
inputs: ['eventPoolId']
But how do I get that value of '5757' in the child component? Such as using alert?
You should be able to just use #Input() on the child property.
I've put this together showing a VERY basic example, but without more to go on regarding your issues, it's hard to know what you need:
https://plnkr.co/edit/y9clOla1WrPFmhMJoz7o?p=preview
The gist is to use #Input() to mark your inputs in the child component, and map those in the template of the parent.
import {Component} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import { ChildComponent } from 'child.component.ts';
#Component({
selector: 'my-app',
template: `
<div>
<button (click)="changeProperty('ABC 123')">Click Me!</button>
<child-component [childProperty]="parentProperty"></child-component>
</div>
`,
})
export class App {
public parentProperty: string = "parentProp";
public changeProperty(newProperty: string) : void {
this.parentProperty = newProperty;
}
}
Then, in the child:
import {Component, Input} from '#angular/core'
#Component({
selector: 'child-component',
template: `
<div>Hello World: {{ childProperty }}</div>
`,
})
export class ChildComponent {
#Input()
childProperty:string;
constructor() {
this.childProperty = 'childProp'
}
}
I think you are setting value to at input variable in a click event, then you have to listen for it in the child component constructor using ngonchanges
ngOnChanges(changes: SimpleChanges) {
if(changes['eventpoolid'] && changes['eventpoolid'].currentValue) {
// you get updated value here
}
}

Categories