Angular CLI disable html form if previous option not selected? - html

I have a form that has a few select fields populated with options.
<form [formGroup]="selectVehicleForm">
<select formControlName="Manufacturer">
<option *ngFor='let cars of cars$'>{{cars.Manufacturer}}</option>
</select>
<select formControlName="Model">
<option *ngFor='let cars of cars$'>{{cars.Model}}</option>
</select>
</form>
My question - how can I disable my "Model" field as long as a user has nothing selected in "Manufacturer"?

You can try like this (not tested) :
constructor(private fb: FormBuilder) {
this.selectVehicleForm = this.fb.group({
Manufacturer: [],
Model: [{ value: '', disabled: true }]
)};
this.selectVehicleForm.get('Manufacturer').valueChanges.subscribe(value => {
if (value) {
this.selectVehicleForm.get('Model').enable();
} else {
this.selectVehicleForm.get('Model').reset('');
this.selectVehicleForm.get('Model').disable();
}
this.selectVehicleForm.updateValueAndValidity();
})
}

You can listen (change) on the FormControl Manufacturer and call enable()/disable() on the FormControl Model
See the Stackblitz
Relevant parts are :
HTML
<select formControlName="Manufacturer" (change)="onChangeManufacturer($event)">
<option *ngFor='let cars of cars$'>{{cars.Manufacturer}}</option>
</select>
Typescript
selectVehicleForm = new FormGroup({
Manufacturer: new FormControl(),
Model: new FormControl(),
});
ngOnInit() {
this.selectVehicleForm.controls['Model'].disable();
}
onChangeManufacturer(value) {
const formControlModel = this.selectVehicleForm.controls['Model'];
if(this.selectVehicleForm.controls['Manufacturer']) {
formControlModel.enable();
} else {
formControlModel.disable();
}
}

Related

Displaying objects dropdown from an array - Angular

I need help with this implementation. Im have an array loaded with some objects, and i want to display only the property called "name" of those objects in the dropdown, and when i select one of those options, i want to have access to the entire object. Is that possible?
At the moment i tried this code:
HTML of the component:
<select (change)="update($event)">
<option value="default">----</option>
<option value={{item}} *ngFor="let item of noMensuales">
{{item.nombre}}
</option>
</select>
TS of the component:
import { Component, OnInit } from '#angular/core';
import { ServicesDebCredService } from 'src/app/services/services-deb-cred.service';
#Component({
selector: 'app-pago-no-mensual',
templateUrl: './pago-no-mensual.component.html',
styleUrls: ['./pago-no-mensual.component.css']
})
export class PagoNoMensualComponent implements OnInit {
noMensuales: any = []
seleccionado:any = {}
constructor(private _serviceDebCred: ServicesDebCredService) { }
update(e : any) {
this.seleccionado = e.target.value
console.log(this.seleccionado)
console.log(this.seleccionado.nombre)
}
ngOnInit(): void {
this.getNoMensuales()
}
getNoMensuales() {
this._serviceDebCred.getNoMensuales().subscribe((res) => {
this.noMensuales = res.noMensuales
})
}
}
The thing is that, on the "seleccionado" field (the one i want to select and get the entire object) i have an empty object when i click on one of the list...
Yes it is possible, you need to tweak your code little bit, If you have an ID in your object just refer that pass that ID as value.
HTML file
<select (change)="update($event)">
<option value="default">----</option>
<option value={{item.id}} *ngFor="let item of noMensuales">
{{item.nombre}}
</option>
</select>
TS file: Into your update function:
update(e : any) {
let selectedObject = {};
this.noMensuales.map((res)=>{
if(e.target.value == res.id){
selectedObject = res;
}
});
console.log(selectedObject)
}
If you dont have ID or unique values in your object you can do it with ngFor index as well
You can easily access the object by referring this.
<select (change)="update($event)">
<option value="default">----</option>
<option value={{item}} *ngFor="let item of noMensuales">
{{item.nombre}}
</option>
I have reduced your update function code line for get your response very quickly
update(e : any) {
console.log(this.noMensuales.filter(item => item.id === e.target.value)[0])
}

Angular table filter clearing group

