What is the proper way of Angular nested model driven reactive form select option for any HttpClient POST request? I have a simple restful web service where it has 2 Objects of type exercise and muscle. I am using Angular reactive forms select option to post a new exercise object. As the object muscle is nested under the exercise object I was using a drop-down select option to nest the muscle object. When I try to create/httpclient post a new exercise, I get a null value for muscle instead of the object itself. Below is JSON of Get example of an exercise object
{
"id": 1,
"name": "Dumbbell curls",
"description": "Dumbbell Stand up curls",
"muscle": {
"id": 1,
"name": "Biceps",
"exercises": [
1
]
}
}
This is the Muscle object
{
"id": 1,
"name": "Biceps",
"exercises": [
{
"id": 1,
"name": "Dumbbell curls",
"description": "Dumbbell Stand up curls",
"muscle": 1
}
]
}
When I try to Create/post a new exercise I get muscle as null.
This is my crearteExercise component
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { ExerciseService } from '../exercise.service';
import { Exercise } from '../exercise.model';
import { Router, ActivatedRoute } from '@angular/router';
import { FormGroup, FormControl, FormBuilder } from '@angular/forms'
import { Muscle } from '../muscle.model';
import { MuscleService } from '../muscle.service';
@Component({
selector: 'app-new-exercise',
templateUrl: './new-exercise.component.html',
styleUrls: ['./new-exercise.component.css']
}) export class NewExerciseComponent implements OnInit {
// @Output() saveNewExercise = new EventEmitter();
profileForm = new FormGroup({
name: new FormControl(''),
description: new FormControl(''),
muscle:new FormGroup({
name: new FormControl('')
})
});
exercises: Exercise[];
exercise: Exercise;
muscles:Muscle[];
constructor(private everciseService: ExerciseService,
private router: Router,
private aR: ActivatedRoute,
private fb: FormBuilder,
private muscleService:MuscleService) { }
ngOnInit() {
this.everciseService.getExercises()
.subscribe(data => this.exercises = data);
this.aR.params.subscribe((params) => {
if (params['id']) {
this.everciseService.getExerciseById(params['id'])
.subscribe(data => {
console.log(data);
this.exercise = data;
this.profileForm = this.fb.group({
'name': [this.exercise['name']],
'description': [this.exercise['description']],
'muscle':[this.exercise.muscle['name']]
});
})
} else {
this.profileForm = this.fb.group({
'name': [null],
'description': [null],
'muscle':[null]
});
}
})
this.muscleService.getAllMuscles()
.subscribe(data =>this.muscles= data);
}
save(exerciseId, formValues) {
debugger;
let exercise: Exercise = {
id: undefined,
name: formValues.name,
description: formValues.description,
muscle: formValues.muscle
}
if (exerciseId !== undefined) {
this.everciseService.updateExercise(exercise, exerciseId.id)
.subscribe(updateExercise => {
this.router.navigate(['/exercises']);
})
} else {
// this.saveNewExercise.emit(exercise);
this.everciseService.addExercise(exercise)
.subscribe(exercise => {
this.exercises.push(exercise);
this.router.navigate(['/exercises']);
});
}
}
}
This is html
<div class="container">
<h2> Add new Exercise </h2>
<form [formGroup]="profileForm" (ngSubmit)="save(exercise,profileForm.value)">
<div class="form-group">
<label for="formGroupExampleInput">
Exercise Name:
</label>
<input type="text" class="form-control" id="formGroupExampleInput" formControlName="name">
</div>
<div class="form-group">
<label for="formGroupExampleInput">
Description:
</label>
<input type="text" class="form-control" id="formGroupExampleInput" formControlName="description">
</div>
<div class="form-group">
<label for="muscle">Select Muscle:</label>
<select class="form-control" id="muscle" formGroupName="muscle">
<option *ngFor="let muscle of muscles" [ngValue]="muscle.id">{{muscle.name}}</option>
</select>
</div>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
</form>
</div>
This is my exerciseService
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Exercise } from './exercise.model';
import { Observable } from 'rxjs';
@Injectable()
export class ExerciseService {
constructor(private http: HttpClient) { }
getExercises() {
return this.http.get<Exercise[]>("/api/exercise");
}
getExerciseById(id: number): Observable<Exercise> {
return this.http.get<Exercise>("/api/exercise/" + id);
}
/** POST: add a new exercise to the database */
addExercise(exercise: Exercise): Observable<Exercise> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'my-auth-token'
})
};
return this.http.post<Exercise>("/api/exercise", exercise, httpOptions);
}
updateExercise(exercise: Exercise, id): Observable<Exercise> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'my-auth-token'
})
};
return this.http.put<Exercise>("/api/exercise/" +id, exercise, httpOptions);
}
deleteExercise(id){
return this.http.delete("/api/exercise/"+id);
}
}
And this is my exercise interface
import { Muscle } from "./muscle.model";
export interface Exercise{
id: number;
name: string;
description: string;
muscle: Muscle;
}