Value not showing for input field using one way binding angular2 - html

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.

Related

Angular 2+: Input decorator not reflecting checkbox

I have a component
timeBoxSelector
HTML:
<input type="checkbox" [(ngModel)]="selected">
TS:
#Component({
...
})
export class TimeboxComponent implements OnInit {
#Input() selected: boolean;
constructor() {}
ngOnInit() {
console.log('Selected: ', this.selected);
}
}
Now, when I create
<app-timebox selected="false"><app-timebox/>
<app-timebox selected="true"><app-timebox/>
In both cases, the checkbox initially appears as selected. Why is this the case, and how can I fix it?
In both cases, you are binding non empty strings, which are truthy values. Use the brackets notation to tell Angular that the bound value is to be evaluated as a Javascript expression:
<app-timebox [selected]="false"><app-timebox/>
<app-timebox [selected]="true"><app-timebox/>

Angular 5: ngModel binding on select element doesn't update

I have this markup for a select element:
<select type="submit" ([ngModel])="selectedValue" #item (change)="onSelectItem(item.value)">
<option>Pick an option</option>
<option *ngFor="let object of objects">{{ object.value }}</option>
</select>
When I update the ngModel binding from typescript, nothing happens. Essentially I am just doing this, in the component:
ngOnInit() {
this.selectedValue = 'something' // One of the options from the list of objects
}
However, nothing happens.
The value I am trying to update it to, are in the list of objects (in the *ngFor) - if that matters.
Change ([ngModel])="selectedValue" to [(ngModel)]="selectedValue"
Just like the docs say:
Visualize a banana in a box to remember that the parentheses go inside the brackets.
Also you do not need the (change) listener if you are using ngModel. You can split your two way binding into [ngModel] and (ngModelChange)
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<select type="submit" [ngModel]="selectedValue" (ngModelChange)="onSelectedChange($event)">
<option *ngFor="let option of options">{{ option }}</option>
</select>
{{ selectedValue }}
` ,
styleUrls: ['./app.component.css']
})
export class AppComponent {
selectedValue = 1;
options = [1,2,3]
onSelectedChange(value: number) {
// do something else with the value
console.log(value);
// remember to update the selectedValue
this.selectedValue = value;
}
}
Live demo
Please change the definition of ([ngModel]) to [(ngModel)] and you should initialize the objects values before assign the value in selectedValue object

Angular2 dynamically generating Reactive forms

I have a concept question and would like some advice.
So I have a component, myFormArray, which is a reactive form. It takes in an input array, and creates a number of FormControls accordingly.
#Component({
selector: 'myFormArray',
templateUrl: 'formarray.component.html'
})
export class FormArrayComponent{
#Input() classFields: any[];
userForm = new FormGroup();
ngOnInit(){
// psuedocode here, but I know how to implement
for (# of entries in classFields)
userForm.FormArray.push(new FormControl());
}
Now, in my parent html, I will be dynamically generating multiple myFormArrays. If that is confusing, assume I'm doing this:
<myFormArray [classFields] = "element.subArray"/>
<myFormArray [classFields] = "element2.subArray"/>
<button (click) = "save()"> //I don't know how to implement this!
And at the very end of the page, I want a save button, that can somehow grab all the values the user inputs in to all the forms, and pushes all this data to an array in a Service component. I'm not sure exactly how to do this part. Note that I don't want individual submit buttons for each dynamically generated form component.
How would I implement this functionality? Thanks!
Your start is good, but you have to write your source code differently.
Instead of this example app.components.ts is main component and my-array.component.ts is child component.
Our test data
classFields1: any[] = ['firstname', 'lastname', 'email', 'password'];
classFields2: any[] = ['country', 'city', 'street', 'zipcode'];
Step 1. Use FormBuilder for form creation (app.component.ts)
You must import FormBuilder and FormGroup from #angular/forms like this:
import { FormBuilder, FormGroup } from '#angular/forms';
and then define in constructor:
constructor(private formBuilder: FormBuilder) { }
Step 2. Define new empty FormGrooup
Now you can define new empty FormGroup in ngOnInit like this:
ngOnInit() {
this.myForm = this.formBuilder.group({});
}
Step 3. Create FormControls dynamically (app.component.ts)
Now you can start with dynamically creation of your FormControls by iteration of classFields. For this I would recommend to create own function. This function gets two parameter: arrayName and classFields. With arrayName we can set custom name of our FormArray-control. classFields-Array we will use for iteration. We create constant variable for empty FormArray, which we called arrayControls. After this we iterate over classFields and create for each element FormControl, which we called control, and push this control into arrayControls. At the end of this function we add our arrayControls to our Form with custom name by using arrayName. Here is an example:
createDynamicArrayControls(arrayName: string, classFields: any[]) {
const defaultValue = null;
const arrayControls: FormArray = this.formBuilder.array([]);
classFields.forEach(classField => {
const control = this.formBuilder.control(defaultValue, Validators.required);
arrayControls.push(control);
})
this.myForm.addControl(arrayName, arrayControls);
}
Import FormControl and FormArray from #angular/forms. Your import line should be like this:
import { FormBuilder, FormGroup, FormArray, FormControl } from '#angular/forms';
Now call createDynamicFormControls-Function in ngOnInit.
Step 4. HTML Template for this dynamic Form (app.component.html)
For this example I create following template:
<h1>My Form</h1>
<form [formGroup]="myForm">
<div formGroupName="test1">
<app-my-array [classFields]="classFields1" [arrayFormName]="myForm.controls.test1"></app-my-array>
</div>
<div formGroupName="test2">
<app-my-array [classFields]="classFields2" [arrayFormName]="myForm.controls.test2"></app-my-array>
</div>
<button type="button" (click)="saveForm()">Submit</button>
</form>
Here we have new div element with formGroupName. This group name is our arrayName in our form. We give our form arrays via #Input to my-array.component.
Step 5. MyArrayComponent
Now this component is very simnple:
import { Component, OnInit, Input } from '#angular/core';
import { FormGroup } from '#angular/forms';
#Component({
selector: 'app-my-array',
templateUrl: './my-array.component.html',
styleUrls: ['./my-array.component.css']
})
export class MyArrayComponent implements OnInit {
#Input() classFields: any[];
#Input() arrayFormName: FormGroup;
constructor() { }
ngOnInit() { }
}
Here we have only two #Input varibales. (I know, this variable can have a better names :-) ).
Step 6. HTML for MyArrayComponent
<div [formGroup]="arrayFormName">
<div *ngFor="let class of arrayFormName.controls; let index = index;">
<label [for]="classFields[index]">{{ classFields[index] }}</label>
<input type="text" [id]="classFields[index]" [formControlName]="index" />
</div>
</div>
<br>
And here is working example on Stackblitz: https://stackblitz.com/edit/angular-wawsja
If you have some question ask me in comments or read the Angular documentation abour Reactive Forms here.

Angular 4 firebase dropdown select tag option

I am using Angular 4 and firebase. I'm trying to build a dropdown selector for a list of properties.
Once a property is selected from the dropdown list, the property location should appear in another input field below.
properties.component.html
<select [(ngModel)]="selectedProperty" (change)="onSelect($event, property)">
<option>--select property--</option>
<option *ngFor="let property of properties">{{property.propertyName}}</option>
</select>
<div *ngIf="selectedProperty">
<label >Location </label>
<input type="text" value="{{selectedProperty.location}}">
</div>
properties.component.ts
import { Component, OnInit } from '#angular/core';
import { PropertyService } from './../services/property.service';
import { Property } from './../models/property';
import { Observable } from 'rxjs/Observable';
#Component({
selector: 'app-property-list',
templateUrl: './property-list.component.html',
styleUrls: ['./property-list.component.scss']
})
export class PropertyListComponent implements OnInit {
properties: Observable<Property[]>;
selectedProperty: Property;
constructor(private propertyService: PropertyService) {}
ngOnInit() {
this.propertyService.getProperties().subscribe(properties => {
this.properties = properties;
})
}
onSelect(event, property: Property){
this.selectedProperty = property;
}
}
I am able to select the property from the dropdown list but the property location does not appear on the input field. I'll appreciate your help.
Instead of value use ngModel
<div *ngIf="selectedProperty">
<label >Location </label>
<input type="text" [(ngModel)]="selectedProperty.location">
</div>
By default selecting option from dropdown selects whatever value provided in selected option tag. So when you select any value in dropdown it putspropertyName inside respective ngModel.
As you want to select the whole object use ngValue in option, what that will do is, when user selects an option it will take down ngValue object value and assigned it to ngModel of select field.
<option [ngValue]="property" *ngFor="let property of properties">
{{property.propertyName}}
</option>

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