I have 2 filters on a user list. A user can select a group containing members and use the search filter to search by last name. When the user backspaces a user to look for another, this resets the groups to all users. I need this to only show the users in the selected group.
TS
updateFilter(event) {
const val = event.target.value.toLowerCase();
const temp = this.temp.filter(function (d) {
return d.lastName.toLowerCase().indexOf(val) !== -1 || !val;
});
this.rows = temp;
if (this.table) {
this.table.offset = 0;
}
}
onGroupSelected($event) {
const groupId = $event.target ? $event.target.value : $event;
if (groupId === 'none') {
this.rows = this.temp;
} else {
const groupUsers = this.groupUserMap.get(groupId);
if (groupUsers) {
this.rows = this.temp.filter((serviceUser) =>
groupUsers.includes(serviceUser.id));
} else {
this.rows = [];
}
}
// #ts-ignore
this.userSelections = this.userSelections ? this.userSelections : {};
this.userSelections.groupId = groupId;
localForage.setItem(this.username, this.userSelections);
}
HTML
<input
type='text'
class="form-control w-200px"
placeholder='Search by Last Name...'
(keyup)='updateFilter($event)'
/>
<select class="form-control w-200px" (change)="onGroupSelected($event)">
<option value="none">All service users</option>
<option *ngFor="let group of groups"
[value]="group.id"
[selected]="userSelections.groupId === group.id">
{{group.name}}
</option>
</select>
You can use ngModel with tow-way binding, to save and manipulate search filters:
<select
class="form-control w-200px"
[(ngModel)]="selectedGroup"
(change)="onGroupSelected()"
>
<option value="none">All service users</option>
<option *ngFor="let group of groups" [value]="group.id">
{{ group.name }}
</option>
</select>
<input
type="text"
class="form-control w-200px"
placeholder="Search by Last Name..."
[(ngModel)]="search"
(keyup)="updateFilter()"
/>
And in order not to lose your users table you can create a copy which will be filtered and displayed.
public initialUsers = [
{ id: 100, groupId: 1, name: 'foo' },
{ id: 101, groupId: 2, name: 'bar' },
{ id: 102, groupId: 1, name: 'john' },
{ id: 103, groupId: 2, name: 'doe' },
{ id: 104, groupId: 2, name: 'baaar' },
{ id: 105, groupId: 1, name: 'fooodoe' },
];
public filteredUsers = [];
ngOnInit(): void {
this.filteredUsers = this.initialUsers;
}
Here is a demo on stackblitz, I used a list to go fast but It's just display. You just have to replace <ul> <li></li> </ul> by your <table> ... </table>
If you would want to take an observable way of doing this, then I would suggest to make a form of your controls, ooooor just use 2 form controls instead. I chose form here as it wraps it up nicely with both form controls (search and dropdown):
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
search: [''],
group: [0] // "all" option as initial id
})
}
Then we would listen to when the form value changes and assign the filtered data to a variable, here named filteredUsers$.
this.filteredUsers$ = this.form.valueChanges.pipe(
startWith(this.form.value), // to trigger initially
// 'this.users' refers to your original users array
map((value: any) => {
// 'all' option is chosen, just filter based on search
if (value.group === 0) return this.users.filter(x => x.lastName.toLowerCase().includes(value.search))
// filter by group and search
return this.users.filter(x => {
return (x.groupId === value.group) && (x.lastName.toLowerCase().includes(value.search.toLowerCase()))
})
})
)
That is it, then we just iterate filteredUsers$ in the template:
<tr *ngFor="let user of filteredUsers$ | async">
Of course we need the form in the view and it would look like this:
<form [formGroup]="form">
<input
type="text"
placeholder="Search by Last Name..."
formControlName="search"
/>
<select formControlName="group">
<option *ngFor="let group of groups" [ngValue]="group.id">
{{ group.name }}
</option>
</select>
</form>
Here is a DEMO with the above code

Setting selected in dropdownlist with Angular

I have a list displayed in a dropdownlist, but it displays the default as a blank and not as the first item in the dropdown.
I have tried adding let i = 0 and then [selected]="i = 0", but this does not seem to set the default item to the first item, however I am receiving the correct value back from i.
Below is my code:
<div class="form-group">
<label for="userName">User Name</label>
<select formControlName="userName" class="form-control" (change)="userChange($event)">
<option *ngFor="let row of usersModel;let i = index" value="{{ row.id }}" [selected]="i == 0">{{ row.userName }} {{ i }}</option>
</select>
</div>
Here is my TypeScript File:
import { Component, OnInit } from '#angular/core';
import { UserAdminService } from '../../services/user-admin.service';
import { FormBuilder, Form, FormControl, FormGroup } from '#angular/forms';
import { Router } from '#angular/router';
#Component({
selector: 'lib-add-user-to-role',
templateUrl: './add-user-to-role.component.html',
styleUrls: ['./add-user-to-role.component.css']
})
export class AddUserToRoleComponent implements OnInit {
addUserToRoleForm: FormGroup;
rolesModel: any[];
usersModel: any[];
selectedRole: string;
selectedUser: string;
constructor(private userAdminService: UserAdminService, private formBuilder: FormBuilder, private router: Router) {
var roleControl = new FormControl('');
var userControl = new FormControl('');
this.addUserToRoleForm = formBuilder.group({ roleName: roleControl, userName: userControl });
}
ngOnInit() {
this.userAdminService.getRoles().subscribe(roles => {
this.rolesModel = roles;
this.selectedRole = this.rolesModel[0].name;
this.userAdminService.getUsersNotInRole(this.selectedRole).subscribe(users => {
this.usersModel = users;
this.selectedUser = this.usersModel[0].id;
console.log(this.usersModel[0].userName);
this.addUserToRoleForm.controls['roleName'].setValue(this.rolesModel[0].name);
this.addUserToRoleForm.controls['userName'].setValue(this.usersModel[0].userName);
});
});
}
userChange(event: any) {
this.selectedUser = event.target.value;
console.log('Selected ' + this.selectedUser);
}
AddUserToRole() {
this.userAdminService.addUserToRole(this.selectedUser, this.selectedRole)
.subscribe(result => {
if (result.success) {
this.router.navigate(['/roleusermaint']);
}
else {
console.log('Error Received on adding user to role');
}
});
}
}
As you can see I added {{ i }} in the text to make sure it shows the value of i and it does:
What am I missing ?
Thanks for any help!
#Axle, if you're using a Reactive Form, you needn't use [selected] nor (change), just, when you create the form you give value to userName
Using the constructor
const firstId=usersModel[0].id
this.form=new FormGroup({
userName:new FormControl(firstId)
})
Using formBuilder
const firstId=usersModel[0].id
this.form=this.fb.group({
userName:firstId
})
Using setValue, after create the form
const firstId=usersModel[0].id
this.form.get('userName').setValue(firstId)
As you are using Angular reactive form, try to keep the logic in ts file itself.
Using setValue(), you can set the default value to a control.
To set the default value to form control you could to it like,
this.form.controls['country'].setValue(this.countries[0].id)
In template use it like,
<option *ngFor="let country of countries" [value]="country.id">
{{ country.name }}
</option>
Working Stackblitz
Ref:
A complete sample code would be something like,
app.component.ts
import { Component } from '#angular/core';
import { FormGroup, FormControl } from '#angular/forms';
import {Country} from './country';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
countries = [
{
id: 'us',
name: 'United States'
},
{
id: 'uk',
name: 'United Kingdom'
},
{
id: 'ca',
name: 'Canada'
}
];
form: FormGroup;
ngOnInit(){
this.form = new FormGroup({
country: new FormControl('')
});
this.form.controls['country'].setValue(this.countries[0].id)
}
}
app.component.html
<form [formGroup]="form">
<select formControlName="country">
<option *ngFor="let country of countries" [value]="country.id">
{{ country.name }}
</option>
</select>
</form>

Angular dependent select boxes doesn't work

