How to POST checkbox value instead of boolean value - Angular 5 - html

I have this template-driven form:
<form #form="ngForm" (submit)="submitForm()" novalidate>
<div class="form-group" [class.has-error]="linkName.invalid">
<label class="control-label" for="name">Name</label>
<input #linkName="ngModel" type="text" class="form-control" name="name" id="name" [(ngModel)]="finalData.name" required />
<div *ngIf="linkName.invalid" class="alert alert-danger">Name is required</div>
</div>
<div class="form-group">
<label for="url">Url</label>
<input type="text" class="form-control" id="url" name="url" [(ngModel)]="finalData.url" readonly/>
</div>
<div class="checkbox" *ngFor="let tag of finalData.tags; index as i" [attr.data-index]="i">
<label><input type="checkbox" name="{{ 'checkbox' + tag }}" id="{{ 'checkbox' + tag }}" (ngModel)="finalData.tags[i]"/>{{ tag }}</label>
</div>
<button type="submit" [disabled]="form.invalid" class="btn btn-primary btn-success">Save</button>
</form>
I want to POST value from checkboxes based on whether they checked or not.
This way with one-way binding (ngModel) it will POST all tags whether they checked or not. If I use two-way binding [(ngModel)] it will POST boolean values and it will change name and id based on boolean value, which I don't want.
Example:
If i check this I want POST foo instead of true
<label><input type="checkbox" name="footag" id="footag" value="foo" [(ngModel)]="finalData.tags[i]"/>foo</label>
This is component used for data binding:
import { Component, OnInit, Injectable } from "#angular/core";
import { DataService } from "../shared/dataService";
import { FinalFormData } from "../shared/finalFormData";
import { ActivatedRoute, Router } from '#angular/router';
import { Observable } from "rxjs/Observable";
import { NgForm } from "#angular/forms";
#Component({
selector: "final-form",
templateUrl: "finalForm.component.html"
})
export class FinalFormComponent implements OnInit{
constructor(private data: DataService, private route: ActivatedRoute, private router: Router) {
}
public finalData: FinalFormData;
public errorMessage = "";
public isBusy = true;
submitForm() {
this.data.postData(this.finalData)
.subscribe(data => {
this.finalData = data;
this.router.navigate(["/"]);
}, err => console.log(err));
}
ngOnInit(): void {
//let url = encodeURIComponent(this.route.snapshot.queryParams['url']);
//this.data.loadData(url)
// .subscribe(finalData => {
// this.finalData = finalData;
// });
this.finalData = this.route.snapshot.data['finalData'];
}
}
FinalFormData class:
export class FinalFormData {
name: string;
url: string;
dateCreated: Date;
tags: any[];
}

you can use the ngModelChange method to pass the value and set it to any variable you want. Refer sample code snippet below:
<label><input type="checkbox" name="footag" id="footag" value="foo" [ngModel]="finalData.tags[i]" (ngModelChange)="CheckBoxValueChange('foo',finalData)"/>foo</label>
in the component.ts file, you can access the value and set it to any variable you want:
CheckBoxValueChange(checkboxValue:string,finalData:any){
finalData.checkboxText=checkboxValue;
alert(checkboxValue);
}

Related

Cannot bind [(ngModel)] into angular html

I am trying to achieve edit form with angular and I am having an error from binding value with [(ngModel)]
ERROR TypeError: Cannot read property 'name' of undefined
Here is my typescript code:
import { Component, OnInit } from "#angular/core";
import { HttpService } from "./../http.service";
import { ActivatedRoute, Router } from "#angular/router";
#Component({
selector: "app-edit",
templateUrl: "./edit.component.html",
styleUrls: ["./edit.component.scss"],
})
export class EditComponent implements OnInit {
id: string;
private sub: any;
author: any;
error: any;
constructor(
private _httpService: HttpService,
private _route: ActivatedRoute,
private _router: Router
) {}
ngOnInit() {
this.sub = this._route.params.subscribe((params) => {
this.id = params["id"];
});
this.oneAuthorInfoRetrieve();
}
oneAuthorInfoRetrieve() {
let observable = this._httpService.getOneTask(this.id);
observable.subscribe((data) => {
console.log("Successfully got data from get one author", data);
this.author = data["data"];
});
}
onEdit() {
let observable = this._httpService.editTask(this.id, this.author);
observable.subscribe((data) => {
console.log("Successfully update", data);
});
}
}
And here is my HTML code:
<a [routerLink]="['/home']"> Home </a>
<b>
<p>Edit this Author:</p>
</b>
<form class="border">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" class="form-control" name="name" [(ngModel)]="author.name">
</div>
<div class="form-group">
<button class="btn btn-danger" id="cancel">Cancel</button>
<button class="btn btn-primary" id="submit" (click)="onEdit()">Submit</button>
</div>
</form>
What can I do to fix this error?
DemoCreate your author model rather than using any
export class Author{
public name:string="";
constructor(){}
}
then in component
author: Author;
in ngOnInit or constructor initialize it
this.author=new Author();
You have this error because author is undefined. You can add a value to author throw a constructor or simply at the declaration author: any = {};
Or, you can display the form only of author is defined :
<form class="border" *ngIf="!!author">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" class="form-control" name="name" [(ngModel)]="author.name">
</div>
<div class="form-group">
<button class="btn btn-danger" id="cancel">Cancel</button>
<button class="btn btn-primary" id="submit" (click)="onEdit()">Submit</button>
</div>
</form>
You have to initialize object author. Because at first author.name does not exist.
Solution:
// declare author such as
author = {};// not null
The answer as you see that the author is undefined, and this also appears whenever an instance is undefined but you try to access it's properties!
Ex:
[(ngModel)]="author.name" // But author is undefined, it'll tell you that the 'name' is undefined,
// instead of 'author' remember this.
But if [(ngModel)]="author" // This will never cause an error
One more thing, author = {}; will not solve your problem, you should define a class (Recommended) like author = new author('Fes', 'Nguyen'); because {} have no property if you don't init or set value for it pro!

