首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >角8通用部件

角8通用部件
EN

Stack Overflow用户
提问于 2019-09-17 08:50:46
回答 2查看 6.2K关注 0票数 1

我有许多逻辑几乎相同的组件。例如:

代码语言:javascript
运行
复制
import { Component, OnInit } from '@angular/core';

import { Rule } from '@models';
import { ConfirmationDialogComponent } from '@core';
import { RulesSaveComponent } from './rules-save.component';
import { RuleService } from '@services';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
    selector: 'app-rules',
    templateUrl: './rules.component.html',
    styleUrls: ['./rules.component.scss'],
})
export class RulesComponent implements OnInit {
    rules: Rule[];

    constructor(private modalService: NgbModal, private ruleService: RuleService) {}

    ngOnInit() {
        this.ruleService.items.subscribe(rules => (this.rules = rules));
    }

    openModal(id: number) {
        const modalRef = this.modalService.open(ConfirmationDialogComponent);
        modalRef.componentInstance.message = 'Deleting a rule is irreversible. Do you wish to continue?';
        modalRef.result.then(
            () => {
                this.ruleService.delete(id);
            },
            () => {
                // Do nothing
            },
        );
    }

    openSaveForm(rule: Rule) {
        const modalRef = this.modalService.open(RulesSaveComponent);
        modalRef.componentInstance.feedId = rule.feedId;
        modalRef.componentInstance.ruleId = rule.id;
        modalRef.componentInstance.modal = true;
    }
}

和:

代码语言:javascript
运行
复制
import { Component, OnInit } from '@angular/core';

import { Conversion } from '@models';
import { ConfirmationDialogComponent } from '@core';
import { ConversionsSaveComponent } from './conversions-save.component';
import { ConversionService } from '@services';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
    selector: 'app-conversions',
    templateUrl: './conversions.component.html',
    styleUrls: ['./conversions.component.scss'],
})
export class ConversionsComponent implements OnInit {
    conversions: Conversion[];

    constructor(private modalService: NgbModal, private conversionService: ConversionService) {}

    ngOnInit() {
        this.conversionService.items.subscribe(conversions => (this.conversions = conversions));
    }

    openModal(id: number) {
        const modalRef = this.modalService.open(ConfirmationDialogComponent);
        modalRef.componentInstance.message = 'Deleting a conversion is irreversible. Do you wish to continue?';
        modalRef.result.then(
            () => {
                this.conversionService.delete(id);
            },
            () => {
                // Do nothing
            },
        );
    }

    openSaveForm(conversion: Conversion) {
        const modalRef = this.modalService.open(ConversionsSaveComponent);
        modalRef.componentInstance.feedId = conversion.feedId;
        modalRef.componentInstance.conversionId = conversion.id;
        modalRef.componentInstance.modal = true;
    }
}

或者为了保存细节,我有:

代码语言:javascript
运行
复制
import { Component, OnInit, Input } from '@angular/core';
import { first } from 'rxjs/operators';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { Rule } from '@models';
import { RuleService } from '@services';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
    selector: 'app-rules-save',
    templateUrl: './rules-save.component.html',
    styleUrls: ['./rules-save.component.scss'],
})
export class RulesSaveComponent implements OnInit {
    @Input() feedId: number;
    @Input() id: number;
    @Input() modal: boolean;
    saveForm: FormGroup;
    loading = false;
    submitted = false;
    editing: boolean;

    constructor(
        private activeModal: NgbActiveModal,
        private formBuilder: FormBuilder,
        private ruleService: RuleService,
    ) {}

    ngOnInit() {
        this.get(this.feedId);
    }

    // convenience getter for easy access to form fields
    get f() {
        return this.saveForm.controls;
    }

    onSubmit() {
        this.submitted = true;

        if (this.saveForm.invalid) {
            return;
        }

        let rule: Rule = {
            id: this.id,
            feedId: this.feedId,
            name: this.f.name.value,
            fieldName: this.f.fieldName.value,
            filterOperator: this.f.filterOperator.value,
            expression: this.f.expression.value,
        };

        this.loading = true;
        this.ruleService[this.editing ? 'update' : 'create'](rule).subscribe(() => {
            this.reset();
            this.activeModal.close('ok');
        });
    }

