I want to create custom control which contains other custom controls and use ngModel that connects all of them. Like :
PersonSearchComponent :
So for now I have working version, but I think i have made something bad (maybe I should use FormBuilder):
PersonSearch Template :
<div>
<developer-search-control [(ngModel)]="searchModel.developerSearchModel"></developer-search-control>
<building-search-control [(ngModel)]="searchModel.buildingSearchModel"></building-search-control>
<country-select [(ngModel)]="searchModel.countryModel"><country-select>
</div>
ParentSearch component
...
export class PersonSearch {
@Output() searchDataEmitter= new EventEmitter();//Exports data to above component which contains this, and listComponent
searchModel : PersonSearchModel : new PersonSearchModel();
performSearch()
{
//gets data from service with searchModel and searchDataEmitter transpors it to above component
}
}
Models : PersonSearchModel :
developerSearchModel : DeveloperSearchModel = new DeveloperSearchModel();
buildingSearchModel: BuildingSearchModel = new BuildingSearchModel();
countryModel : CountryModel;
DeveloperSearchModel :
name : string
surname : string
proffesion : ProfessionModel
Template developerSearchControl.component.html:
<div *ngIf="value">//This is the problem
<input [(ngModel)]="value.name"></input>
<input [(ngModel)]="value.surname"></input>
<profesion-select [(ngModel)]="value.ProffesionSelect">
</div>
developerSearchControl.component:
...
@Component({
selector: 'developer-search-control',
templateUrl: './developerSearchControl.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DeveloperSearchControlComponent),
multi: true,
}],
})
export class DeveloperSearchControlComponent extends ElementBase<DeveloperSearchModel > {
protected model: NgModel;
constructor(
@Optional() @Inject(NG_VALIDATORS) validators: Array<any>,
@Optional() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<any>,
) {
super(validators, asyncValidators);
}
}
profesionSelect.component
...
@Component({
selector: 'profesion-select',
template: `
<div>
<label *ngIf="label">{{label}}</label>
<dx-select-box
[dataSource]="data"
[(ngModel)]="value"
displayExpr="proffesionName"
[placeholder]="placeholder"
[searchEnabled]="true"
>
</dx-select-box>
</div>`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: ProfessionComponent,
multi: true,
}],
})
export class ProfessionComponent extends ElementBase<string> implements OnInit {
private data: ProfessionModel[];
private label: string = 'proffesion :';
private placeholder: string = 'Select profession';
@ViewChild(NgModel) model: NgModel;
constructor(private proffesionService: ProfessionDataService,
@Optional() @Inject(NG_VALIDATORS) validators: Array<any>,
@Optional() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<any>,
) {
super(validators, asyncValidators);
}
ngOnInit() {
this.professionService.getDevelopersProfessions().subscribe(
data => {
this.data = data;
}
);
}
}
ElementBase is a generic ControlValueAccessor with validation from : http://blog.rangle.io/angular-2-ngmodel-and-custom-form-components/
So my problem is that when I create the template for children (developerSearch, buildingSearch) the value passed with ngModel is not initialized for them and i get :
EXCEPTION: Uncaught (in promise): Error: Error in ./DeveloperSearchControlComponent class DeveloperSearchControlComponent - inline template:2:33 caused by: Cannot read property 'name' of null
Error: Error in ./DeveloperSearchControlComponent class DeveloperSearchControlComponent - inline template:2:33 caused by: Cannot read property 'name' of null
Because the value from ngModel is null at start. So I have to use *ngFor="value" in templates of child components which looks bad. Is there any solution to initialize the object before template verification? or Im doing this very wrong?
The ngModel directive is a directive that is used to bind the values of the HTML controls (input, select, and textarea) or any custom form controls, and stores the required user value in a variable and we can use that variable whenever we require that value. It also is used during form validations.
Yeah, you can use a function. In which case the ng-model will be the value returned by the function.
Angular 2: Connect your custom control to ngModel with Control Value Accessor. NOTE: Please note that this article refers to an old version of Angular. Core concepts and ideas may still be useful but not all examples will work with current Angular without changes.
The ngmodel directive binds the value of HTML controls (input, select, textarea) to application data. With the ng-model directive you can bind the value of an input field to a variable created in Angular. The binding goes both ways. If the user changes the value inside the input field, the Angular property will also change its value.
Custom form controls/inputs are a typical pattern in complex Angular applications. It’s common to want to encapsulate HTML, CSS, and accessibility in an input component to make it easier to use in forms throughout the application. Common examples of this are datepickers, switches, dropdowns, and typeaheads.
We can see our custom app-switch works seamlessly with the Reactive Forms/Form Builder API just like any other text input. NgModel allows us to bind to an input with a two-way data binding syntax similar to Angular 1.x. We can use this same syntax when using a custom form control.
There's a way to use two-way binding with safe-navigation operator:
<input [ngModel]="value?.name" (ngModelChange)="value?.name ? value.name = $event : null">
Props to: https://stackoverflow.com/a/36016472/5706293
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With