Angular 5 ng-content问题

时间:2018-03-20 07:17:18

标签: typescript angular-cli angular5 ng-content

当我在Angular 5中的两个组件之间实现 ng-content 时,我遇到了奇怪的问题。

这是我的第一个组件是FooterComponent

<div class="footer">
  <ng-content select="footer"></ng-content>
</div>

和footer.component.ts

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

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

  constructor() { }

  ngOnInit() {
  }

}

第二个组件是AboutComponent

<app-footer>
  <footer>
   this is my footer
  </footer>
</app-footer>

这个app-module.ts在第一次尝试和第二次尝试我导入about.module.ts或footer.module.ts而不是AboutComponent和FooterComponent。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AppComponent } from './app.component';
import { AboutComponent } from './about/about.component';
import { FooterComponent } from './footer/footer.component';

@NgModule({
  declarations: [
    AppComponent,
    AboutComponent,
    FooterComponent
  ],
  imports: [
    BrowserModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }

app.component.html只有router-outlet标签

<router-outlet></router-outlet>

所以我有两个问题,第一个是当我使用 ng serve 命令行运行Angular时,我没有看到任何输出。第二个也是重要的一个是当我运行 ng test 命令行时,我看到了这个Bug ......

AboutComponent should create
  Failed: Template parse errors:
  'app-footer' is not a known element:
  1. If 'app-footer' is an Angular component, then verify that it is part of 
     this module.
  2. If 'app-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to 
     the '@NgModule.schemas' of this component to suppress this message. ("
     [ERROR ->]<app-footer>
     <footer>
     this is my footer
     "): ng:///DynamicTestModule/AboutComponent.html@0:0

所以我一直尝试很多像

这样的解决方案
  1. 生成about.module.ts并导入 CUSTOM_ELEMENTS_SCHEMA 并尝试 NO_ERRORS_SCHEMA 。并导入FooterComponent并最终在app.module.ts中导入about.module.ts

  2. 我使用FooterComponent做同样的事情。

  3. 我一直在尝试在每个模块中使用 CUSTOM_ELEMENTS_SCHEMA NO_ERRORS_SCHEMA ,这给了我相同的结果。

  4. 这个package.json

    {
     "name": "ng-app",
     "version": "0.0.0",
     "license": "MIT",
     "scripts": {
       "ng": "ng",
       "start": "ng serve",
       "build": "ng build --prod",
       "test": "ng test",
       "lint": "ng lint",
       "e2e": "ng e2e"
      },
      "private": true,
      "dependencies": {
        "@angular/animations": "^5.2.0",
        "@angular/common": "^5.2.0",
        "@angular/compiler": "^5.2.0",
        "@angular/core": "^5.2.0",
        "@angular/forms": "^5.2.0",
        "@angular/http": "^5.2.0",
        "@angular/platform-browser": "^5.2.0",
        "@angular/platform-browser-dynamic": "^5.2.0",
        "@angular/router": "^5.2.0",
        "core-js": "^2.4.1",
        "rxjs": "^5.5.6",
        "zone.js": "^0.8.19"
      },
      "devDependencies": {
        "@angular/cli": "~1.7.3",
        "@angular/compiler-cli": "^5.2.0",
        "@angular/language-service": "^5.2.0",
        "@types/jasmine": "~2.8.3",
        "@types/jasminewd2": "~2.0.2",
        "@types/node": "~6.0.60",
        "codelyzer": "^4.0.1",
        "jasmine-core": "~2.8.0",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "~2.0.0",
        "karma-chrome-launcher": "~2.2.0",
        "karma-coverage-istanbul-reporter": "^1.2.1",
        "karma-jasmine": "~1.1.0",
        "karma-jasmine-html-reporter": "^0.2.2",
        "protractor": "~5.1.2",
        "ts-node": "~4.1.0",
        "tslint": "~5.9.1",
        "typescript": "~2.5.3"
      }
    }
    

    最后我创建了这个新的Angular-cli项目。

    感谢。

1 个答案:

答案 0 :(得分:1)

您需要做的第一件事是在 app.module.ts 中加入RouterModule。您正在尝试使用路由器插座(<router-outlet></router-outlet>)。那不行。

更新了 app.module.ts

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

import { AppComponent } from './app.component';
import { FooterModule } from './footer/footer.module';
import { FooterComponent } from './footer/footer.component';

@NgModule({
declarations: [
    AppComponent
],
imports: [
    BrowserModule,
    FooterModule,
    RouterModule.forRoot([
        {path: '', component: FooterComponent}
    ])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

查看RouterModule的新导入。此外,在将RouterModule添加到imports数组后,我还添加了一个转到FooterComponent的默认路由。我需要一些东西去寻找,这就是我选择的。随着应用程序的进展,将其更改为您喜欢的内容。

提醒您,即使进行了这些更改,您也不会在浏览器中看到任何内容。您需要向页脚添加一些内容才能看到内容。我会把那部分留给你。如果在运行ng serve时右键单击并检查主页面,您将看到页脚元素确实已呈现(它们只是没有任何有价值的内容)。

就测试而言,您需要将FooterComponent添加到AboutComponent规范中的声明部分以及导入。更新了以下规格。

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

import { AboutComponent } from './about.component';

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

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

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

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

由于AboutComponent正在托管FooterComponent,因此单元测试需要了解混合中的所有组件。这就解决了这个问题。

然后,为了清除最终错误,您将与测试AppComponent相关,您需要模拟路由器插座以在规范中使用。该代码如下。

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { Component } from '@angular/core';

describe('AppComponent', () => {
beforeEach(async(() => {
    TestBed.configureTestingModule({
    declarations: [
        AppComponent, RouterOutletStubComponent
    ],
    }).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 'app'`, async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app.title).toEqual('app');
}));
});


@Component({selector: 'router-outlet', template: ''})
class RouterOutletStubComponent { }

由于您删除了AppComponent的所有原始HTML以将其用作路由器插座,因此我不得不删除其中一个单元测试,因为不再需要它。

RouterOutletStubComponent在这里很有意思。这允许AppComponent单元测试成功运行。此时所有AppComponent都是路由器出口容器。

快乐的编码!