2016-03-17 56 views
33

Tôi đang xây dựng một ứng dụng Angular2 trong Typescript và muốn sử dụng chức năng hệ thống lớp (đọc: thừa kế lớp) được cung cấp bởi Typescript. Tuy nhiên, có vẻ như Angular2 không chơi tốt với các lớp dẫn xuất. Tôi đang tìm kiếm một số trợ giúp để ứng dụng của tôi hoạt động.Angular2 và hỗ trợ kế thừa lớp

Sự cố tôi đang gặp phải là tôi có lớp cơ sở và có một số lớp học trẻ em từ đó. Khi tôi xây dựng cây thành phần của mình, tôi muốn có thể truy cập vào cha/con của các thành phần (hoặc là cách tốt). Từ những gì tôi hiểu, Angular2 cung cấp hai tùy chọn để thực hiện điều đó:

  1. Tiêm phụ huynh vào thành phần con
  2. Sử dụng ContentChildren (hoặc ViewChildren) để truy cập vào những đứa trẻ của các thành phần.

Cả hai hoạt động tốt nếu bạn biết loại lớp bạn đang làm việc (ChildComponent), nhưng có vẻ thất bại khi bạn cố gắng sử dụng lớp cơ sở của các thành phần này (BaseComponent) làm bộ chọn.

Để hình dung nó ở một số mã (xem này Plunker cho một bản demo trực tiếp), tôi có một thành phần ứng dụng/lớp như sau:

@Component({ 
    selector: 'my-app', 
    template: `<parent-comp> 
     <child-comp1></child-comp1> 
     <child-comp1></child-comp1> 
     <child-comp2></child-comp2> 
    </parent-comp>`, 
    directives: [ParentComponent, ChildComponent1, ChildComponent2] 
}) 
export class MyApplication { 
} 

Các Base Class và trẻ em Các lớp học được định nghĩa là:

export class BaseComponent { 
    // Interesting stuff here 
} 

@Component({ 
    selector: 'child-comp2', 
    template: '<div>child component #2</div>' 
}) 
export class ChildComponent2 extends BaseComponent { 
} 

@Component({ 
    selector: 'child-comp1', 
    template: '<div>child component #1</div>' 
}) 
export class ChildComponent1 extends BaseComponent { 
} 

Và lớp cha mẹ có một số logic để đếm con của nó.

@Component({ 
    selector: 'parent-comp', 
    template: `<div>Hello World</div> 
    <p>Number of Child Component 1 items: {{numComp1}} 
    <p>Number of Child Component 2 items: {{numComp2}} 
    <p>Number of Base Component items: {{numBase}} 
    <p><ng-content></ng-content> 
    ` 
}) 
export class ParentComponent implements AfterContentChecked { 

    @ContentChildren(ChildComponent1) contentChild1: QueryList<ChildComponent1> 
    @ContentChildren(ChildComponent2) contentChild2: QueryList<ChildComponent2> 
    @ContentChildren(BaseComponent) contentBase: QueryList<BaseComponent> 
    public numComp1:number 
    public numComp2:number 
    public numBase:number 

