角度(Angular):由于它不是'input'的已知属性(不能重复),因此无法绑定到'ngModel'

时间:2018-11-22 19:49:18

标签: angular jasmine ngmodel

我在同一主题上阅读了许多帖子,但是我99%的确定我已经遵守了所有答案。 从ng new为您创建的非常基本的应用开始。它运行良好,通过了3个Karma测试。 我使用ngModel使用一个输入<==>打字稿链接添加了一个新组件,但此错误无法测试新组件:

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”导入{FormsModule}; 并导入:[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 两种版本,一种带有表单,另一种没有表单。不要以为它应该在那里,但也可以尝试一下。 版本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 :(得分:0)

原始思想:

我看到了一些问题。这段代码在测试之外有效吗?首先,calculate.component.html中ngModel后面有一个空格。当前为[(ngModel)]= "qty",但应为[(ngModel)]="qty"

第二,我相信您也需要指定'name'属性。您已经导入了FormsModule,但是必须在[(ngModel)]中添加具有相同名称的输入的name属性。因此,在您的情况下,calculate.component.html类似于:

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

您可能还需要指定一种类型,例如type="text"

(这些原始想法不是问题的出处)

使用Stackblitz更新

现在,我已将您的代码复制到Stackblitz中。由于您正在尝试测试CalculateComponent,因此我从此测试环境中完全消除了应用程序组件,并仅设置了一个以相同容量运行的简单TestWrapperComponent,从而简化了很多工作-它为CalculateComponent提供了执行环境。从TestWrapperComponent内对CalculateComponent的引用,并可以在其上进行测试,例如'qty'变量的值等。有关详细信息,请参见Stackblitz。

我以这种方式进行了设置,以分别对CalculateComponent和AppComponent进行单元测试。对单元测试,集成测试和端到端测试here之间的区别进行了很好的讨论。

要重现您的错误,我要做的就是注释掉FormsModulecalculate.component.spec.ts的导入,就像这样:

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

注意:将FormsModule正确导入到TestBed中后,该组件将创建并测试无误。确保将其正确导入到calculate.component.spec.ts中的TestBed中,而不是简单导入到 app.component.spec.ts中的一个中!

答案 1 :(得分:0)

@dmcgrandle为我找到的简短答案。 (谢谢!)

我的主要组件app.component.html包含从属组件

def do_OPTIONS(self):
    self.send_response(200,"ok")
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header("Access-Control-Allow-Methods", "*")
    self.send_header("Access-Control-Allow-Headers", "*")
    self.end_headers()

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

<app-calculate></app-calculate>  

运行应用程序时,calculate组件继承了将其添加到app.component中的Forms,并且工作正常。但是,当我运行ng测试时,它会失败,因为测试是独立运行的,因此计算组件无法使用ngModel。解决方法是将表格包含在calculate.component.spec.ts

import { FormsModule } from '@angular/forms';
...

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