Displaying objects dropdown from an array - Angular - html

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

Related

Refresh datalist in view after user finishes typing in textbox Angular 7

I am trying to refresh a datalist in the view after waiting for user to finish typing in the textbox and updating results. Tried with angular directives, tried with Observable and various timeouts and debounces and no luck. I ran out of options.
In the html file:
<input type="text" class="form-control" id="Other"
(keyup)="onKeySearch($event)" list="dynamicList" formControlName="Other"/>
<datalist id="dynamicList">
<option *ngFor="let employee of employeesList" [value]="employee.Name">
{{employee.Name}}</option>
</datalist>
in the .ts file:
public employeesList: EmployeeData[] = [];
timeout: any = null;
getEmployeesList(name : string) {
let empList: EmployeeData[] = [];
// get employees list from service
this.employeeService.getEmployeesList(name).subscribe((data: any) => {
empList = data;
console.log(empList)
})
return empList;
}
public onKeySearch(event: any) {
let empListt: EmployeeData[] = [];
clearTimeout(this.timeout);
var $this = this;
this.timeout = setTimeout(() => {
empListt = $this.getEmployeesList(event.target.value);
console.log(empListt)
}, 1000);
this.employeesList = empListt;
}
The problem is that the datalist is not updates after retrieving the data an populating the list. After it exists the method the list is again empty, thus no data to display.
I have added stackblitz example code with similar code as above (same behavior):
.ts file:
import { Component, VERSION, OnInit } from "#angular/core";
import { FormControl } from "#angular/forms";
import { distinctUntilChanged, debounceTime, tap } from "rxjs/operators";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
searchControl = new FormControl("");
message = "";
public employeesList: string[] = [];
ngOnInit() {
this.searchControl.valueChanges
.pipe(
tap(() => (this.message = "User is typing...")),
distinctUntilChanged(),
debounceTime(1000)
)
.subscribe(res => {
this.message = "User finished typing!";
this.employeesList.push('1');
this.employeesList.push('2');
this.employeesList.push('3');
});
}
}
.html file:
<input [formControl]="searchControl" list="dynamicList">
<datalist id="dynamicList">
<option *ngFor="let employee of employeesList">
{{employee}}</option>
</datalist>
<span> {{message}} </span>
The dropdown will be filtered according to the text you have entered. So, in the given example, since you have pushed 1,2 and 3 values into the list, the drop down will only list with the filtered value.
Eg. if you input 1, the drop down list will have 1 (which is the required functionality)
You can see this behavior clearly if you slightly change the test input as :
ngOnInit() {
this.searchControl.valueChanges
.pipe(
tap(() => (this.message = "User is typing...")),
distinctUntilChanged(),
debounceTime(1000)
)
.subscribe(res => {
this.message = "User finished typing!";
this.employeesList.push('Employee 1');
this.employeesList.push('Employee 2');
this.employeesList.push('Employee 3');
});
}
Now, when you search 'Employee', it will list all 3, and if you search 'Employee 1', it will list the required one entry only. (Which is the expected behavior)
Your formControl (called 'Other', for some reason) has an event that is emitted as an Observable on each change. You can subscribe to that event, and use the RxJS operator debounceTime() to specify how many milliseconds should it wait for the user to stop typing until the event is emitted.
I have created a simple DEMO, maybe it's easier to understand.
Good luck!

Async function is not working for me it's is showing error

**I have an issue while displaying categories.I am trying this by using
async
function but it is not showing data**
<div class="form-group">
<label for="category">Category</label>
<select id="category" class="form-control">
<option value=""></option>
<option *ngFor="let c of categories$ | async" [value]="c.$key">{{
c.name
}}</option>
</select>
</div>
I already tried this but it is not working
product-form.component.ts
export class ProductFormComponent {
categories$;
constructor(categoryService: CategoryService) {
this.categories$ = categoryService.getCategories();
}
}
And here i am create product data
save(product) {
this.productService.create(product);
console.log(product);
}
category.service.ts
**By using
.valueChanges
I am able to get data but it is not storing data in firebase db. It is showing undefined**
export class CategoryService {
constructor(private db: AngularFireDatabase) {}
getCategories() {
return this.db.list('/categories').valueChanges();
}
}
For creating product data and pushing it db i used this method
product.service.ts
export class ProductService {
constructor(private db: AngularFireDatabase) {}
create(product) {
return this.db.list('/products').push(product);
}
}
This is error i am getting
InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe'
List Categories:
Modify getCategories(). Add snapshotChanges() or valueChanges()
Try like this:
return this.db.list('/categories').snapshotChanges();
or,
return this.db.list('/categories').valueChanges();
Create Product:
$products: FirebaseListObservable<any[]>;
create(product) {
return this.$products.push(product);
}

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

Drop Down List in Angular 2 Model Driven Form

I have a model driven form in which I would like to add a drop down list containing several options. The options are from a pre-fetched list, and the model of the form is injected to the component. The form is loaded correctly: All the fields from the model are filled properly, abd the list of options for the drop-down list is also loaded correctly.
The only problem is that I can't set the selected value of the list, and it appears with an empty value at first.
Here, I am loading the HMOs list, then loading the patient, and only then creating the form.
All the values of the form (name, id, etc. which are omitted here) are loaded correctly into the form.
The drop-down list in the form is filled correctly: All HMOs are populating the list.
Still, the selected value in the list is missing, and the lost is loaded with no initial value.
For debugging purposes, I have replaced the boolean condition in the option tag: patient.hmo.uid == hmo.uid to a function call: isSelected(hmo).
This function essentially does the same comparison and returns its value, but first logs it. Indeed I see that the option with the correct hmo gets a true value and all other options get false values, meaning all data is loaded correctly.
Also, when I set the [selected]="true" (always to be true), I do see the change affects: The last option is selected (the default in HTML).
So where am I wrong? How should I set the selected option correctly?
Code for the component (all fields except HMO are omitted):
import {Component, Input, Inject, OnInit} from "#angular/core";
import {
FormGroup,
FormControl,
REACTIVE_FORM_DIRECTIVES,
Validators,
FormBuilder,
FormArray
} from "#angular/forms";
import {Patient} from "./patient";
import {PatientsService} from "./patients.service";
import {Hmo} from "../hmos/hmo";
import {HmosService} from "../hmos/hmos.service";
import {Doctor} from "../doctors/doctor";
import {DoctorsService} from "../doctors/doctors.service";
import {Router, ActivatedRoute} from "#angular/router";
import {Subscription} from "rxjs/Rx";
import {Response} from "#angular/http";
import {JavaDate} from "./java-date";
#Component({
moduleId: module.id,
selector: 'gy-patient-edit',
templateUrl: 'patient-edit.component.html',
directives: [REACTIVE_FORM_DIRECTIVES],
})
export class PatientEditComponent implements OnInit {
patientForm: FormGroup;
#Input() patient: Patient;
private hmos: Hmo[];
private patientUid: number;
private showForm: boolean = false;
constructor(#Inject(PatientsService) private patientsService: PatientsService,
#Inject(HmosService) private hmosService: HmosService,
#Inject(ActivatedRoute) private route: ActivatedRoute,
#Inject(FormBuilder) private formBuilder: FormBuilder) {
}
ngOnInit(): any {
this.subscription = this.route.params.subscribe(
(params: any) => {
this.patientUid = params['id']; //Getting the UID from the URL
}
);
this.hmosService.hmosChanged.subscribe(
(hmos: Hmo[]) => {
this.hmos = hmos; //Fetching available HMOs
}
);
this.hmosService.fetchHmos();
this.patientsService.fetchPatient(this.patientUid) //Fetching the Patient
.map((response: Response) => response.json())
.subscribe((data: Patient) => {
this.patient = data;
this.restartForm(); //Only required so the form will ne initialized only after the patient is received from the server
});
}
restartForm(){
this.patientForm = this.formBuilder.group({
hmo: [this.patient.hmo]]
});
this.showForm = true;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Code for the HTML form:
<div class="row" *ngIf="showForm">
<div class="col-xs-12" *ngIf="showForm">
<form [formGroup]="patientForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="hmo">HMO</label>
<select formControlName="hmo" id="hmo">
<option *ngFor="let hmo of hmos"
[value]="hmo.uid" [selected]="patient.hmo.uid == hmo.uid">
{{hmo.name}}
</option>
</select>
</form>
</div>
</div>
Code for Patient:
import {Hmo} from "../hmos/hmo";
export class Patient {
constructor(public hmo: Hmo) {
}
}
Code for Hmo:
export class Hmo{
constructor(public uid: number, public name: string){}
}
The selected option is calculated by comparing the <option>'s value with <select>'s value. In light of that, to mark an <option> as selected, we need to make sure the wrapping <select> is containing the same value, which in turn requires the correct value of the corresponding form control in your model.
Your code can be slightly modified as follow:
restartForm(){
this.patientForm = this.formBuilder.group({
hmo: [this.patient.hmo.uid]
});
this.showForm = true;
}
And Template:
<select formControlName="hmo" id="hmo">
<option *ngFor="let hmo of hmos"
[value]="hmo.uid">
{{hmo.name}}
</option>
</select>

Angular2: How do you pass a selected item from a HTML datalist element back to the component?

I have simple component which includes a to dreate a drop-down box. This is list is filled with the results from a Web API call. For display purposes I only use two fields of the item. However, once an element has been selected I need to do stuff with all the other fields. How do I pass the entire element back to the component?
Really would appreciate any help.
<h1>Get Locations</h1>
<div>
<div>
<input list="browsers" name="browser" #term (keyup)="search(term.value)">
<datalist id="browsers">
<option *ngFor="let item of items | async" >
{{item.code + " " + item.description}}
</option>
</datalist>
</div>
<input type="submit" value="Click" (click)="onSelect(item)" />
</div>
The component code is as follows:
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { LocationService } from './location.service';
import {Location} from './location.component';
import './rxjs-operators';
#Component({
selector: 'lesson-08',
templateUrl: './views/lesson08.html',
providers: [LocationService]
})
export class Lesson08 implements OnInit{
constructor(private locationService: LocationService) { }
aLoc: Location;
ngOnInit() {
this.aLoc = new Location();
}
errorMessage: string;
locations: Location[];
mode = 'Observable';
displayValue: string;
private searchTermStream = new Subject<string>();
search(term: string) {
this.searchTermStream.next(term);
}
onSelect(item: Location) {
// do stuff with this location
}
items: Observable<Location[]> = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((term: string) => this.locationService.search(term));
}
The (click) event calling the method should be on the option selected. Your declared "item" is only known in the scope of the *ngFor, so on the levels of its children. You declared it on a too high level.