The actual complex code is abstracted to make it more readable.
In our Angular 2 project, we have got a component <top-component>
(LEVEL 1) like this:
<top-component>
</top-component>
Which has the following template : <some-form>
(LEVEL 2):
<some-form>
</some-form>
Which has the following template (LEVEL 3):
<form #f="ngForm" (submit)="handleFormSubmit(f)" >
<input name="Label" value="Label" />
<input name="Value" value="Value" />
<some-select></some-select>
<button> Cancel </button>
<button> Save </button>
</form>
The template of <some-select>
(LEVEL 4) is:
<select name="selectData" ngDefaultControl [(ngModel)]="selectData">
<option *ngFor="let option of options" [ngValue]="option.value">{{option.label}}</option>
</select>
The problem is that when we submit #f="ngForm"
to handleFormSubmit(f)
,
the f.value
values does not have the values from the some-select
's select
element.
I fixed this by using a shared service.
Long story short:
With this, you can make it work. And you can have a very dynamic form.
If you need an example tell me and when I can I will make you a simple example here.
Hope it helped! Cheers!
Update:
Let's go from child to parent here.
SelectField
Component:
@Component({
selector: 'select-field',
template: `
<select class="col-md-12 form-control input-xs" name="ibos-newsletter" [(ngModel)]="fieldset.value" (ngModelChange)="onChange($event)">
<option *ngFor="let option of options" [ngValue]="option.id"
[selected]="option.id === condition">{{option.name}}
</option>
</select>
`
})
export class SelectField implements OnInit {
private fieldset = {};
private options = <any>[];
private fieldName = 'SelectField';
constructor(private sharedService: SharedService) {
// we get data from our shared service. Maybe the initial data is gathered and set up in the Form service.
// So if the Form service just calls this method we are subscribed and we get the data here
this.sharedService.updateFieldsetsListener$.subscribe((fieldset) => {
if (fieldset.field=== this.fieldName) {
this.selectModel = fieldset;
}
}
);
}
ngOnInit() {
}
onChange() {
// fieldset.value (our model) is automatically updated, because this is binded with (ngModelChange). This means that we are sending an updated fieldset object
this.sharedService.updateFieldsets(this.fieldset);
}
}
SharedService
service:
@Injectable()
export class SharedService {
updateFieldsetsListener$: Observable<any>;
private updateFieldsetsSubject = new Subject<any>();
constructor(private jsonApiService: JsonApiService) {
this.updateFieldsetsListener$ = this.updateFieldsetsSubject .asObservable();
}
updateFieldsets(fieldset) {
this.updateFieldsetsSubject .next(fieldset);
}
}
Form Component:
Inside your constructor you should have the subscribe:
this.sharedService.updateFieldsetsListener$.subscribe((fieldset) => {
// Here you have a full object of your field set. In this case the select.
// You can add it to a form object that contains all the fieldsets objects...
// You can use these formfields objects (instead of sending / receiving only the model) to dynamically: select an option, disable an input, etc...
}
);
Personal thoughts: