I have a component binding issue. I'm pretty sure that I've got a syntax issue, but I'm not sure what I'm doing wrong.
The full source code is available at https://github.com/TheMagnificent11/LunchVoting in the feature/6_ExtendedInputBug branch (https://github.com/TheMagnificent11/LunchVoting/tree/feature/6_ExtendedInputBug). The master and develop branches have working code that doesn't use the extended-input component.
input-error.component.ts
This is the component that displays a form field error.
import { Component, Input } from '@angular/core';
@Component({
selector: 'input-error',
template: './input-error.component.html'
})
export class InputErrorComponent {
@Input()
errorMessage: string;
@Input()
isError: boolean = true;
}
input-error.component.html
<span class="text-danger" *ngIf="isError">
{{errorMessage}}
</span>
extended-input.component.ts
This is the component combines label, input and validation errors (collection of child components input-error
) for a single form field.
import {
Component,
Input,
ContentChildren,
QueryList
} from '@angular/core';
import { InputErrorComponent } from '../input-error/input-error.component';
@Component({
selector: 'extended-input',
template: './extended-input.component.html'
})
export class ExtendedInputComponent {
@Input()
inputName: string = '';
@Input()
labelText: string = '';
@Input()
isError: boolean = false;
@ContentChildren(InputErrorComponent)
errors: QueryList<InputErrorComponent>;
}
extended-input.component.html
<div class="form-group" [ngClass]="{'has-error':border border-danger}">
<label for="{{inputName}}">{{labelText}}</label>
<ng-content select="input-control"></ng-content>
<div *ngIf="isError">
<ng-content select="input-errors"></ng-content>
</div>
</div>
controls.module.ts
Module that has extended-input
component
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { ExtendedInputComponent } from './extended-input.component.ts';
import { InputErrorComponent } from './input-error.component.ts';
let components = [
ExtendedInputComponent,
InputErrorComponent
];
@NgModule({
declarations: components,
imports: [
CommonModule,
ReactiveFormsModule
]
})
export class ControlsModule {
}
register.component.ts
This the form component that uses the other extended-input
component.
import { Component } from '@angular/core';
import {
FormBuilder,
FormGroup,
FormControl,
Validators
} from '@angular/forms';
@Component({
selector: 'register',
templateUrl: './register.component.html'
})
export class RegisterComponent {
registrationForm: FormGroup;
givenName: FormControl;
surname: FormControl;
constructor(private formBuilder: FormBuilder) {
this.givenName = new FormControl('', [Validators.required, Validators.maxLength(100)]);
this.surname = new FormControl('', [Validators.required, Validators.maxLength(100)]);
this.registrationForm = this.formBuilder.group({
givenName: this.givenName,
surname: this.surname,
});
}
}
register.component.html
<form [formGroup]="registrationForm" (submit)="onSubmit()">
<extended-input [inputName]="'givenName'"
[labelText]="'Given Name'"
[isError]="givenName.touched && givenName.invalid">
<input-control>
<input type="text" formControlName="givenName" />
</input-control>
<input-errors>
<input-error [isError]="givenName.hasError('required')">
Given Name is required
</input-error>
</input-errors>
</extended-input>
<!-- The above components should produce HTML similar to this -->
<div class="form-group">
<label for="surname">Surname</label>
<input type="text" formControlName="surname" />
<div [hidden]="surname.valid || surname.untouched">
<span class="text-danger" [hidden]="!surname.hasError('required')">
Surname is required
</span>
</div>
</div>
<button type="submit" [disabled]="!registrationForm.valid">
Register
</button>
</form>
Entry Module
The module that contains register
component.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { ControlsModule } from '../controls/controls.module';
import { RegisterComponent } from './register-component';
@NgModule({
declarations: components,
imports: [
CommonModule,
ReactiveFormsModule,
ControlsModule
]
})
export class EntryModule {
}
Error
Uncaught Error: Template parse errors:
Can't bind to 'inputName' since it isn't a known property of 'extended-input'.
1. If 'extended-input' is an Angular component and it has 'inputName' input, then verify that it is part of this module.
2. If 'extended-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
<form [formGroup]="registrationForm" (submit)="onSubmit()">
<extended-input [ERROR ->][inputName]="'givenName'"
[labelText]="'Given Name'"
"): ng:///EntryModule/RegisterComponent.html@9:28
Can't bind to 'labelText' since it isn't a known property of 'extended-input'.
1. If 'extended-input' is an Angular component and it has 'labelText' input, then verify that it is part of this module.
2. If 'extended-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
<extended-input [inputName]="'givenName'"
[ERROR ->][labelText]="'Given Name'"
[isError]="givenName.touched && givenName.inv"): ng:///EntryModule/RegisterComponent.html@10:28
Can't bind to 'isError' since it isn't a known property of 'extended-input'.
1. If 'extended-input' is an Angular component and it has 'isError' input, then verify that it is part of this module.
2. If 'extended-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. (""'givenName'"
[labelText]="'Given Name'"
[ERROR ->][isError]="givenName.touched && givenName.invalid">
<input-control>
"): ng:///EntryModule/RegisterComponent.html@11:28
'input-control' is not a known element:
1. If 'input-control' is an Angular component, then verify that it is part of this module.
2. If 'input-control' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. (""
[isError]="givenName.touched && givenName.invalid">
[ERROR ->]<input-control>
<input type="text" formControlName="givenName" />
"): ng:///EntryModule/RegisterComponent.html@12:16
Can't bind to 'isError' since it isn't a known property of 'input-error'.
1. If 'input-error' is an Angular component and it has 'isError' input, then verify that it is part of this module.
2. If 'input-error' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
</input-control>
<input-errors>
<input-error [ERROR ->][isError]="givenName.hasError('required')">
Given Name is required
"): ng:///EntryModule/RegisterComponent.html@16:33
'input-error' is not a known element:
1. If 'input-error' is an Angular component, then verify that it is part of this module.
2. If 'input-error' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
</input-control>
<input-errors>
[ERROR ->]<input-error [isError]="givenName.hasError('required')">
Given Name is requi"): ng:///EntryModule/RegisterComponent.html@16:20
'input-errors' is not a known element:
1. If 'input-errors' is an Angular component, then verify that it is part of this module.
2. If 'input-errors' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("input type="text" formControlName="givenName" />
</input-control>
[ERROR ->]<input-errors>
<input-error [isError]="givenName.hasError('required')">
"): ng:///EntryModule/RegisterComponent.html@15:16
'extended-input' is not a known element:
1. If 'extended-input' is an Angular component, then verify that it is part of this module.
2. If 'extended-input' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
<form [formGroup]="registrationForm" (submit)="onSubmit()">
[ERROR ->]<extended-input [inputName]="'givenName'"
[labelText]="'Given Name'"
"): ng:///EntryModule/RegisterComponent.html@9:12
at syntaxError (vendor.js:sourcemap:38524)
at TemplateParser.parse (vendor.js:sourcemap:49621)
at JitCompiler._compileTemplate (vendor.js:sourcemap:63824)
at vendor.js:sourcemap:63743
at Set.forEach (<anonymous>)
at JitCompiler._compileComponents (vendor.js:sourcemap:63743)
at vendor.js:sourcemap:63630
at Object.then (vendor.js:sourcemap:38513)
at JitCompiler._compileModuleAndComponents (vendor.js:sourcemap:63629)
at JitCompiler.compileModuleAsync (vendor.js:sourcemap:63558)
Does anyone know what I've done wrong?
If you are declaring extendedInputComponent
and InputErrorComponent
in some other module(ControlsModule
) than your RegisterComponent
is declared(EntryModule
) and ControlsModule
is only imported in EntryModule
, you have to export the Components also you declared in the same ControlsModule
.
ie, your ControlsModule
should be like
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { ExtendedInputComponent } from './extended-input.component.ts';
import { InputErrorComponent } from './input-error.component.ts';
let components = [
ExtendedInputComponent,
InputErrorComponent
];
@NgModule({
declarations: components,
imports: [
CommonModule,
ReactiveFormsModule
],
exports: components
})
export class ControlsModule {
}