Can I get values from a dynamically created multiple select element? - html

Can I get values from a dynamically created multiple select element?
I have fixed categories of products which I intend to load dynamically from an API. Each one of those categories has an array with the options I want to be able to select. I'm stuck with it, I cant retrieve the selected values, and I recently read something that says that we can't get the selected values from a dynamically created select with angular-material. Is that true?
I've tried getting the elements by id using jQuery and have tried multiple ways of getting the selected values.
On my menu-service, which I didn't show, I print form.values but it is empty'; it should contain the selected options, or the opcEscolhidas array should contain the selected values.
Here is my template:
<div id="main" class="row">
<h2>Selecione os itens do Cardápio</h2>
<form (submit)="onCreateMenu(form)" #form="ngForm" id="items-form">
<ul class="collapsible" data-collapsible="accordion">
<li *ngFor="let categoria of categorias">
<div class="collapsible-header">{{categoria.nome}}</div>
<div class="collapsible-body">
<div class="opGroup">
<mat-form-field>
<mat-label>{{categoria.nome}}</mat-label>
<mat-select ([value])="opcEscolhidas" multiple>
<mat-option *ngFor="let opcao of categoria.opcoes" [value]="opcao">{{opcao}}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</li>
</ul>
<button type="submit" class="btn">Montar Cardápio</button>
</form>
</div>
and here is my component:
import { Component, OnInit } from '#angular/core';
// import * as $ from 'jquery';
import { FormControl } from '#angular/forms';
import { MenuService } from '../menu.service';
import { NgForm } from '#angular/forms';
#Component({
selector: 'app-create-menu',
templateUrl: './create-menu.component.html',
styleUrls: ['./create-menu.component.css']
})
export class CreateMenuComponent implements OnInit {
// feijao = "";
// arroz = "";
// macarrao = "";
// carne = "";
// acomp = "";
// salada = "";
opcEscolhidas = [];
categorias = [
{
"id":1,
"nome":"Feijão",
"opcoes": ["Carioca", "Preto", "Verde", "Macassa"]
},
{
"id":2,
"nome":"Arroz",
"opcoes": ["Branco", "Refogado", "Integral"]
},
{
"id":3,
"nome":"Macarrão",
"opcoes": ["Alho e Óleo", "Molho de tomate", "Manteiga e
cebola", "Molho branco"]
},
{
"id":4,
"nome":"Carne",
"opcoes": ["Bisteca/porco", "Carne de sol", "Peito de
frango", "Coxa de frango"]
},
{
"id":5,
"nome":"Acompanhamentos",
"opcoes": ["Purê", "Farofa", "Vinagrete", "Batata frita"]
},
{
"id":6,
"nome":"Salada",
"opcoes": ["Alface", "Tomate", "Rúcula", "Repolho"]
}
];
public menuService;
constructor(menuService: MenuService) {
this.menuService = menuService;
}
ngOnInit() {
}
onCreateMenu(form: NgForm) {
this.menuService.createMenu(form);
}
On my menu-service, which I didnt show, I print form.values, but it is empty, and it should contain the selected options. Or my "opcEscolhidas" array should contain the selected values.strong text

You need to bind ngModel to the control. Go through this video,
https://www.youtube.com/watch?v=hAaoPOx_oIw

Try this
<select
class="custom-select"
name="overallRating"
[ngModel]="inspectionGeneralInfo?.OverallRating">
<option [value]="-1">
Select a rating
</option>
<option
*ngFor="let orc of inspectionGeneralInfo?.OverallRatingChoices"
[value]="orc.AnswerCode">
{{orc.AnswerDescription}}
</option>
</select>

Related

Multiple Select component for Angular with list style

I need a select component like
The problem is they don't have it in Material Angular, so I tried using default HTML select inside the component. It works fine until I tried to destroy the view of the HTML select(for example when you redirect to other page), it will freeze the whole page for a couple of seconds(the larger the list the longer it will freeze).
First, anyone know the reason why Angular takes a while to destroy non material angular component? Then does anyone have a solution whether to make the freeze gone or appoint me to select component library that could be use in Angular perfectly? I really need the support of being able to select multiple items with click + shift
Here's my component code:
HTML:
<div class="chart">
<div class="toolbar">
<div class="row">
<i *ngIf="multiple" (click)="resetFilter()" class="option material-icons left">refresh</i>
<h4>Sample Id</h4>
<span class="option right"></span>
</div>
</div>
<div class="content">
<select *ngIf="!showSampleCSV" [multiple]="multiple" [size]="100" class="samples-list" [(ngModel)]="selectedSamples" (ngModelChange)="onSelect($event)">
<option *ngFor="let sampleID of sampleIDs" [value]="sampleID">{{sampleID}}</option>
</select>
<app-samples-text *ngIf="showSampleCSV" [samples]="selectedSamples" [multiple]="multiple" (filterSamples)="filterCSV($event)"></app-samples-text>
</div>
</div>
TS:
import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy, OnDestroy } from '#angular/core';
#Component({
selector: 'app-samples-list',
templateUrl: './samples-list.component.html',
styleUrls: ['./samples-list.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SamplesListComponent implements OnInit, OnDestroy {
#Input() sampleIDs : string[] = [];
#Input() showSampleCSV : boolean;
#Input() selectedSamples : string[];
#Output() onSelectSamples = new EventEmitter<string[]>();
#Output() onUpdateSamples = new EventEmitter<string[]>();
#Input() multiple: boolean = true;
size = this.sampleIDs.length;
constructor() { }
ngOnInit() {
}
resetFilter() {
this.onSelectSamples.emit(this.sampleIDs);
}
onSelect(samples){
this.onSelectSamples.emit(samples);
}
filterCSV(samples){
this.onUpdateSamples.emit(samples.map(sample => sample.trim()));
}
ngOnDestroy() {
}
}
Problem illustration on stackblitz https://stackblitz.com/edit/angular-qojyqc?embed=1&file=src/app/app.component.html
Material does provide an option for multi select values
<mat-form-field>
<mat-label>Toppings</mat-label>
<mat-select [formControl]="toppings" multiple>
<mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-
option>
</mat-select>
</mat-form-field>
For more information go Here

Angular - View prints old values along with new values

Using Angular. I have a variable modelResponse which gets updated and the new value prints. But along with it, in the html, all of its old values are also printed.
I have used the 2 way data binding on modelResponse in the html [(ngmodel)]= {{{{modelResponse}}}}
home-page.component.html
<span><a mat-raised-button style="margin-left:5rem" color="accent" (click)=show()><b>Score the
Model</b></a></span>
<br>
<br>
<div class=" example-container" *ngIf=showdirectPredict>
<form
style="background-color: cornsilk; size: 0.8rem; font-style: italic;font-family: Arial, Helvetica, sans-serif;font-size: 0.8rem;border-top-right-radius: 0.5rem;border-bottom-left-radius: 0.5rem;border-bottom-right-radius: 0.5rem;border-top-left-radius: 0.5rem"
(ngSubmit)="makepredictrequest()" #myForm="ngForm">
<p>
<br>
<b style="margin-left: 1rem;">Enter the Embedding Dimensions</b>
<br>
<br>
<mat-form-field class="fields" appearance="fill" style="margin-left:1rem">
<mat-label>Enter ED d0</mat-label>
<input matInput placeholder="d0" [(ngModel)]="dee0" name="d0-dimension">
<!-- <mat-hint>We need your name for the ID badge ;) !</mat-hint>-->
</mat-form-field>
<button mat-raised-button type="submit" style="margin-left:2rem" color="primary" md-raised-button>Submit</button>
<button mat-raised-button type="submit" style="margin-left:1rem" color="primary" (click)=dontshow()
md-raised-button>Close</button>
<b style="margin-left: 10rem;"> RESULT : This Non-CRU customer belongs to Cluster Number : {{modelResponse}} </b>
</p>
<br>
<br>
</form>
home-page.component.ts
import { Component, OnInit } from '#angular/core';
import { User } from '../User.model';
import { Embeddings } from '../embeddings.model';
import { CommonModule } from '#angular/common';
import { BrowserModule } from '#angular/platform-browser';
import { AccountService } from '../account.service';
import { D0embed } from '../d0embed';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
showdirectPredict = false;
modelResponse: any;
lastResponse: any;
modelname: any;
dee0: any;
ed0: D0embed;
d0: D0embed[] = [];
embedding: Embeddings = new Embeddings();// initiate all arrays in this model via constructor or here
modelResponseString: any;
constructor(private serv: AccountService) {
}
ngOnInit() {
}
makepredictrequest() {
console.log('In makepredictrequest()');
this.ed0 = this.dee0;
this.embedding.d0.push(this.ed0)
this.serv.scoreModel(this.embedding).subscribe((data: any) => {
this.modelResponse = data['value'];
console.log('Request finished');
this.lastResponse = this.modelResponse[this.modelResponse.length - 1];
console.log('The data received is :' + this.lastResponse);
});
}
show() {
this.showdirectPredict = true;
}
dontshow() {
this.showdirectPredict = false;
}
}
Using
RESULT : This Non-CRU customer belongs to Cluster Number : {{modelResponse}}
gives me for example,
On clicking scoreModel() first time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5
On clicking scoreModel() second time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5, 13
On clicking scoreModel() third time ,
RESULT : This Non-CRU customer belongs to Cluster Number : 5, 13, 2
All I want to see everytime is ofcourse the current value of the Cluster number, i.e the modelResponse.
It seems that modelResponse field is an array of numbers and the lastResponse is the last number in that array, i.e. the value that you need. But template binding looks like This Non-CRU customer belongs to Cluster Number : {{modelResponse}}.
Try changing it to This Non-CRU customer belongs to Cluster Number : {{lastResponse}}.

