首页 文章

Angular:'t bind to ' ngModel ' since it isn' t 'input'的已知属性(不重复)

提问于
浏览
1

我在这个相同的主题中已经阅读了很多帖子,但我99%肯定我已经遵守了所有的答案 . 从为您创建的非常基本的应用程序开始 . 它运行良好,它通过3 Karma测试罚款 . 我使用ngModel添加了一个带有一个输入<==> typescript链接的新组件,它无法使用此错误测试新组件:

Failed: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("<div class="boxed">
    <b>Invoice:</b>
      <input [ERROR ->][(ngModel)]= "qty">
    </div>
 "): ng:///DynamicTestModule/CalculateComponent.html@2:11
Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. ("<div class="boxed">
  <b>Invoice:</b>
    <input [ERROR ->][(ngModel)]= "qty">
</div>
 "): ng:///DynamicTestModule/CalculateComponent.html@2:11
    at syntaxError (./node_modules/@angular/compiler/fesm5/compiler.js?:1275:17)
    at TemplateParser.parse (./node_modules/@angular/compiler/fesm5/compiler.js?:15084:19)
    at JitCompiler._parseTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24272:37)
    at JitCompiler._compileTemplate (./node_modules/@angular/compiler/fesm5/compiler.js?:24259:23)
    at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:62)
    at Set.forEach (<anonymous>)
    at JitCompiler._compileComponents (./node_modules/@angular/compiler/fesm5/compiler.js?:24202:19)
    at eval (./node_modules/@angular/compiler/fesm5/compiler.js?:24120:19)
    at Object.then (./node_modules/@angular/compiler/fesm5/compiler.js?:1266:77)
    at JitCompiler._compileModuleAndAllComponents (./node_modules/@angular/compiler/fesm5/compiler.js?:24118:26)

我从'@ angular / forms'完成了import ;和导入:[FormsModule]我正确拼写了ngModel . 我接下来会发布文件 .

请帮忙 .

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CalculateComponent } from './calculate/calculate.component';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here

@NgModule({
  declarations: [
    AppComponent,
    CalculateComponent
  ],
  imports: [
    FormsModule,
    BrowserModule

  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts 两个版本,一个有一个,一个没有表单的东西 . 不要以为它应该在那里,但也试了一下 . Version 1:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'testKarma';
}

V2

import { Component } from '@angular/core';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; 

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})


@NgModule({
  imports: [
    FormsModule,
   ]
})

export class AppComponent {
  title = 'testKarma';
}

app.component.spec.ts

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { CalculateComponent } from './calculate/calculate.component';  //klf
import { FormsModule } from '@angular/forms'; 
describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent,
        CalculateComponent  
      ],
      imports: [ FormsModule ] 
    }).compileComponents();
  }));
  it('should create the app', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));
  it(`should have as title 'testKarma'`, async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app.title).toEqual('testKarma');
  }));
  it('should render title in a h1 tag', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('h1').textContent).toContain('Welcome to testKarma!');
  }));
});

app.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
</div>
<div>
  <app-calculate></app-calculate>  
</div>

calculate.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-calculate',
  templateUrl: './calculate.component.html',
  styleUrls: ['./calculate.component.css']
})
export class CalculateComponent implements OnInit {

  qty = 0;  

  constructor() { }

  ngOnInit() {
  }
}

calculate.component.html

<div class="boxed">
  <b>Invoice:</b>
    <input [(ngModel)]= "qty">
</div>

calculate.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CalculateComponent } from './calculate.component';

describe('CalculateComponent', () => {
  let component: CalculateComponent;
  let fixture: ComponentFixture<CalculateComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ CalculateComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(CalculateComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

2 回答

  • 0

    @dmcgrandle为我找到答案的简短版本 . (谢谢!!)

    我的主要组件app.component.html包含一个依赖的组件

    <app-calculate></app-calculate>
    

    我已经为ngModel添加了这些必需的行,以便在app.component.ts中工作

    import { FormsModule } from '@angular/forms';
    ...
    
    @NgModule({
      imports: [
        FormsModule,
       ]
    })
    

    当我运行应用程序时,计算组件继承了我将其添加到我的app.component中的表单,并且它工作得很好 . 但是当我运行测试时,它会失败,因为测试是独立运行的,因此计算组件不能使用ngModel . 修复是在calculate.component.spec.ts中包含Forms

    import { FormsModule } from '@angular/forms'; 
    ...
     beforeEach(async(() => {
        TestBed.configureTestingModule({
          imports: [ FormsModule ],  
          declarations: [ CalculateComponent ]
        })
        .compileComponents();
      }));
    
  • 0

    原创想法:

    我看到了一些问题 . 这段代码是否在测试之外工作?首先,在calculate.component.html中 ngModel 之后有一个空格 . 它目前是 [(ngModel)]= "qty" 但应该是 [(ngModel)]="qty"

    其次,我认为你还需要指定'name'属性 . 您已导入FormsModule,但必须在[(ngModel)]中为输入添加名称属性 . 所以在你的情况下你的calculate.component.html看起来像:

    <div class="boxed">
      <b>Invoice:</b>
        <input [(ngModel)]="qty" name="qty">
    </div>
    

    您可能还想指定一个类型,例如 type="text" .

    (这些原始想法不是你问题的根源)

    使用Stackblitz进行更新

    现在我已将您的代码复制到Stackblitz中 . 由于您正在尝试测试CalculateComponent,我通过完全从此测试环境中删除app组件并简单地设置一个行为相同容量的简单TestWrapperComponent来简化,它为CalculateComponent提供了执行的环境 . 然后我得到了从TestWrapperComponent中引用CalculateComponent并可以对其进行测试,例如'qty'变量的值等 . 有关详细信息,请参阅Stackblitz .

    我通过这种方式对它进行单元测试,将CalculateComponent与AppComponent分开并进行单独测试 . 关于单元,集成和e2e测试之间差异的良好讨论here .

    要重现您的错误,我所要做的就是在 calculate.component.spec.ts 中注释掉 FormsModule 的导入,如下所示:

    TestBed.configureTestingModule({
        imports: [ /* FormsModule */ ],
        declarations: [ 
            TestWrapperComponent,
            CalculateComponent
        ]
    }).compileComponents();
    

    注意:当FormsModule正确导入TestBed时,组件会创建并测试而不会出现错误 . 确保将其正确导入到calculate.component.spec.ts中的TestBed中,而不是简单地导入app.component.spec.ts中的TestBed!

相关问题