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) 获得。 masterdevelop 分支有不使用 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-controlinput-errors,但我没有在此处看到这些组件的代码,因此无法让我的一切正常工作,但这是一个开始.我不能完全遵循 ng-content/transclusion 的策略,但是 angular 的那部分不是我的强项。

如果您在其他模块(ControlsModule) 中声明extendedInputComponentInputErrorComponent 而不是声明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 {
}