How to make an angular component reusable? (Angular 2+)

I made an input box for an IP Address with Port. This input box is made of 5 inputs box within a div. This is a basic example.
<div class="form-inline" style="display: inline-block">
<input required name="block1" class="form-control" #block1="ngModel" type="text" [(ngModel)]="ipBlock1">.
<input required name="block2" class="form-control" #block2="ngModel" type="text" [(ngModel)]="ipBlock2">.
<input required name="block3" class="form-control" #block3="ngModel" type="text" [(ngModel)]="ipBlock3">.
<input required name="block4" class="form-control" #block4="ngModel" type="text" [(ngModel)]="ipBlock4">:
<input required name="block5" class="form-control" #block5="ngModel" type="text" [(ngModel)]="ipBlock5">
</div>
In ip-address-input.component.ts file I have:
#Input() ipProtocol
#Output() ipAddressCreated: EventEmitter<any> = new EventEmitter<{ipAddress: string}>();
ipBlock1: string;
ipBlock2: string;
//some logic like string concatenation (ipBlock1 + '.' + ipBlock2 + '.' + ...)
In app.component.html:
<ip-address-input [ipProtocol]="dhcpRangeStart"></ip-address-input>
<ip-address-input [ipProtocol]="dhcpRangeStop"></ip-address-input>
But when I check for example for the first IP it returns the last entered IP. How I can make this component reusable (make multiple instances of it)
Image with the actual IP Input box:
I've built a few controls similar to yours by leveraging ControlValueAccessor and NG_VALUE_ACCESSOR from angular forms. Basically, these provide you with a pattern to build your own custom and reusable form controls.
Below is an example code but you can also follow this tutorial to get your component built.
Component:
import { Component, OnInit, forwardRef } from '#angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl } from '#angular/forms';
const IP_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => IpInputComponent),
multi: true
};
#Component({
selector: 'ip-address-input',
providers: [IP_VALUE_ACCESSOR],
templateUrl: './ip-input.component.html',
styleUrls: ['./ip-input.component.css']
})
export class IpInputComponent implements OnInit, ControlValueAccessor {
ipBlock1: string;
ipBlock2: string;
ipBlock3: string;
ipBlock4: string;
ipBlock5: string;
disabled: boolean;
onChange: Function;
onTouched: Function;
get value(): string {
return ipBlock1 + '.' + ipBlock2 + '.' + ipBlock3 + '.' + ipBlock4 + ':' + ipBlock5;
}
constructor() {
this.onChange = (_: any) => {};
this.onTouched = () => {};
this.disabled = false;
}
ngOnInit() {
}
writeValue(obj: any): void {
if(obj) {
let arr = obj.split('.');
this.ipBlock1 = arr[0];
this.ipBlock2 = arr[1];
this.ipBlock3 = arr[2];
this.ipBlock4 = arr[3].split(':')[0];
this.ipBlock5 = arr[3].split(':')[1];
}
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
}
Template:
<div class="form-inline" style="display: inline-block">
<input required class="form-control" type="number" [ngModel]="ipBlock1" />.
<input required class="form-control" type="number" [ngModel]="ipBlock2" />.
<input required class="form-control" type="number" [ngModel]="ipBlock3" />.
<input required class="form-control" type="number" [ngModel]="ipBlock4" />:
<input required class="form-control" type="number" [ngModel]="ipBlock5" />
</div>
Usage:
<ip-address-input formControlName="ipAddress" (value)="ipAddress.value"></ip-address-input>
HTH

How can I get the value of this object?

I am using Angular 8 to get the data out of a radio input. When I send that data to Node then to Mongodb database, it is not register, and it appear like this in the db collection:
"__v" : 0
The output of the data that is being sent from Angular is: { type: administrator }, what I want to register in the db is only the word adminstrator. The Node console shows an error because of the object that is passed to the db when it expects a string value.
The Angular template is this:
<br>
<div class="w3-panel w3-border w3-margin" style="width: 500px; height: 550px">
<label class="w3-text-blue"><h2>New User</h2></label>
<label class="w3-text-blue"><b>Name and Last Name</b></label><br>
<input type="text" class="w3-input w3-border" [(ngModel)]="name" ><br>
<label class="w3-text-blue"><b>User</b></label><br>
<input type="text" class="w3-input w3-border" [(ngModel)]="user"><br>
<label class="w3-text-blue"><b>Password</b></label><br>
<input type="password" class="w3-input w3-border" [(ngModel)]="password"><br>
<label class="w3-text-blue"><b>Confirm Password</b></label><br>
<input type="password" class="w3-input w3-border" [(ngModel)]="confirm"><br>
<label class="w3-text-blue"><b>Type of User</b></label><br>
<form #myForm="ngForm" (submit)="sendRadio(myForm.value)" >
<input id="administrator" type="radio" name="type" class="w3-radio" value="administrator" ngModel>
<label for="administrador">Administrador</label> <br>
<input id="normal" type="radio" name="type" class="w3-radio" value="normal" ngModel>
<label for="normal">Moderador</label>
<br><br>
<button type="submit" (click)="createUser(user, password, name)" class="w3-button w3-round-xxlarge w3-green">Create</button>
<button class="w3-button w3-round-xxlarge w3-red">Clean Fields</button>
</form>
</div>
The component's typescript file:
import { Component, OnInit } from '#angular/core';
import { PersonService } from '../_services/person.service';
#Component({
selector: 'app-create-user',
templateUrl: './create-user.component.html',
styleUrls: ['./create-user.component.css']
})
export class CreateUserComponent implements OnInit {
user: any;
password: any;
confirm: any;
name: any;
type: string;
constructor(private ps: PersonService) { }
ngOnInit() {
}
sendRadio(value: any) {
this.type = value;
console.log(this.type); // <--- this outputs { type: administrator }
}
createUser(userU, userPassword, userName) {
if (this.password === this.confirm) {
if (this.password.length > 0 && this.confirm.length > 0) {
this.ps.createUser(userU, userPassword, userName, this.type);
} else {
console.log('Password has to match and be completed');
}
}else {
console.log('Password does not match');
}
}
}
The service to send the data (PersonService):
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class PersonService {
uri = 'http://localhost:3000';
constructor(private http: HttpClient) { }
createUser(userU, userPassword, userName, userType: string) {
const obj = {
user: userU,
password: userPassword,
name: userName,
type: userType
};
this.http.post(`${this.uri}/createUser`, obj)
.subscribe(res => console.log('User has been created'));
}
Just pass in
console.log(this.type.type);
because you need the value of the key for type. This prints out 'administrator' and you can pass that to your backend node.

How to send dynamically added row values from angular to java controller

I created a dynamically adding/deleting rows using Angular reactive forms. Rows are getting added and deleted. But how you can send all these row values from Angular application to java controller.I am pasting the code below.
app.component.html
<div class="container">
<h3 class="page-header">Seasons</h3>
<button type="button" class="btn btn-primary" (click)="addTeam()">Add New Row</button><br/>
<form [formGroup] = "seasonsForm">
<div formArrayName = "teamRows">
<div *ngFor = "let team of seasonsForm.controls.teamRows.controls; let i=index" [formGroupName] = "i">
<h4>Team- #{{i+1}}</h4>
<div class="form-group">
<label>Team Name</label>
<input formControlName = "teamName" class="form-control">
</div>
<div class="form-group">
<label>Stadium</label>
<input formControlName = "stadiumName" class="form-control">
</div>
<div class="form-group">
<label>Capacity</label>
<input formControlName = "capacity" class="form-control">
</div>
<div class="form-group">
<label>Founded</label>
<input formControlName = "founded" class="form-control">
</div>
<div class="form-group">
<label>Head Coach</label>
<input formControlName = "headCoach" class="form-control">
</div>
<div class="form-group">
<label>Last Season</label>
<input formControlName = "lastSeason" class="form-control">
</div>
<button *ngIf = "seasonsForm.controls.teamRows.controls.length" (click) = "deleteTeam(i)" class="btn btn-danger">Delete Button</button>
</div>
</div>
</form>
<pre>{{ seasonsForm.value |json }}</pre>
</div>
app.component.ts
import { Component, OnInit } from '#angular/core';
import { FormGroup,FormArray,FormBuilder,Validators} from '#angular/forms';
import { Teams } from '../service/http-client.service';
#Component({
selector: 'app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
public seasonsForm: FormGroup;
public teams:Teams[];
constructor(private _fb: FormBuilder) { }
ngOnInit() {
this.seasonsForm = this._fb.group({
teamRows: this._fb.array([this.initTeamRows()])
});
}
get formArr() {
return this.seasonsForm.get('teamRows') as FormArray;
}
initTeamRows() {
return this._fb.group({
teamName: [''],
stadiumName: [''],
capacity: [''],
founded: [''],
headCoach: [''],
lastSeason: ['']
});
}
addTeam() {
this.formArr.push(this.initTeamRows());
}
deleteTeam(index: number) {
this.formArr.removeAt(index);
}
}
createTeam(): void {
this.httpClient.post<Teams>("http://localhost:8080/addTeam", seasonsForm);
.subscribe( res => {
alert("Successful");
})
};
export class Teams {
constructor(
public teamName:string,
public stadiumName:string,
public capacity:string,
public founded:string,
public headCoach:string,
public lastSeason:string,
) {}
}
I tried to send entire formGroup(seasonsForm) but it is getting failed.I am relatively new to Angular and i searched in Google but i didn't find much help. So any help in this would be appreciated.
you need to send form value on your createTeam function. If you console.log(seasonsForm), you can see there are some other attributes which is only about your form.
Also if you want you can check is form valid.
createTeam(): void {
if(seasonsForm.valid){
this.httpClient.post<Teams>("http://localhost:8080/addTeam", seasonsForm.value);
.subscribe( res => {
alert("Successful");
})
};
}
First of all if you are using NoSQL database then you can send a JSON file containing arrays. So here i decided to send a json file containing Array values to server side and then i converted the form group name to JSON.Stringify. In Server side you can retrieve that json in String format and parse it and send to DB. Here is the code below
onSubmit() {
this.httpClient.post("http://localhost:8080/addTeams",JSON.stringify(this.seasonsForm.value))
.subscribe((response: Response) => {
})
alert("Successful");
}

