Search code examples
angularrequiredform-fields

Set Required to a custom Angular2 dropdown component


I have a form that has few input fields and a custom dropdown. The question is: Can I set my-custom-dropdown component to be required?

My form looks something like this:

<form name="myform" (ngSubmit)="onSubmit()" #myform="ngForm">
    <!-- other fields omitted for brevity -->
    <my-custom-dropdown name="someValue" #someValue="ngModel" [(ngModel)]="model.someValue"></my-custom-dropdown>

    <button type="submit">Submit</button>
</form>

My dropdown component is basically a custom component that looks something like this:

<div>
    <label>
        Set some value
    </label>
    <p class="form-control-static">{{model.name}}</p>
    <ul>
        <my-custom-dropdown-item *ngFor="let option of options; let i = index" [(value)]="model" [option]="option"></my-custom-dropdown-item>
    </ul>
</div>

And finally I have items of a dropdown like this:

<li>
    <!-- some structural and styling stuff omitted for brevity -->
    {{option.name}}
</li>

I'm using the latest version of Angular2. I did not include Typescript files but long story short, my-custom-dropdown component implements ControlValueAccessor.


Solution

  • What I ended up doing is a simple directive that I can apply to a dropdown component:

    import { Directive } from '@angular/core';
    import { AbstractControl, ValidatorFn, Validator, FormControl, NG_VALIDATORS } from '@angular/forms';
    
    //validation function
    function validateDropdownFactory(): ValidatorFn {
        return (c: AbstractControl) => {
            let isValid = c.value !== null;
    
            if (isValid) {
                return null;
            }
            else {
                return {
                    dropdownRequired: {
                        valid: false
                    }
                };
            }
        }
    }
    
    @Directive({
        selector: '[dropdownRequired][ngModel]',
        providers: [
            { provide: NG_VALIDATORS, useExisting: DropdownRequired, multi: true }
        ]
    })
    
    export class DropdownRequired implements Validator {
        validator: ValidatorFn;
    
        constructor() {
            this.validator = validateDropdownFactory();
        }
    
        validate(c: FormControl) {
            return this.validator(c);
        }
    }
    

    And then I applied it like this:

    <my-custom-dropdown name="someValue" #someValue="ngModel" [(ngModel)]="model.someValue" dropdownRequired></my-custom-dropdown>