Angular2: наследование компонентов

Внезапно, совсем в другом проекте, мне нужно было сделать наследование компонентов. Так как я не очень люблю катпастить и потом пять раз бегать по коду и менять схожие функции. Но другой проект — уже большой и сложный, поэтому в упрощенном варианте на текущем демопроекте и будет показано как собственно по-быстрому отнаследовать схожие функции и не заниматься мутотенью потом. Репозиторий примера BlogDemo.

Создание второго компонента

Чтобы было на чем показывать — давайте к блогу сделаем таблицу комментов. Прямо и тупо скопировав уже существующую схему — джейсон, структура данных и компонент (см. предыдущий пример)

api/second.json

{
	"data" : [
		{
			"id" : 11,
			"date" : "2016-09-01",
			"author" : "Vasya Pupkin",
			"title" : "Blog Comment 1",
			"text" : "Some comment text"
		},
		{
			"id" : 2,
			"date" : "2016-09-11",
			"author" : "Vasya Pupkindze",
			"title" : "Blog Comment 2",
			"text" : "Another comment text"
		}
	],
	"total" : 100,
	"code" : 200
}

second/second.data.ts

export class Record {
	id:string;
	author:string;
	date:string;
	title:string;
	text:string;
}
export class SecondResponse {
	data:Record[];
	total:number;
	code:number;
}

second/second.component.ts

import {Component} from '@angular/core';
 
import {HTTP_PROVIDERS} from '@angular/http';
import {AppService} from './../app.service';
import {SecondResponse} from './second.data';
 
@Component({
	selector: 'my-app-second',
	template: `<h1>Second Application</h1>
			<table *ngIf="result.data">
				<tr *ngFor="let entry of result.data">
					<td valign="top">{{entry.author}}</td>
					<td valign="top">{{entry.title}}</td>
					<td valign="top">{{entry.text}}</td>					
				</tr>
			</table>
 
	`,
	providers: [AppService, HTTP_PROVIDERS],
})
class SecondComponent {
	public result : SecondResponse;
	constructor(private appService:AppService) {
		this.result = new SecondResponse();
		this.appService.get('api/second.json')
			.then(response => this.setResponse(response.json() as SecondResponse))
			.catch(this.appService.handleError);
	}
 
	public setResponse(result:SecondResponse) {
		this.result = result;
	}
}
 
export {SecondComponent};

main.ts

Не забудем дописать инициализацию и вставить в шаблон

import {bootstrap}    from '@angular/platform-browser-dynamic';
 
import {AppComponent} from './app.component';
import {SecondComponent} from './second/second.component';
 
bootstrap(AppComponent);
bootstrap(SecondComponent);
<body>
<my-app>Loading...</my-app>
<my-app-second>Loading Secondary App...</my-app-second>
</body>

Избавление от копипаста

Как мы видим — у компонента второго только тип данных и ссылка отличаются… а добавим пейджинг, сортировку и тд — и что, в каждом из них копировать? на это мы пойти не можем — будем упрощать — введем еще два класса

basic/basic.data.ts

 

basic/basic.data.ts

export class Record {
	id:string;
}
export class BasicResponse {
	data:Record[];
	total:number;
	code:number;
}

basic/basic.component.ts

import {Component} from '@angular/core';
 
import {HTTP_PROVIDERS} from '@angular/http';
import {AppService} from '../app.service';
import {BasicResponse} from './basic.data';
 
class BasicComponent {
	public result:BasicResponse;
	public url:'plz_set';
 
	constructor(private appService:AppService, url) {
		this.url = url;
		this.appService.get(this.url)
			.then(response => this.setResponse(response.json() as BasicResponse))
			.catch(this.appService.handleError);
	}
 
	public setResponse(result:BasicResponse) {
		this.result = result;
	}
}
 
export {BasicComponent};

Внимание, пример который хочется написать по аналогии с php — писать нельзя, консоль.лог выведет пустое значение

basic/basic.component.ts

class BasicComponent {
	public url:'plz_set';
 
	constructor(private appService:AppService) {
		console.log(this.url);
	}
}
class OtherComponent extends BasicComponent {
	public url:'other_value';
        constructor(private appService:AppService) {
		super(appService);
	}
 
}

Перепишем наши компоненты с наследованием

app.component.ts

import {Component} from '@angular/core';
 
import {HTTP_PROVIDERS} from '@angular/http';
import {AppService} from './app.service';
import {DataResponse} from './app.data';
import {BasicComponent} from "./basic/basic.component";
 
@Component({
	selector: 'my-app',
	template: `<h1>My First Angular 2 App</h1>
			<div *ngIf="result.data">
				<div *ngFor="let entry of result.data">
					<h2>{{entry.title}}</h2>
					<p>{{entry.intro}}</p>					
				</div>
			</div>
 
	`,
	providers: [AppService, HTTP_PROVIDERS],
})
class AppComponent extends BasicComponent{
	public result : DataResponse;
	constructor(private appService:AppService) {
		super(appService, 'api/data.json');
		this.result = new DataResponse();
	}
}
 
export {AppComponent};

second/second.component.ts

import {Component} from '@angular/core';
 
import {HTTP_PROVIDERS} from '@angular/http';
import {AppService} from './../app.service';
import {SecondResponse} from './second.data';
import {BasicComponent} from "../basic/basic.component";
 
@Component({
	selector: 'my-app-second',
	template: `<h1>Second Application</h1>
			<table *ngIf="result.data">
				<tr *ngFor="let entry of result.data">
					<td valign="top">{{entry.author}}</td>
					<td valign="top">{{entry.title}}</td>
					<td valign="top">{{entry.text}}</td>					
				</tr>
			</table>
 
	`,
	providers: [AppService, HTTP_PROVIDERS],
})
class SecondComponent extends BasicComponent{
	public result : SecondResponse;
	constructor(private appService:AppService) {
		super(appService, 'api/second.json');
		this.result = new SecondResponse();
	}
}
 
export {SecondComponent};

Что должно выйти в итоге — мухи отдельно, котлеты отдельно, красота и эс

два компонента на одной странице Angular 2

2 комментария “Angular2: наследование компонентов”

  1. Святослав

    Есть проблема, что метаданные не наследуются. Например, если мы заходим template родительского оставить без изменений или обернуть в свой тег, то это не получится сделать. Если знаете как сделать, будет здорово дополнить статью.

    Ответить
    • к сожалению прямо темплейты — нет, но можно 1) вынести темплейт в файл и использовать один файл и там и там 2) вынести его в директиву… нужно посмотреть на 4ый ангуляр — возможно эту проблему там решили, у меня на продакшен проектах по факту вообще ни разу не стала необходимость шаблоны отнаследовать

      Ответить

Оставить комментарий

XHTML: Вы можете использовать такие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">