Angular2 Edit profile: Display retrieved data in HTML input tag

I have an edit profile page. So when the user clicks on the edit profile page the users details should be displayed in the input tag fields in the HTML. But I am unable to display the details I am retrieving.
edit-profile.component.html
<form novalidate (ngSubmit)="onFormSubmit(signupForm)" #signupForm="ngForm">
<div class="form-inputs clearfix">
<div class="row">
<div class="col-md-6">
<p>
<label class="required">First Name<span>*</span></label>
<input
type="text"
[value]="accountDetails.firstName"
name="firstName"
[(ngModel)] = "user.firstName"
#firstName = "ngModel"
required><p>{{accountDetails.firstName}} </p>
<span *ngIf="firstName.invalid && (firstName.dirty || firstName.touched)" class="input-error">
<span *ngIf = "firstName.errors?.required">
First Name field can't be blank
</span>
</span>
</p></form>
edit-profile.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiServiceProvider } from '../services/api.service';
#Component({
selector: 'app-edit-profile',
templateUrl: './edit-profile.component.html',
styleUrls: ['./edit-profile.component.css']
})
export class EditProfileComponent implements OnInit {
public user: any = {};
public accountDetails: any = {}
constructor(
private api: ApiServiceProvider
) { }
ngOnInit() {
let profile = JSON.parse(localStorage.getItem("profile"));
this.accountDetails = profile.user;
console.log(this.accountDetails);
}
public onFormSubmit({ value, valid }: { value: any, valid: boolean }) {
this.user = value;
this.api.put("/users/editprofile", value.userId, false)
.subscribe((data) => {
console.log(data)
localStorage.setItem("profile", JSON.stringify(data));
location.href = "/profile"
}, (err) => {
alert("Registartion failed " + err);
})
}
}
you only populate your accountDetails variable but you try to bind your user variable.
so you have:
this.accountDetails = profile.user;
but you bind your input to the user variable:
<input type="text" [(ngModel)]="user.firstName" #firstName="ngModel" required>
Either populate your user variable:
this.user = profile.user;
or bind to your account details variable:
<input type="text" [(ngModel)]="accountDetails.firstName" #firstName="ngModel" required>
Also you need to close your div clearfix, div row and div column correctly before closing the form tag. </div></div></div></form>