Get a hold of a FormControl instance by querying a component's template

short answer: You can't

You just can't. (Well, maybe be you can but it will be hacky !)

long answer: you can't, but...

FormControl is not injectable. Directives are injectable, but, you would have to deal with formControlName,ngModel,formControl, etc and they wouldn't be accessible from the wrapping component but its children...

For your case you could try with @ContentChildren(FormControlName) theControl: any; as there is no FormControlDirective implied in your code, but you wouldn't be able to access the FormControl anyway (property _control is internal, soo it would be a hack)...

So you should stick to managing your errors from the component dealing with the FormGroup.

BUT if you want to display a custom input (that won't display error message as is but will be able to show this input is in error state (the host element will get the ng-valid, ng-invalid classes, so it's just a matter of style), you can do this by implementing ControlValueAccessor.

A bridge between a control and a native element.

A ControlValueAccessor abstracts the operations of writing a new value to a DOM element representing an input control.

It means directives/components implementing this interface can be used with ngModel, formControl,etc...

eg: <my-component [(ngModel)]="foo"></my-component>

it is not the exact reproduction of your problem, but this implementation solved the same kind of problem for me :

export const INPUT_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => InputComponent),
  multi: true
};

@Component({
  selector: "field",
  template: `<!--put anything you want in your template-->
            <label>{{label}}</label>
            <input #input (input)="onChange($event.target.value)" (blur)="onTouched()" type="text">`,
  styles: [],
  providers: [INPUT_VALUE_ACCESSOR]
})
export class InputComponent implements ControlValueAccessor {
  @ViewChild("input")
  input: ElementRef;
  @Input()
  label:string;
  onChange = (_: any) => { };
  onTouched = () => { };

  constructor(private _renderer: Renderer) { }

  writeValue(value: any): void {
    const normalizedValue = value == null ? "" : value;
    this._renderer.setElementProperty(this.input.nativeElement, "value", normalizedValue);
  }

  registerOnChange(fn: (_: any) => void): void {
      this.onChange = fn;
  }
  registerOnTouched(fn: () => void): void { this.onTouched = fn; }

  setDisabledState(isDisabled: boolean): void {
    this._renderer.setElementProperty(this.input.nativeElement, "disabled", isDisabled);
  }
}

then you can just :

<field label="Title" formControlName="title"></field>

You can get ahold of the Form Control Name instance via:

@Component({
  selector: 'field',
  templateUrl: './field.component.html',
  styleUrls: ['./field.component.scss']
})
export class FieldComponent implements AfterContentInit {
  @Input()
  public label: string;

  @ContentChild(FormControlName)
  public controlName: FormControlName;

  public ngAfterContentInit(): void {
    console.log(this.controlName.control);
  }
}