실제 각도 상속 예제
태그의 자동 완성 처리와 같은 두 가지 공통 기능이 여전히 있기 때문에 코드 중복을 피하기 위해 Angular 구성 요소 상속을 사용하기로 결정했습니다. 이 블로그 게시물에서는 각도 상속에 대한 코드 예제를 보여주고 일부 각도 특성에 이름을 지정합니다.
Source code for this post is available on Github
공통 기본 양식 구성요소
먼저 태그 로드 및 자동 완성을 처리하는 스니펫 기본 양식 클래스를 정의하고 초기 스니펫 메서드 및 탐색 메서드를 만듭니다.
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { Observable } from 'rxjs';
import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { snippet_common_tags } from '../shared/snippet-common-tags';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { Snippet, CodeSnippet } from '../core/model/snippet';
import { map, startWith } from 'rxjs/operators';
import { MatChipInputEvent } from '@angular/material/chips';
import { MatAutocompleteActivatedEvent, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { SuggestedTagsStore } from '../core/user/suggested-tags.store';
import { UserInfoStore } from '../core/user/user-info.store';
import { Params, Router } from '@angular/router';
import { textSizeValidator } from '../core/validators/text-size.validator';
import { HttpResponse } from '@angular/common/http';
import { throwError as observableThrowError } from 'rxjs/internal/observable/throwError';
import { PersonalSnippetsService } from '../core/personal-snippets.service';
import { ErrorService } from '../core/error/error.service';
@Component({
template: ''
})
export class SnippetFormBaseComponent implements OnInit {
snippetFormGroup: FormGroup;
codeSnippetsFormArray: FormArray;
userId = null;
// chips
selectable = true;
removable = true;
addOnBlur = true;
autocompleteTagsOptionActivated = false;
// Enter, comma, space
separatorKeysCodes = [ENTER, COMMA];
commonSnippetTags = snippet_common_tags;
autocompleteTags = [];
tagsControl = new FormControl();
filteredTags: Observable<any[]>;
@Input()
snippet: Snippet;
@ViewChild('tagInput', {static: false})
tagInput: ElementRef;
constructor(
protected formBuilder: FormBuilder,
protected personalSnippetsService: PersonalSnippetsService,
protected suggestedTagsStore: SuggestedTagsStore,
protected userInfoStore: UserInfoStore,
protected router: Router,
protected errorService: ErrorService
) {
}
ngOnInit(): void {
this.userInfoStore.getUserInfo$().subscribe(userInfo => {
this.userId = userInfo.sub;
this.suggestedTagsStore.getSuggestedSnippetTags$(this.userId).subscribe(userTags => {
this.autocompleteTags = userTags.concat(this.commonSnippetTags.filter((item => userTags.indexOf(item) < 0))).sort();
this.filteredTags = this.tagsControl.valueChanges.pipe(
startWith(null),
map((tag: string | null) => {
return tag ? this.filter(tag) : this.autocompleteTags.slice();
})
);
});
});
}
addTag(event: MatChipInputEvent): void {
const input = event.input;
const value = event.value;
if ((value || '').trim() && !this.autocompleteTagsOptionActivated) {
// if ((value || '').trim()) {
this.formArrayTags.push(this.formBuilder.control(value.trim().toLowerCase()));
}
// Reset the input value
if (input) {
input.value = '';
}
this.tagsControl.setValue(null);
this.formArrayTags.markAsDirty();
}
removeTagByIndex(index: number): void {
if (index >= 0) {
this.formArrayTags.removeAt(index);
}
this.formArrayTags.markAsDirty();
}
filter(name: string) {
return this.autocompleteTags.filter(tag => tag.toLowerCase().indexOf(name.toLowerCase()) === 0);
}
optionActivated($event: MatAutocompleteActivatedEvent) {
if ($event.option) {
this.autocompleteTagsOptionActivated = true;
}
}
selectedTag(event: MatAutocompleteSelectedEvent): void {
this.formArrayTags.push(this.formBuilder.control(event.option.viewValue));
this.tagInput.nativeElement.value = '';
this.tagsControl.setValue(null);
this.autocompleteTagsOptionActivated = false;
}
get formArrayTags() {
return <FormArray>this.snippetFormGroup.get('tags');
}
createCodeSnippet(codeSnippet: CodeSnippet): FormGroup {
return this.formBuilder.group({
code: [codeSnippet.code, textSizeValidator(5000, 500)],
comment: codeSnippet.comment
});
}
createInitialCodeSnippet(): FormGroup {
return this.formBuilder.group({
code: ['', textSizeValidator(5000, 500)],
comment: ['', textSizeValidator(1000, 30)]
});
}
createEmptyCodeSnippet(): FormGroup {
return this.formBuilder.group({
code: ['', textSizeValidator(5000, 500)],
comment: ['', textSizeValidator(1000, 30)]
});
}
addEmptyCodeSnippet(index: number): void {
this.codeSnippetsFormArray.insert(index + 1, this.createEmptyCodeSnippet());
}
removeCodeSnippet(index: number) {
this.codeSnippetsFormArray.removeAt(index);
}
createSnippet(snippet: Snippet, copyToMine: boolean, popup: any) {
snippet.userId = this.userId;
const now = new Date();
snippet.lastAccessedAt = now;
if (copyToMine) {
delete snippet['_id'];
snippet.createdAt = now
}
this.personalSnippetsService.createSnippet(this.userId, snippet)
.subscribe(
response => {
const headers = response.headers;
// get the snippet id, which lies in the "location" response header
const lastSlashIndex = headers.get('location').lastIndexOf('/');
const newSnippetId = headers.get('location').substring(lastSlashIndex + 1);
snippet._id = newSnippetId;
const queryParmas = popup ? {popup: popup} : {};
this.navigateToSnippetDetails(snippet, queryParmas)
},
(error: HttpResponse<any>) => {
this.errorService.handleError(error.body.json());
return observableThrowError(error.body.json());
}
);
}
navigateToSnippetDetails(snippet: Snippet, queryParams: Params): void {
const link = [`./my-snippets/${snippet._id}/details`];
this.router.navigate(link, {
state: {snippet: snippet},
queryParams: queryParams
});
}
}
구성 요소 상속
UpdateSnippetFormComponent
및 CreateSnippetFormComponent
구성 요소는그것에서 상속합니다.
예를 들어
CreateSnippetFormComponent
에서 그 중 하나를 살펴보고 특정 사항에 대해 논의해 보겠습니다.// imports ignored for brevity
@Component({
selector: 'app-save-snippet-form',
templateUrl: './create-snippet-form.component.html',
styleUrls: ['./create-snippet-form.component.scss']
})
export class CreateSnippetFormComponent extends SnippetFormBaseComponent implements OnInit {
snippetFormGroup: FormGroup;
codeSnippetsFormArray: FormArray;
userId = null;
@Input()
snippet$: Observable<Snippet>;
@ViewChild('tagInput', {static: false})
tagInput: ElementRef;
snippet: Snippet;
@Input()
code; // value of "desc" query parameter if present
@Input()
title; // value of "title" query parameter if present
@Input()
sourceUrl; // value of "url" query parameter if present
@Input()
tagsStr; // tags received - string with comma separated values
@Input()
comment; // comment received via query
@Input()
popup; // if it's popup window
constructor(
protected formBuilder: FormBuilder,
protected personalSnippetsService: PersonalSnippetsService,
protected suggestedTagsStore: SuggestedTagsStore,
protected userInfoStore: UserInfoStore,
private userDataStore: UserDataStore,
private logger: Logger,
protected router: Router,
private route: ActivatedRoute,
protected errorService: ErrorService,
private webpageInfoService: WebpageInfoService,
private stackoverflowHelper: StackoverflowHelper,
) {
super(formBuilder, personalSnippetsService, suggestedTagsStore, userInfoStore, router, errorService);
}
ngOnInit(): void {
super.ngOnInit();
this.buildInitialForm();
this.codeSnippetsFormArray = this.snippetFormGroup.get('codeSnippets') as FormArray;
if (this.sourceUrl) {
const stackoverflowQuestionId = this.stackoverflowHelper.getStackoverflowQuestionIdFromUrl(this.sourceUrl);
if (stackoverflowQuestionId) {
this.webpageInfoService.getStackoverflowQuestionData(stackoverflowQuestionId).subscribe((webpageData: WebpageInfo) => {
if (webpageData.tags) {
for (let i = 0; i < webpageData.tags.length; i++) {
this.formArrayTags.push(this.formBuilder.control(webpageData.tags[i]));
}
this.tagsControl.setValue(null);
this.formArrayTags.markAsDirty();
}
},
error => {
console.error(`Problems when scraping data for stackoverflow id ${stackoverflowQuestionId}`, error);
});
}
}
this.setTagsFromQueryParameter();
}
private setTagsFromQueryParameter() {
if (this.tagsStr) {
const tags: String[] = this.tagsStr.split(',');
for (let i = 0; i < tags.length; i++) {
this.formArrayTags.push(this.formBuilder.control(tags[i].trim()));
}
this.tagsControl.setValue(null);
this.formArrayTags.markAsDirty();
}
}
buildInitialForm(): void {
this.snippetFormGroup = this.formBuilder.group({
title: [this.title ? this.title : '', Validators.required],
tags: this.formBuilder.array([], [tagsValidator, Validators.required]),
codeSnippets: new FormArray([this.createInitialCodeSnippet()]),
sourceUrl: this.sourceUrl ? this.sourceUrl : '',
public: false
});
}
createInitialCodeSnippet(): FormGroup {
return this.formBuilder.group({
code: [this.code ? this.code : '', textSizeValidator(5000, 500)],
comment: [this.comment ? this.comment : '', textSizeValidator(1000, 30)]
});
}
}
extends
키워드는 상속을 표시하는 데 사용됩니다. - CreateSnippetFormComponent extends SnippetFormBaseComponent
protected
로 정의하고 생성자의 시작 부분에 super
키워드를 사용하여 생성자를 호출해야 합니다. - super(formBuilder, personalSnippetsService, suggestedTagsStore, userInfoStore, router, errorService);
ngOnInit
기능을 트리거하려면 하위 구성 요소에서도 super
키워드를 사용하여 호출해야 합니다(그렇지 않으면 덮어쓰게 됩니다) - super.ngOnInit();
Typescript의 클래스 상속에 대한 자세한 설명은 TypeScript 핸드북의 "Classes" section을 참조하십시오.
다음 gif에서 작동 중인 코드 스니펫 생성 양식을 볼 수 있습니다.
If you have found this useful, please show some love and give us a star on Github
Reference
이 문제에 관하여(실제 각도 상속 예제), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/codepedia/real-life-angular-inheritance-example-3g52텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)