Target a checkbox in *ngfor checkbox list

I have a list of checkboxes that are binded to an object in my component typescript file, I want it to check/uncheck on the list when user clicks on the checkbox, but for some reason, it only checks the and uncheck the first checkbox on the list and not the one that user has clicked on.
Here is the code below:
<div>
<ul class="reports-container">
<li *ngFor="let item of data.reports" [class.active]="selectedReport==item" >
<input type="checkbox" id="{{'savedreport'+i}}" class="k-checkbox" [checked]="item.IsSubscribed" [value]="item.IsSubscribed"(change)="onChkBoxChange($event,item)" />
</li>
</ul>
</div>
here is the typescript function:
onChkBoxChange(event, item: SavedReport) {
item.IsSubscribed = event.target.checked;
}
when I put a breakpoint it always passes in the first item from the list, any thoughts?
As #Michael Beeson suggested I used two-way binding on my checkbox value, that solved the problem, so the code is now:
<div>
<ul class="reports-container">
<li *ngFor="let item of data.reports" [class.active]="selectedReport==item" >
<input type="checkbox" id="{{'savedreport'+i}}" class="k-checkbox" [checked]="item.IsSubscribed" [(value)]="item.IsSubscribed"(change)="onChkBoxChange($event,item)" />
</li>
</ul>
</div>
Advice: use angular forms for this that's why forms exist in angular is
gonna simplify the whole case like yours.
I made a stackblitz to show you how to occur this by using reactive forms and FormArray in angular you even can use template driven forms if you want to, the point is using forms feature in angular gonna save your time and effort when you encounter such a case.
html
<div>
<ul class="reports-container">
<form [formGroup]="checkboxForm">
<div formArrayName="checkboxList" *ngFor="let item of data; let i = index">
<label>
<input type="checkbox" id="{{'savedreport'+i}}" [name]="item" [formControlName]="i" class="k-checkbox" (change)="onChkBoxChange($event, i)" />
{{item}}
</label>
</div>
</form>
</ul>
</div>
TS
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, FormArray } from '#angular/forms';
#Component({
selector: '...',
templateUrl: '...',
styleUrls: [ '...' ]
})
export class AppComponent implements OnInit {
data: string[] = ['data1', 'data2', 'data3', 'data4'];
checkboxForm: FormGroup;
ngOnInit() {
this.checkboxForm = new FormGroup({
checkboxList: new FormArray([])
});
this.arrayOfCheckboxs();
}
private arrayOfCheckboxs() {
const formArr = this.checkboxForm.get('checkboxList') as FormArray;
this.data.forEach(item => {
formArr.push(new FormControl());
});
}
onChkBoxChange(e: MouseEvent, idx: number) {
console.log(`${(<HTMLInputElement>e.target).name}: ${this.checkboxForm.get('checkboxList').value[idx]}`);
}
}

