Angular - 组件绑定问题
Angular - Component Binding Issue
我有组件绑定问题。我很确定我遇到了语法问题,但我不确定我做错了什么。
完整的源代码可在 https://github.com/TheMagnificent11/LunchVoting in the feature/6_ExtendedInputBug branch (https://github.com/TheMagnificent11/LunchVoting/tree/feature/6_ExtendedInputBug) 获得。 master 和 develop 分支有不使用 extended-input 组件的工作代码。
输入-error.component.ts
这是显示表单域错误的组件。
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;
}
输入-error.component.html
<span class="text-danger" *ngIf="isError">
{{errorMessage}}
</span>
扩展-input.component.ts
这是为单个表单字段组合了标签、输入和验证错误的组件(子组件的集合 input-error
)。
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>;
}
扩展-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
具有 extended-input
个组件的模块
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
这是使用另一个 extended-input
组件的表单组件。
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>
入门模块
包含 register
组件的模块。
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 {
}
错误
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)
有人知道我做错了什么吗?
1. If 'extended-input' is an Angular component and it has 'inputName' input, then verify that it is part of this module.
确保您的组件已正确导入。我注意到 RegisterComponent 在 class 名称的末尾有 'Component' 后缀,但其他的 InputError 和 ExtendedInput 没有。您是否使用 CLI 创建了一个而不是其他的?如果您没有使用 CLI,可能您忘记了将它们手动导入到您的模块中。
在那之后,我发现 属性 绑定有问题。它需要一个引号内的表达式,所以如果你想传递文字文本,你需要在引号内加上引号。有点奇怪。 [labelText]="Given Name"
将查找变量 Given 和 Name,因此需要为 [labelText]="'Given Name'"
。这是上面的错误:
[ERROR ->][labelText]="Given Name"
您的应用似乎还有其他一些组件 input-control
和 input-errors
,但我没有在此处看到这些组件的代码,因此无法让我的一切正常工作,但这是一个开始.我不能完全遵循 ng-content/transclusion 的策略,但是 angular 的那部分不是我的强项。
如果您在其他模块(ControlsModule
) 中声明extendedInputComponent
和InputErrorComponent
而不是声明RegisterComponent
(EntryModule
) 和ControlsModule
仅在 EntryModule
中导入,您还必须导出在同一 ControlsModule
中声明的组件。
也就是说,你的 ControlsModule
应该像
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 {
}
我有组件绑定问题。我很确定我遇到了语法问题,但我不确定我做错了什么。
完整的源代码可在 https://github.com/TheMagnificent11/LunchVoting in the feature/6_ExtendedInputBug branch (https://github.com/TheMagnificent11/LunchVoting/tree/feature/6_ExtendedInputBug) 获得。 master 和 develop 分支有不使用 extended-input 组件的工作代码。
输入-error.component.ts
这是显示表单域错误的组件。
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;
}
输入-error.component.html
<span class="text-danger" *ngIf="isError">
{{errorMessage}}
</span>
扩展-input.component.ts
这是为单个表单字段组合了标签、输入和验证错误的组件(子组件的集合 input-error
)。
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>;
}
扩展-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
具有 extended-input
个组件的模块
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
这是使用另一个 extended-input
组件的表单组件。
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>
入门模块
包含 register
组件的模块。
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 {
}
错误
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)
有人知道我做错了什么吗?
1. If 'extended-input' is an Angular component and it has 'inputName' input, then verify that it is part of this module.
确保您的组件已正确导入。我注意到 RegisterComponent 在 class 名称的末尾有 'Component' 后缀,但其他的 InputError 和 ExtendedInput 没有。您是否使用 CLI 创建了一个而不是其他的?如果您没有使用 CLI,可能您忘记了将它们手动导入到您的模块中。
在那之后,我发现 属性 绑定有问题。它需要一个引号内的表达式,所以如果你想传递文字文本,你需要在引号内加上引号。有点奇怪。 [labelText]="Given Name"
将查找变量 Given 和 Name,因此需要为 [labelText]="'Given Name'"
。这是上面的错误:
[ERROR ->][labelText]="Given Name"
您的应用似乎还有其他一些组件 input-control
和 input-errors
,但我没有在此处看到这些组件的代码,因此无法让我的一切正常工作,但这是一个开始.我不能完全遵循 ng-content/transclusion 的策略,但是 angular 的那部分不是我的强项。
如果您在其他模块(ControlsModule
) 中声明extendedInputComponent
和InputErrorComponent
而不是声明RegisterComponent
(EntryModule
) 和ControlsModule
仅在 EntryModule
中导入,您还必须导出在同一 ControlsModule
中声明的组件。
也就是说,你的 ControlsModule
应该像
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 {
}