0

I have a simple component that implements reactive forms and sets up 7 input fields which are select inputs.

I am trying to apply a validator on it to force at least one of them to contain a value.

Component:

renderForm() {
        this.importForm = this.fb.group({
            costCenter: [],
            area: [],
            silo: [],
            department: [],
            location: [],
            segment: [],
            role: []
        },
            {
                validator: (formGroup: FormGroup) => {
                    return this.validateFilter(formGroup);
                }
            });
    }

    /**
     * Checks to see that at least one of the filter
     * options have been filled out prior to searching
     * for employees.
     *
     * @param formGroup
     */
    validateFilter(formgroup: FormGroup) {
        if (formgroup.controls["costCenter"].value ||
            formgroup.controls["area"].value ||
            formgroup.controls["silo"].value ||
            formgroup.controls["department"].value ||
            formgroup.controls["location"].value ||
            formgroup.controls["segment"].value ||
            formgroup.controls["role"].value
        ) {
            return { validateFilter: true };
        } else {
            return null;
        }
    }

When I submit my form an inspect the form itself, it keeps saying that its valid, even though none of the inputs have been filled out.

When I look at the individual form control values, they are displaying as null, verifying that not value has been stored.

Anything noticeable that I am doing wrong?

Update:

Not sure if this matters but a value of my input is an array:

enter image description here

I would think that this is still considered to be true when testing to see if it has a value?

Update 2: Here is a snippet of my HTML. This snippet is the same for each dropdown, just references a different function to populate it.

<tr>
                <td class="col-md-2 strong">Area</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="area" [allowClear]="true" [multiple]="true" [items]="getAreas()" placeholder="Select one or more Areas">
                        </ng-select>
                    </div>
                </td>
            </tr>

Update 3:

As requested, here is the full HTML template.

<tbody>
            <tr>
                <td class="col-md-2 strong">Cost Center</td>
                <td>
                    <div class="form-group">
                       <ng-select formControlName="costCenter" [allowClear]="true" [multiple]="true" [items]="getCostCenters()" placeholder="Select one or more Cost Centers">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Area</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="area" name="area" [allowClear]="true" [multiple]="true" [items]="getAreas()" placeholder="Select one or more Areas">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Silo</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="silo" name="silo" [allowClear]="true" [multiple]="true" [items]="getSilos()" placeholder="Select one or more Silos">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Department</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="department" name="department" [allowClear]="true" [multiple]="true" [items]="getDepartments()" placeholder="Select one or more Departments">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Location</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="location" name="location" [allowClear]="true" [multiple]="true" [items]="getLocations()" placeholder="Select one or more Locations">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Segment</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="segment" name="segment" [allowClear]="true" [multiple]="true" [items]="getSegments()" placeholder="Select one or more Segments">
                        </ng-select>
                    </div>
                </td>
            </tr>
            <tr>
                <td class="col-md-2 strong">Role</td>
                <td>
                    <div class="form-group">
                        <ng-select formControlName="role" name="role" [allowClear]="true" [multiple]="true" [items]="getRoles()" placeholder="Select one or more Roles">
                        </ng-select>
                    </div>
                </td>
            </tr>
        </tbody>

Update 4:

As a test, I commented out all of the validation logic and just returned return { validFilter: true }; expecting it to tell my form that its valid. However, this was not the case and the form is still invalid.

Seems like there may be an underlying issue somewhere else?

8
  • This will be invalid because department, location and etc is null. Can you show your template? Commented Jul 24, 2017 at 22:37
  • @brijmcq I added an HTML snippet to the question. Commented Jul 24, 2017 at 22:41
  • @brijmcq - I added the name= property to each element, resulting in the same issue. Commented Jul 24, 2017 at 22:55
  • It seems that you get the data on "area" formcontrol. Can you show the other formcontrols? I.e the department or location etc Commented Jul 24, 2017 at 22:55
  • @brijmcq Updated with the full template as requested. Commented Jul 24, 2017 at 22:57

3 Answers 3

1

So I could be wrong, but at first glance it looks like you have the validator mixed up. It should be the following:

/**
 * Checks to see that at least one of the filter
 * options have been filled out prior to searching
 * for employees.
 *
 * @param formGroup
 */
validateFilter(formgroup: FormGroup) {
    if (formgroup.controls["costCenter"].value ||
        formgroup.controls["area"].value ||
        formgroup.controls["silo"].value ||
        formgroup.controls["department"].value ||
        formgroup.controls["location"].value ||
        formgroup.controls["segment"].value ||
        formgroup.controls["role"].value
    ) {
        return null
    } else {
        return { noFilterOptionsSet: true };
    }
}

The way validators work is that a "valid" validator returns null, in other words: "I didn't find anything wrong". If it finds something it returns an object with a descriptively named property with a boolean value that further describes the state of the property, most likely "true". This is used to trigger different errors and inform the form of which error occured so you can apply different labels and error messages.

Sign up to request clarification or add additional context in comments.

4 Comments

I think this is it! A quick test showed that it passed validation when I selected one value for a single input. However, when I removed the value, looks like my form kept the value as an empty array instead of null. role:Array(0) vs when it started as role: null. I just need to find see if I can reset this to null upon removal and then the validation should reset back to invalid upon removal. Will accept this answer here shortly.
You may need to have a "clear" button that uses the setValue method on the controls to return them to a null state.
I got it working. I just set my form controls to an empty array costCenter: [[]] and then in my validator, I do formgroup.controls["costCenter"].value.length. Nice work on catching that :)
help needed on this stackoverflow.com/questions/49534244/… @joshrathke
1

You can try this

this.importForm = this.fb.group({
            costCenter: ['', [Validators.required],
            area:  ['', [Validators.required],
            silo: ['', [Validators.required],
            department: ['', [Validators.required],
            location: ['', [Validators.required],
            segment: ['', [Validators.required],
            role:  ['', [Validators.required]
        });

This would make your form with a default values of ' ' with required validation. The reason why the validators are in array is because you can also add multiple validator like this

 department: ['', [Validators.required,  Validators.minLength(3)]],

Hope this helps

2 Comments

I gave this a try and now even when I select a value for anyone of the inputs, the form is invalid. As a test, I even tried to select a value for all of the inputs and it didn't make a difference.
help needed on this stackoverflow.com/questions/49534244/… @brijmcq
0

My code looks a bit different ... not sure if it would change things for you:

validateFilter(formgroup: FormGroup) {
    if (formgroup.get("costCenter").value ||
        formgroup.get("area").value ||
        formgroup.get("silo").value ||
        formgroup.get("department").value ||
        formgroup.get("location").value ||
        formgroup.get("segment").value ||
        formgroup.get("role").value
    ) {
        return { 'validateFilter': true };
    } else {
        return null;
    }
}
  • In the return statement, the return value is a string and a boolean, so I enclosed it in quotes.

  • I also used .get instead of .controls, but that should not matter.

I have a working example of a custom group validator here for reference if that helps: https://github.com/DeborahK/Angular2-ReactiveForms/tree/master/Demo-Final-Updated

5 Comments

I gave this a try and ran into the same issue. The whole form is invalid, even when I select an input. I updated my original question to make sure there isn't an issue with my value being an array. Would this still test as true? I am using a plugin ng-select which allows me to select multiple values from the dropdown, thus the final output being an array.
so it sounds like each input element then has a value that is the array. Have you tried checking the array length then instead of checking for null? formgroup.get("costCenter").value.length
Good call, I tried adding the .length check on there, however, it results in the same invalid form.
Can you provide a plunker that demonstrates the problem?
help needed on this stackoverflow.com/questions/49534244/… @DeborahK

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.