Value not showing for input field using one way binding angular2

Objective: Get a collection of values based on the dropdown selection and place them in hidden input fields to be included in my model;
The relative html:
<select class="selectFoo" (change)="onSelect($event.target.value)" name="FooName" ngModel>
<option selected="selected">--Select--</option>
<option *ngFor="let foo of foos" [value]="foo.ID">{{foo.Name}}
</option>
</select>
<input type="hidden" [value]="fooAddress" name="FooAddress" ngModel/>
In the code above I called a function named OnSelect to get the data about the selected foo. The foos are populated using a webservice call. Here is the snippet from my ts file.
import { Component, OnInit } from '#angular/core';
import { Foo } from './model';
import { DataService } from './data.service';
#Component({
moduleId: module.id,
selector: 'add-on',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
foos : Foo[];
selectedFoo: Foo;
fooAddress: string;
onSelect(fooID){
this.selectedFoo = null;
for(var i = 0; i < this.foos.length; i++)
{
console.log(this.foos[i].ID);
if(this.foos[i].ID == fooID){
this.selectedFoo = this.foos[i];
this.fooAddress = this.selectedFoo.Address.toString();
}
}
}
}
I originally tried one way binding my value to the selectedFoo but I was getting an error indicating my Address value wasn't defined. I noticed I could set the value equal to selectedFoo and it didn't error. So i created a new variable that was set to the fooAddress based on the selected foo. I get no value even though while stepping through the code I see it has a value.
How can I get my value to populate so I can use it in my model? Let me know if I need to provide anything else.
Thanks!
If I am correctly understanding what you are after then something like this would work:
<select name="FooName" [(ngModel)]="selectedFoo">
<option>--Select--</option>
<option *ngFor="let foo of foos" [ngValue]="foo" >{{foo.Name}}</option>
</select>
<input type="hidden" [value]="selectedFoo?.Address" name="FooAddress" />
//Assuming your 'foo' items are e.g. { ID: 1, Name: 'Hello', Address: '123 Hello St'}
Here you can bind the Address property of the selectedFoo directly to your hidden input field, rather than needing to handle the (change) event.

