I'd like to link radio buttons inside a form to an object, i cant get it to work!
I am linking ngModel to a variable of type string that is called presentation
I dont know what am I missing? even when i copy a working example it wont work in my form!
here is part of my form that I think is dysfunctional:
HTML:
<div class="uk-margin-large-right">
<div class="uk-flex-inline ">
<span class="uk-form-label uk-margin-small-right uk-text-bold "> Presentation </span>
<label class="uk-margin-medium-right">
<input class="uk-radio " type="radio" name="radio1" value="Cephalic" [(ngModel)]="presentaion"> Cephalic </label>
<label class="uk-margin-medium-right">
<input class="uk-radio" type="radio" name="radio1" value="Breech" [(ngModel)]="presentaion"> Breech </label>
<label class="uk-margin-medium-right">
<input class="uk-radio" type="radio" name="radio1" value="Transverse lie" [(ngModel)]="presentaion"> Transverse lie </label>
</div>
<p>this is {{presentation}}</p>
</div>
Typescript:
import { Component, OnInit } from '#angular/core';
import { CommService } from '../services/comm.service';
#Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {
user = {
Doctor: '',
Patient: '',
Type:'',
Report: ''
};
presentation:'';
constructor(private CommService: CommService) { }
ngOnInit() {
this.CommService.setData(this.user);
console.log(this.presentation);
}
}
Declare it like this if you want to give it initial value
presentaion:string = 'Cephalic';
log() { // log the value to console
console.log(this.presentaion)
}
Template
<p>this is {{presentaion}}</p>
<button (click)="log()">Log the value to console</button>
in your example there was a typo with the property name <p>this is {{presentation}}</p> just change it to presentaion
stackblitz example
Related
I have a problem with getting values of checkbox in angular. Here is the snippet:
<div class="list-group-item" *ngFor="let ticket of tickets">
<input
type="checkbox"
[name]="ticket.id"
[id]="ticket.id"
[value]="ticket.id"
formControlName="ticketTypes"
/>
<label for="{{ ticket.id }}">{{ ticket.name }}</label>
</div>
I am getting above checkbox's value as true. How to get checkbox value correctly ?
Here is a stackblitz
You can use (change) which fires every time when change detects on the input element and then write a custom logic to get the checked items from list, for example:
HTML:
<div class="list-group-item" *ngFor="let ticket of tickets">
<input type="checkbox" [name]="ticket.id" [id]="ticket.id" [value]="ticket.id" (change)="onCheck(ticket.id)"/>
<label for="{{ ticket.id }}">{{ ticket.name }}</label>
</div>
<pre>{{tickets | json}}</pre>
TS Code:
import { Component } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
tickets = [{ id: 1, name: "Test1" }, { id: 2, name: "Test2" }];
checkedTickets = [];
onCheck(evt) {
if (!this.checkedTickets.includes(evt)) {
this.checkedTickets.push(evt);
} else {
var index = this.checkedTickets.indexOf(evt);
if (index > -1) {
this.checkedTickets.splice(index, 1);
}
}
console.log(this.checkedTickets);
}
}
Working Demo
In such scenarios better/recommended to use formArray if you are dealing with the form or you can use simply ngModel two way data binding of Angular.
<form [formGroup]="form" (submit)="submit(form.value)">
<div *ngFor="let s of addOns.controls; let j=index">
<input type="checkbox" [formControl]="s"/> {{user1.addOns[j].name}}
</div>
</form>
Also simply formControlName i.e single control is generally used while dealing with Radio Buttons because in that case user can select always single value but here in case of checkboxes you can select multiple entries as well, which is designed like this, So you might use array in that case like above in my example.
Working Example
Or in case you want to use ngModel you can use it like this -
<ul>
<li *ngFor="let item of list">
<input type="checkbox" [(ngModel)]="item.checked">{{item.title}}
</li>
</ul>
Working Example
When I am using reactive forms and try to access the same control in multiple Inputs it looks like it's only a one-way-data-binding (input-to-model).
If I edit an input it will update the model correctly but it will not refresh the other input as well.
<input type="text" formControlName="test" id="in1">
<input type="text" formControlName="test" id="in2">
My work-a-round is to add the following line to both inputs:
(change)="form.controls.test.setValue(form.controls.test.value)
But to be honest this looks like a pretty bad solution. Am I doing anything wrong here? What is the correct way to archive this?
https://plnkr.co/edit/yALzCIHgOA463OvGi5rP
I don't sure why you need exactly 2 fields with same formControlName but a solution could be - Create custom angular element.
#Component({
selector: 'custom-element',
templateUrl: `
<input type="text" [(ngModel)]="value">
<input type="text" [(ngModel)]="value">
`,
styleUrls: ['./custom-element.component.css']
})
export class CustomElementComponent implements ControlValueAccessor
#Input() value: any
writeValue(value: any) {
// Some if statements
this.value = value;
}
registerOnChange(fn: Function) {
// your code here
}
registerOnTouched(fn: Function) {
// your code here
}
And in the parent component template
<custom-element formControlName="fieldname"></custom-element>
For more details (and deeper explanation), you can check https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
You can use ngModel:
<div>
<form [formGroup]="form">
<h2>Test = {{form?.controls.test.value}}</h2>
1. <input type="text" formControlName="test" [(ngModel)]="test">
2. <input type="text" formControlName="test" [(ngModel)]="test">
3.
<button type="button" (click)="form.controls.test.setValue('manual')">change with setValue</button>
</form>
</div>
The two-way binding syntax is really just syntactic sugar for a
property binding and an event binding
For example:
<app-sizer [(size)]="fontSizePx"></app-sizer>
Is equal to:
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
CODE EXAMPLE
So I have a simple login component created with angular like so.
<div class="form">
<form (submit) = "loginUser($event)">
<input type="text" placeholder="username"/>
<input type="password" placeholder="password"/>
<button type = "submit">login</button>
</form>
</div>
On click of this button I want to be able to print the data to the console which is why I added this functionality.
<form (submit) = "loginUser($event)">
This is what my .ts file looks like for that same component.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-login-form',
templateUrl: './login-form.component.html',
styleUrls: ['./login-form.component.css']
})
export class LoginFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
loginUser(e){
var username = e.target.elements[0].value;
var password = e.target.elements[1].value;
console.log(username,password);
}
}
When I look at the console I don't see the user name and password that was entered. Am I doing something wrong?
<form class="k-form" (ngSubmit)="loginUser()>
<input type="text" [(ngModel)]="username" name="username" placeholder="username">
<input type="password"[(ngModel)]="password" name="password" placeholder="password">
</form>
Component
username: string;
password: string;
loginUser(){
console.log(this.username,this.password);
}
Upon adding e.preventDefault() to the function it seems to work as expected
Please see the following examples. I have loaded jquery and jquery-steps into the project already and it is working. However after rendering the view, changing the data in the input boxes doesn't update the values in the form group mainForm. I believe the reason is that jquery-steps dynamically removed and reconstructed the html for the form, and so the form group doesn't link to the DOMs anymore.
Is there any way to re-bind FormGroup mainForm to the DOMs after jquery-steps reconstructed the html?
I read about ComponentResolver and ViewContainerRef, is it where it should use those? Could you give me an example how to use those in this situation?
Thank you!
<pre>{{ mainForm.value | json }}</pre>
<form [formGroup]="mainForm" id="mainForm" action="#">
<h1>Account</h1>
<div>
<label for="userName">User name *</label>
<input formControlName="userName" type="text" class="required">
<label for="password">Password *</label>
<input formControlName="password" type="text" class="required">
<label for="confirm">Confirm Password *</label>
<input formControlName="confirm" type="text" class="required">
<p>(*) Mandatory</p>
</div>
<h1>Finish</h1>
< div>
<input formControlName="acceptTerms" type="checkbox" class="required">
<label for="acceptTerms">I agree with the Terms and Conditions.</label>
</div>
</form>
import {Component, AfterContentInit} from "#angular/core";
import {FormBuilder, Validators, FormGroup} from "#angular/forms";
#Component({
templateUrl: 'main-view.template.html'
})
export class MainViewComponent implements AfterContentInit {
private mainForm: FormGroup;
constructor(private formBuilder: FormBuilder) {
this.mainForm = this.formBuilder.group({
userName: ['', Validators.required],
password: ['', Validators.required],
confirm: ['', Validators.required],
acceptTerms: ['', Validators.required],
});
}
ngAfterContentInit() {
$("#mainForm").steps();
}
}
The main reason why that is not working is that jquery-steps plugin removes your html markup.
Using jquery in angular2 is bad idea but if you want to get it working i can offer you slightly modify the library
jquery.steps.js
function render(wizard, options, state) {
+ var contentWrapper = $('<{0} class=\"{1}\"></{0}>'.format(options.contentContainerTag, "content " + options.clearFixCssClass));
+ contentWrapper.append(wizard.children());
// Create a content wrapper and copy HTML from the intial wizard structure
var wrapperTemplate = "<{0} class=\"{1}\">{2}</{0}>",
orientation = getValidEnumValue(stepsOrientation, options.stepsOrientation),
verticalCssClass = (orientation === stepsOrientation.vertical) ? " vertical" : "",
- //contentWrapper = $(wrapperTemplate.format(options.contentContainerTag, "content " + options.clearFixCssClass, wizard.html())),
See also Plunker Example
I'm creating an input text component with angular2. I need to add a class at this control if is valid and if it's required. This is the component:
import { Component, Input } from "#angular/core";
import { NgForm } from '#angular/forms';
#Component({
selector: "input-control",
template: `
<div [class.has-success]="required" class="form-group form-md-line-input form-md-floating-label">
<input [class.edited]="model[property]"
[(ngModel)]="model[property]"
[attr.ngControl]="property"
[name]="property"
type="text"
class="form-control"
id="{{property}}"
value=""
[attr.required]="required">
<label [attr.for]="property">{{label}}</label>
<span class="help-block">{{description}}</span>
</div>
`
})
export class InputControlComponent {
#Input()
model: any;
#Input()
property: string;
#Input()
label: string;
#Input()
description: string;
#Input()
required: boolean;
#Input()
form: NgForm;
}
In the first row of the template I set the "has-success" class if the input is required but I need to set it if it's valid too. Somethig like this:
[class.has-success]="required && form.controls[property].valid"
The html is this:
<form role="form" *ngIf="active" (ngSubmit)="onSubmit(databaseForm)" #databaseForm="ngForm">
<div class="form-body">
<div class="row">
<div class="col-md-6">
<input-control [model]="model" [property]="'code'" [form]="databaseForm" [label]="'#Localizer["Code"]'" [description]="'#Localizer["InsertCode"]'" [required]="true"></input-control>
</div>
<div class="col-md-6">
<input-control [model]="model" [property]="'description'" [form]="databaseForm" [label]="'#Localizer["Description"]'" [description]="'#Localizer["InsertDescription"]'"></input-control>
</div>
</div>
</div>
</form>
I think that you can't use the template-driven form a sub-component and make it be part of a form of the parent component without implementing a custom value accessor with Angular2 prior to version RC2.
See this question:
Angular 2 custom form input
With version RC2+, I think that it's possible out of the box like this:
<form #databaseForm="ngForm">
<input-control name="code" [ngModelOptions]="{name: 'code'}"
[(ngModel)]="model.code"/>
</form>