How to solve no value in select when ngModel changes? - javascript

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.

Related

Change in one dropdown value is affecting other dropdowns

I have a add button which will keep on adding a div container which consists of two dropdowns. On selecting on dropdown we are setting other dropdown data.
When I click on add div it will add a second div with both dropdowns. But, change in one dropdown is affecting other dropdown.
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
private map = new Map<string, string[]>([
['Poland', ['Warszawa', 'Krakow']],
['USA', ['New York', 'Austin']],
]);
filtersList: any = [{}];
country: string;
city: string;
get countries(): string[] {
return Array.from(this.map.keys());
}
get cities(): string[] | undefined {
return this.map.get(this.country);
}
addFilter() {
this.filtersList.push({});
}
removeFilter(index) {
this.filtersList.splice(index, 1);
}
trackByIndex(index, item) {
return index;
}
}
app.component.html
<div *ngFor="let num of filtersList; let i = index; trackBy: trackByIndex">
<select [(ngModel)]="country">
<option *ngFor="let country of countries" [value]="country">
{{ country }}
</option>
</select>
<select *ngIf="country" [(ngModel)]="city" [value]="city">
<option *ngFor="let city of cities">{{ city }}</option>
</select>
<button (click)="removeFilter()">Remove</button>
</div>
<button (click)="addFilter()">Add more filters</button>
After adding div, each dropdown should have respective selected values.
So, when I click on add div it will add a second div with both dropdowns. But, change in one dropdown is affecting other dropdown.
That's because these two dropdowns share the same variable/storage. You need to give them separate storage. In this case, we create a list of object with selectedCountry and selectedCity.
app.component.ts
// import stuff here
type Filter = {
selectedCountry: string;
selectedCity: string;
};
#Component({
...
})
export class AppComponent {
...
filterList: Filter[] = [];
addFilter() {
this.filterList.push({selectedCountry: '', selectedCity: ''});
}
}
app.component.html
<div *ngFor="let filter of filterList">
<select [(ngModel)]="filter.selectedCountry">
<option *ngFor="let country of countries" [value]="country">
{{ country }}
</option>
</select>
<select *ngIf="country" [(ngModel)]="filter.selectedCity" [value]="city">
<option *ngFor="let city of cities">{{ city }}</option>
</select>
<button (click)="removeFilter()">Remove</button>
</div>
<button (click)="addFilter()">Add more filters</button>

How to set selected value of HTML Select Element in Angular 7 reactive forms?

I'm using Angular 7 reactive forms in my component. Part of my component:
#Component({
selector: 'my-form',
templateUrl: './my-form.component.html',
styleUrls: ['./my-form.component.scss']
})
export class MyFormComponent implements OnInit {
form: FormGroup;
loaded: boolean = false;
item: Item;
// item gets loaded from the server and looks like this:
// {
// id: 'dksldfkfjdk',
// title: 'first',
// selected: 'basic'
// }
itemsForSelect = ['basic', 'primary', 'admin'];
isNew: boolean = false;
constructor(private route: ActivatedRoute,
private resourceService: ResourceService,
private fb: FormBuilder,
private router: Router) {
}
ngOnInit() {
this.resourceService.getItem().subscribe(res => {
if (res.success) {
this.item = res.item;
this.createForm();
this.loaded = true;
}
});
}
createForm() {
this.form = this.fb.group({
'title': [this.item.title, Validators.compose([])],
'selected': [this.item.selected, Validators.compose([])]
});
}
}
Part of component HTML template related form:
<form [formGroup]="form" (ngSubmit)="isNew ? create() : update()" [class.error]="!form.valid && form.touched">
<div class="form-group">
<label for="item"></label>
<select placeholder="Choose Select" [formControl]="form.controls.selected" class="form-control"
id="item">
<option *ngFor="let itemForSelect of itemsForSelect">{{ itemForSelect }}</option>
</select>
</div>
<button class="btn btn-primary udpate pointer" [disabled]="!form.valid" type="submit">
{{ isNew ? 'Create' : 'Update' }}
</button>
</form>
The problem is that after updating item with, for example admin value, it has this value from server in property selected, but it still shows basic in HTML select as selected, after fetching data and showing form. How to set selected in Angular 7? I know I can use [(ngModel)] = item.selected, but as I'm using form.controls, I'm getting warning in console.
You can use patchValue on your form control like that:
public updateValue() {
this.form.get('selected').patchValue('basic');
}
Improvement: Dont use formControl with formControlName in same form control. Here is link to deeper explanation
You need to add [value] property to options
<option
[value]="itemForSelect"
*ngFor="let itemForSelect of itemsForSelect"
>{{ itemForSelect }}</option>
Sandbox: https://codesandbox.io/s/angular-l0d09

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.

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

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);
}
- - - - -
}

How to set first option as default option [duplicate]

I have worked on angular 4 project, In this project, I have a requirement to set the first option as selected where all options are created dynamically by loop.
html code:
<select [(ngModel)]="selectedServiceType" [ngModelOptions]="{standalone: true}" (ngModelChange)="getServiceType($event)">
<ng-container *ngFor="let service of services">
<option [ngValue]="service">{{service.name}}</option>
</ng-container>
</select>
If anyone know about let me know. Thanks in advance!
Try like this :
<select class="form-control" (change)="onChange($event)">
<option *ngFor="let service of services; let itemIndex = index" [selected]="itemIndex == 0" [ngValue]="service.value">{{service.name}}</option>
</select>
component.ts
export class HomeComponent implements OnInit {
private selectedServiceType: any;
private services: Array<any> = [];
constructor() {
this.services = [{
name: "Harish",
value: 5000
}, {
name: "Chandru",
value: 5001
}]
}
onChange(e) {
this.selectedServiceType = e.target.value;
}
}
Just in your ts, inside ngOnInit
selectedServiceType : any;
ngOnInit() {
//make sure you have values for **`services`**
this.selectedServiceType = services[0];
}
add this code
<select (change)="onChange($event.target.value)" value={{selectedService}}>
<ng-container>
<option *ngFor="let service of services" >{{service.name}}</option>
</ng-container>
</select>
and you component.ts should be
export class YourClass implements OnInit {
selectedService: any;
services:any = [];
--your API call code set values to services array
this.services=this.service.APImethod()
onChange(newValue) {
this.selectedService=newValue;
}
}

Categories