setting display of select in angular 2

I am trying to set the display of select tag to a value obtained through another call. But I am not able to do so even after trying [selected] ,[ngValue],[value],etc.
<select class="form-control" [(ngModel)]="selectedRegion" name="Region" (ngModelChange)="onRegionChange(selectedRegion)" val="true" id="cloud-region" >
<option *ngFor="let region of regions" [selected]="selectedRegion.Name===region.Name?'region.Name':null">{{region.Name}}</option>
</select>
I set the value of "selectedRegion" after obtaining data through a http response in an Observable. I basically want to display the region that is received in another call as the selected display of select out of a pre-decided array which also contains this value.
Tried it in this plunker. Couldn't do it.
https://plnkr.co/edit/njGlIV?p=preview
Thanks.
I believe you're missing a [value] attribute on your <option>
<select
class="form-control"
[(ngModel)]="selectedRegion" name="Region"
(ngModelChange)="onRegionChange(selectedRegion)"
val="true"
id="cloud-region">
<option
*ngFor="let region of regions"
[value]="region.Name"
[selected]="selectedRegion.Name===region.Name?'region.Name':null">{{region.Name}}</option>
</select>
I don't think selected is actually needed if you've already tied up your select element with a model. The reason why your select isn't reflecting because your options have no value.
UPDATED:
Based on your plunkr, I've added a simulated http call to retrieve a value from an Observable. Once i've received a value from the stream, I immediately updated my model.
//our root app component
import {Component, Directive, Output, EventEmitter, Input, SimpleChange} from 'angular2/core'
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
//import 'rxjs/Rx';
#Component({
selector: 'my-app',
template:`
<h1>Selecting Number</h1>
<select type="number" [(ngModel)]="levelNum" (ngModelChange)="toNumber()">
<option *ngFor="let level of levels" [ngValue]="level.num">{{level.name}}</option>
</select>
{{levelNum}}
`,
})
export class AppComponent {
levelNum:number = 0;
levels:Array<Object> = [
{num: 0, name: "AA"},
{num: 1, name: "BB"}
];
ngOnInit(){
this.fakeHttpCall()
.subscribe(res => {
this.levelNum = res;
});
}
toNumber(){
this.levelNum = +this.levelNum;
console.log(this.levelNum);
}
fakeHttpCall(){
let request = new Observable(
obs => {
let timeout = setTimeout(() => {
obs.next(1);
obs.complete();
clearTimeout(timeout);
},2000);
}
);
return request;
}
}