    private get(feedId: number) {
        this.editing = !!this.id;

        if (this.editing) {
            this.ruleService.get(this.id).subscribe(rule => {
                this.buildForm(rule);
            });
        } else {
            var rule = new Rule();

            rule.id = 0;
            rule.feedId = feedId;

            this.buildForm(rule);
        }
    }

    private buildForm(rule: Rule) {
        this.saveForm = this.formBuilder.group({
            name: [rule.name, Validators.required],
            fieldName: [rule.fieldName, Validators.required],
            filterOperator: [rule.filterOperator, Validators.required],
            expression: [rule.expression, Validators.required],
        });
    }

    private reset() {
        if (this.editing) return;

        this.submitted = false;
        this.saveForm.reset();
    }
}

代码语言:javascript
运行
复制
import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { Conversion } from '@models';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ConversionService } from '@services';

@Component({
    selector: 'app-conversions-save',
    templateUrl: './conversions-save.component.html',
    styleUrls: ['./conversions-save.component.scss'],
})
export class ConversionsSaveComponent implements OnInit {
    @Input() feedId: number;
    @Input() id: number;
    @Input() modal: boolean;
    saveForm: FormGroup;
    loading = false;
    submitted = false;
    editing: boolean;

    constructor(
        private activeModal: NgbActiveModal,
        private formBuilder: FormBuilder,
        private conversionService: ConversionService,
    ) {}

    ngOnInit() {
        this.get(this.feedId);
    }

    // convenience getters for easy access to form fields
    get f() {
        return this.saveForm.controls;
    }

    onSubmit() {
        this.submitted = true;

        if (this.saveForm.invalid) {
            return;
        }

        let conversion: Conversion = {
            id: this.id,
            feedId: this.feedId,
            name: this.f.name.value,
            fieldName: this.f.fieldName.value,
            filterOperator: this.f.filterOperator.value,
            expression: this.f.expression.value,
            mathOperator: this.f.mathOperator.value,
            value: this.f.value.value,
        };

        this.loading = true;
        this.conversionService[this.editing ? 'update' : 'create'](conversion).subscribe(() => {
            this.reset();
            this.activeModal.close('ok');
        });
    }

    private get(feedId: number) {
        this.editing = !!this.id;

        if (this.editing) {
            this.conversionService.get(this.id).subscribe(conversion => {
                this.buildForm(conversion);
            });
        } else {
            var conversion = new Conversion();

            conversion.id = 0;
            conversion.feedId = feedId;

            this.buildForm(conversion);
        }
    }

    private buildForm(conversion: Conversion) {
        this.saveForm = this.formBuilder.group({
            name: [conversion.name, Validators.required],
            fieldName: [conversion.fieldName, Validators.required],
            filterOperator: [conversion.filterOperator, Validators.required],
            expression: [conversion.expression, Validators.required],
            mathOperator: [conversion.mathOperator, Validators.required],
            value: [conversion.value, Validators.required],
        });
    }

    private reset() {
        if (this.editing) return;

        this.submitted = false;
        this.saveForm.reset();
    }
}

两者之间根本没有太大的区别。实际上,对于每种类型(、list、、Save),您可以看到它们之间的更改是相同的。因此,在列表组件中,更改如下:

  • 注入服务(RuleServiceConversionService),
  • 消息。

除此之外,它们是相同的。

对于保存组件,更改如下:

  • 注入服务
  • 在保存
  • 之前建立的模型用于创建表单组

buildForm方法

所以,因为我重复了很多次相同的模式,所以我希望有一种方法来做一个泛型组件?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-19 09:48:09

我不喜欢别人给我的答案,所以我决定自己发狂。这是我的解决方案(这是列表组件):

代码语言:javascript
运行
复制
import { Component, OnInit, ViewChild } from '@angular/core';

import { FilterResource } from 'src/app/_core/models/filter-resource';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
import { BaseSaveComponent } from './base-save.component';
import { DataService } from 'src/app/_core/services/data.service';

@Component({
    selector: 'app-base-list',
    templateUrl: './base-list.component.html',
    styleUrls: ['./base-list.component.scss'],
})
export class BaseListComponent<T extends FilterResource> implements OnInit {
    @ViewChild(ConfirmationDialogComponent, { static: true }) confirmationDialog: ConfirmationDialogComponent;
    @ViewChild(BaseSaveComponent, { static: true }) saveForm: BaseSaveComponent<T>;
    items: T[];