The first box works well. But the second one doesn't work. They depend on each other. And the error does not appear.
I can't try anything else because it doesn't any errors.
city.service.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class CityService {
constructor(private http:Http) { }
getCitys(){
return this.http.get("http://localhost:3003/api")
.map(response => response.json());
}
}
city.ts
export interface City
{
name: string,
value:number,
down: Down[]
}
export interface Down
{
name: string,
value:number,
places: Places[]
}
export interface Places
{
name: string;
pname:string;
unvan: string
}
city.component.ts
#Component({
selector: 'app-city',
templateUrl: './city.component.html',
styleUrls: ['./city.component.css']
})
export class CityComponent implements OnInit {
cityDatas: [];
downDatas: [];
placesDatas: [];
constructor(private cityService: CityService) { }
ngOnInit() {
this.cityService.getCitys().subscribe(d => {
this.cityDatas = d;
this.downDatas = d.down;
this.placesDatas = d.places });
}
}
city.component.html
<select [(ngModel)]="selectedData">
<option [ngValue]="null" selected disabled>First</option>
<option *ngFor="let data of cityDatas" [value]="data">
{{ data.name }}
</option>
</select>
<select [(ngModel)]="selectedDw" >
<option [ngValue]="null" selected disabled>Second</option>
<option *ngFor="let dw of downDatas" [value]="dw">
{{dw.name}}
</option>
</select>
And api json
[
{"name":"City1",
"value":1,
"down":
[{"name":"Down11",
"value":101,
"places":
[{"name":"Place111",
"pname":"JustPlace",
"unvan":"center"
},
{"name":"Place112",
"pname":"Jp",
"unvan":"center"
}]
},
{"name":"Down12",
"value":102,
"places":
[{"name":"Place121",
"pname":"Jp",
"unvan":"side"
},
{"name":"Place122",
"pname":"Jp",
"unvan":"side"
}]
}
]
},
{"name":"City2",
"value":2,
"down":
[{"name":"Down21",
"value":103,
"places":
[{"name":"Place211",
"pname":"Jp",
"unvan":"center"
},
{"name":"Place212",
"pname":"Jp",
"unvan":"center"
}]
},
{"name":"Down22",
"value":104,
"places":
[{"name":"Place221",
"pname":"JustPlace",
"unvan":"side"
},
{"name":"Place222",
"pname":"Jp",
"unvan":"side"
}]
}
]
}
]
When I choose the first one, I want the second to work. And I want the results displayed. But I couldn't run the second select box and the console didn't give any errors.
Why does not work? And how will it work?
downDatas is undefined, because d in the subscription is an array, not an object. Try to implement it in this way (after selecting selectedData in the first select, this data will be available in the second):
<select [(ngModel)]="selectedData">
<option selected disabled>First</option>
<option *ngFor="let data of cityDatas; index as i;" [value]="i">
{{ data.name }}
</option>
</select>
<select [(ngModel)]="selectedDw" >
<option [ngValue]="null" selected disabled>Second</option>
<option *ngFor="let dw of cityDatas[selectedData]?.down" [value]="dw">
{{ dw.name }}
</option>
</select>
stackblitz
You need implement change event of city select tag and update datasource for downDatas
onChange($event, cityid) {
let selectedcity = this.cityDatas.filter(c=>c.value == cityid)[0];
console.log(JSON.stringify(selectedcity))
this.downDatas = selectedcity.down;
}
HTML
<select [(ngModel)]="selectedData" #city (change)="onChange($event, city.value)">
Demo https://stackblitz.com/edit/angular-city-down?file=src/app/app.component.ts

Default selected checkbox

I want to ask about how I can set option to be default selected?
<form [formGroup]="form2">
<select formControlName="drop">
<option disabled>Choose one</option>
<option *ngFor="let example of examples" [value]="example.id" [disabled]="example.isDisabled" [selected]="example.isSelected">{{ example.name }}</option>
</select>
</form>
Component:
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
#Component({
selector: 'app-drop-down-list',
templateUrl: './drop-down-list.component.html',
styleUrls: ['./drop-down-list.component.css']
})
export class DropDownListComponent implements OnInit {
public form = new FormGroup({
drop: new FormControl('',
Validators.required,
),
});
public form2 = new FormGroup({
drop: new FormControl('',
Validators.required,
),
});
examples = [{
id: 1, name: 'Test1', isSelected: false, isDisabled: true,
},
{
id: 2, name: 'Test2', isSelected: true, isDisabled: false,
},
{
id: 3, name: 'Test3', isDisabled: false,
}
];
constructor() { }
ngOnInit() {
}
onSubmit(form) {
console.log(form);
}
}
I was searching on stack but I don't want to mix reactive forms with ngModel, also I don't wan't to use patchValue because It only set default value without choosing element in list. Thanks for help!
if you want option to be selected then do like this , just pass id value in your formcontrol intialization
public form2 = new FormGroup({
drop: new FormControl(this.examples[0].id,
Validators.required,
),
});
or if you dont want to initialization immediately and want later on then make use of setValue method, below is required when you are fecthing data from server and want to set value i just hard coded value just to show as example , you should replace with the value you get from server
form2.get('drop').setValue('1');
html should be as below no need of [selected]
<select formControlName="drop">
<option disabled>Choose one</option>
<option *ngFor="let example of examples" [value]="example.id" [disabled]="example.isDisabled" >{{ example.name }}</option>
</select>