    ngAfterContentChecked() { 
    this.numComp1 = this.contentChild1.length 
    this.numComp2 = this.contentChild2.length 
    this.numBase = this.contentBase.length 
    } 

(Một lần nữa, bạn có thể thấy một bản demo sống here)

Kết quả cho hai quầy đầu tiên được như mong đợi. Có 2 ChildComponent1 và 1 ChildComponent2 trẻ em. Không may, bộ đếm BaseComponent không hiển thị tổng của các bộ đếm này, nhưng cho thấy 0. Nó không tìm thấy bất kỳ lớp nào thuộc kiểu BaseComponent ở trẻ em.

Điều tương tự cũng xảy ra khi ParentComponent cũng mở rộng từ BaseComponent và bạn muốn Tiêm nó vào một ChildComponent. Injector sẽ yêu cầu loại ParentComponent cụ thể và không thể làm việc với lớp cơ sở.

Bất kỳ manh mối nào về cách làm việc với các lớp dẫn xuất trong Angular2? Tôi có thiếu một cái gì đó hoặc cố gắng một cái gì đó không thể?

+0

Tôi nghĩ rằng đây là một vấn đề về Góc và cụ thể hơn với việc triển khai ContentChildren và ViewChildren vì vì tôi có thể hiểu rằng họ chỉ sử dụng siêu dữ liệu của đứa trẻ để so sánh nên BaseComponent dài không được bao gồm ở đó đứa trẻ không phải là dded vào QueryList. Tuy nhiên nếu bạn thêm các nhà cung cấp: [BaseComponent] cho con của bạn sẽ có cá thể BaseComponent trong siêu dữ liệu của thành phần và con hiện tại sẽ được thêm vào QueryList EVEN nếu thừa kế không được sử dụng và cũng sẽ tạo ra một cá thể khác của BaseComponent khác với đứa trẻ. –

+0

[Liên kết Plunker] (http://plnkr.co/edit/dpdJvK06OY3o44pWiAMG?p=preview) đối với trường hợp được mô tả trong nhận xét trước. –

+0

@NikolaNikolov: Tôi đã thử đề xuất của bạn khi có BaseComponent làm nhà cung cấp. Điều đó thực sự thêm BaseComponent vào danh sách ContentChildren của cha/mẹ. Tuy nhiên, những trường hợp này, như bạn đã đề cập, khác với các cá thể lớp dẫn xuất. Điều đó thật tệ. – Sjoerd

Trả lời

32

Thêm một nhà cung cấp cho mỗi thành phần có nguồn gốc, răng cưa các thành phần cơ bản để các thành phần có nguồn gốc:

@Component({ 
    selector: 'child-comp2', 
    template: '<div>child component #2</div>', 
    providers: [{provide: BaseComponent, useExisting: forwardRef(() => ChildComponent2) }] 
}) 
export class ChildComponent2 extends BaseComponent { 
} 

@Component({ 
    selector: 'child-comp1', 
    template: '<div>child component #1</div>', 
    providers: [{provide: BaseComponent, useExisting: forwardRef(() => ChildComponent1) }] 
}) 
export class ChildComponent1 extends BaseComponent { 
} 

Plunker: http://plnkr.co/edit/5gb5E4curAE2EfH2lNZQ?p=preview

+0

Cảm ơn, điều đó dường như hoạt động! Tôi cũng đã kiểm tra xem bạn có thực sự có được cá thể được tạo ra chứ không phải là một cá thể thành phần riêng biệt hay không, và điều đó cũng có vẻ hoạt động chính xác: http://plnkr.co/edit/KSchL5dOCebxEQU692u9?p=preview – Sjoerd

+0

cách bạn xử lý các phụ thuộc của BaseClass trong constructor? –

+0

@TobiasGassmann: Bạn nên đăng câu hỏi mới với ví dụ cụ thể. –

0

Bạn có thể sử dụng một biến mẫu địa phương với một truy vấn ContentChildren để tạo ra một danh sách của tất cả các thành phần với một lớp cơ sở được chia sẻ. Dưới đây là một số plunk cho mã bên dưới. Cách tiếp cận này được lấy từ đề xuất trong bài đăng blog Rookie mistakes của Kara Erickson.

Trong mẫu mỗi thành phần con được đánh dấu bằng #child:

<app-container> 
    <app-child1 #child></app-child1> 
    <app-child1 #child></app-child1> 
    <app-child1 #child></app-child1> 
    <app-child1 #child></app-child1> 
    <app-child2 #child></app-child2> 
    </app-container> 

này sau đó có thể được sử dụng để chọn tất cả các thành phần với các thành phần cơ bản chia sẻ:

import { Component, QueryList, ContentChildren, ViewChildren, AfterViewInit, AfterContentInit } from '@angular/core'; 
    import { BaseComponent } from '../base/base.component'; 
    import { Child1Component } from '../child1/child1.component'; 
    import { Child2Component } from '../child2/child2.component'; 

    @Component({ 
    selector: 'app-container', 
    templateUrl: './src/container/container.component.html' 
    }) 
    export class ContainerComponent implements AfterContentInit { 
    @ContentChildren('child') allChildren: QueryList<BaseComponent>; 
    @ContentChildren(Child1Component) child1Chdilren: QueryList<Child1Component>; 
    @ContentChildren(Child2Component) child2Chdilren: QueryList<Child2Component>; 

    constructor() { } 

    ngOnInit() { 
    } 

    ngAfterContentInit() { 
    } 

    } 
Các vấn đề liên quan