    constructor(private dataService: DataService<T>, private deleteMessage: string) {}

    ngOnInit() {
        this.dataService.items.subscribe(items => (this.items = items));
    }

    openModal(id: number) {
        this.confirmationDialog.message = this.deleteMessage;
        this.confirmationDialog.open();
        this.confirmationDialog.closed.subscribe(() => {
            this.dataService.delete(id);
        });
    }

    openSaveForm(model: T) {
        this.saveForm.id = model.id;
        this.saveForm.feedId = model.feedId;
        this.saveForm.open();
    }
}

FilterResource就是这样的:

代码语言:javascript
运行
复制
export class FilterResource {
    public id: number;
    public feedId: number;
}

无论如何,我的DataService是通用的:

代码语言:javascript
运行
复制
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

import { environment } from '@environments/environment';
import { Resource } from '../models/resource';
import { ToastrService } from 'ngx-toastr';
import { BehaviorSubject } from 'rxjs';

@Injectable({
    providedIn: 'root',
})
export class DataService<T extends Resource> {
    items: BehaviorSubject<T[]>;

    constructor(private endpoint: string, private http: HttpClient, private toastr: ToastrService) {
        this.items = new BehaviorSubject<T[]>([]);
    }

    initialize(feedId: number) {
        this.http.get<T[]>(`${environment.apiUrl}/feeds/${feedId}/${this.endpoint}`).subscribe(response => {
            this.items.next(response);
        });
    }

    get(id: number) {
        return this.http.get<T>(`${environment.apiUrl}/${this.endpoint}/${id}`);
    }

    create(filter: T) {
        return this.http.post<T>(`${environment.apiUrl}/${this.endpoint}`, filter).pipe(
            map((response: any) => {
                const message = response.message;
                const item = response.model;

                let items = this.items.value;
                items.push(item);

                this.emit(items, message);

                return response.model;
            }),
        );
    }

    update(filter: T) {
        return this.http.put<T>(`${environment.apiUrl}/${this.endpoint}`, filter).pipe(
            map((response: any) => {
                const message = response.message;
                const item = response.model;

                let items = this.items.value;
                this.remove(items, filter.id);
                items.push(item);

                this.emit(items, message);

                return response.model;
            }),
        );
    }

    delete(id: number) {
        this.http.delete<any>(`${environment.apiUrl}/${this.endpoint}/${id}`).subscribe(response => {
            let items = this.items.value;
            items.forEach((item, i) => {
                if (item.id !== id) return;
                items.splice(i, 1);
            });

            this.emit(items, response.message);
        });
    }

    private remove(items: T[], id: number) {
        items.forEach((item, i) => {
            if (item.id !== id) return;
            items.splice(i, 1);
        });
    }

    private emit(items: T[], message: string) {
        this.items.next(items);
        this.toastr.success(message);
    }
}

因此,这意味着我能够扩展组件:

代码语言:javascript
运行
复制
import { Component } from '@angular/core';

import { Filter } from '@models';
import { FilterService } from '@services';
import { BaseListComponent } from '../base/base-list.component';

@Component({
    selector: 'app-filters',
    templateUrl: './filters.component.html',
    styleUrls: ['./filters.component.scss'],
})
export class FiltersComponent extends BaseListComponent<Filter> {
    constructor(filterService: FilterService) {
        super(filterService, 'Deleting a filter is irreversible. Do you wish to continue?');
    }
}

我也是用同样的方式救的。

票数 4
EN

Stack Overflow用户

发布于 2019-09-17 09:07:46

您可以创建作为服务工厂的服务,抽象出实际使用的服务,因为它们具有相同的接口。

伪码:

代码语言:javascript
运行
复制
export class FactoryService {
  constructor(private rule_service: RuleService, private conversion_service: ConversionService) { }

  public correctService(name: string): MyServiceInterface {
    if(name === 'rule') {
      return this.rule_service;
    } else if (name === 'conversion') {
      return this.conversion_service
    } else {
      // Handle error...
    }
  }
}

其中定义了带有正确签名的MyServiceInterface类型,以便它是干净的。

然后从代码中调用this.factory_service.correctService('rule').delete(id)等等。

对于buildForm来说也是一样,用工厂服务进行抽象。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57970640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档