1
votes

I am using Angular2. I have this in my master component:

<form #f="ngForm" novalidate (ngSubmit)="save()">
  <child [cosField]="cosField" [f]="f"></child>
  <button type="submit" [disabled]="!f.valid">Submit</button>
</form>

I have a different child component that I call from this component. The code in the child component is :

<input type="text" name="flow" [(ngModel)]="cosField.value" required  #name="ngModel"/>
<div [hidden]="name.valid || (!f.submitted)" 
    class="error">
  An error has occurred.
</div>

I want to access this local variable f in the child component. Basically for form validation. If some validation fails in the child component the message "An error has occurred" gets correctly displayed. But in the master component, f.valid still remains true and so the submit button is always enabled. However if I inline the child component into the master component itself, then everything works fine and the Submit button is disabled if the validation fails. Is there a way to split a form across multiple components, and still be able to effectively validate controls using the local variable f?

1

1 Answers

0
votes

Pass the value out of the child component using an Angular2 @Output EventEmitter, so the parent component can catch the event and update its sense of validity for f.

You have to add to the Component logic for your parent and child components. The pattern in Typescript looks something like this:

Parent component:

...<imports>...
@Component({
    selector: 'parent-component',
    ...
})
export class ParentComponent implements OnInit {
    ...
    ngOnInit() {
        ...
    });

    childChanged(event) {
        // Use event value to do validity checking here.
    }
}

Child component:

import { Component, Output, EventEmitter } from '@angular/core';
<...other imports...>

@Component({
    selector: 'child',
    ...
})
export class ChildComponent implements OnInit {
    @Output() change: EventEmitter<any> = new EventEmitter();

    ...
}

Now your child's input can emit an event on the @Outputwhich propagates to the parent. For example, the child can propagate a change on blur and pass the validity of name:

<input type="text" name="flow" [(ngModel)]="cosField.value" required  #name="ngModel" (blur)="change.emit(name.valid)" />

The parent picks up the change and handles the validity status by looking for your custom change event:

<child [cosField]="cosField" [f]="f" (change)="childChanged($event)"></child>

Here are other references I found useful when first learning about this stuff: