我一直在寻找过去几天的答案,但我找不到解决方案。
我有一个基页组件,所有其他页面都扩展了它,因为涉及到大量的crud页面。在我的场景中,我创建了一个模态和ng-content选择器,以便在需要时填充输入。
代码:
基页list.component.html
<section class="widget animated fadeIn" widget>
<header>
<h4 class="page-title" *ngIf="pageType !== PageType.TAB">
<ng-content select=".page-title"></ng-content>
</h4>
<div class="widget-controls">
<a data-widgster="expand" title="Expand" href="#"><i class="glyphicon glyphicon-chevron-up"></i></a>
<a data-widgster="collapse" title="Collapse" href="#"><i class="glyphicon glyphicon-chevron-down"></i></a>
</div>
</header>
<div class="widget-body" [ngSwitch]='status'>
<div class="mt-0 clearfix">
<alert *ngFor="let toast of alertService.toasts; let i = index" [type]="toast.type + ' alert-sm'" (close)="alertService.closeToast(i)" dismissible="true" dismissOnTimeout="5000">
<div [innerHTML]="toast.msg"></div>
</alert>
<!-- Spinner -->
<div class="sk-fading-circle" *ngSwitchCase="status === PageStatus.LOADING || status === PageStatus.EASY_LOADING ? status : -1">
<div class="sk-circle1 sk-circle"></div>
<div class="sk-circle2 sk-circle"></div>
<div class="sk-circle3 sk-circle"></div>
<div class="sk-circle4 sk-circle"></div>
<div class="sk-circle5 sk-circle"></div>
<div class="sk-circle6 sk-circle"></div>
<div class="sk-circle7 sk-circle"></div>
<div class="sk-circle8 sk-circle"></div>
<div class="sk-circle9 sk-circle"></div>
<div class="sk-circle10 sk-circle"></div>
<div class="sk-circle11 sk-circle"></div>
<div class="sk-circle12 sk-circle"></div>
</div>
<!-- Spinner End -->
<!--Tables-->
<div *ngSwitchCase="status == PageStatus.DONE || status === PageStatus.EASY_LOADING ? status : -1">
<div class="form-control-static">
<div class="form-group pull-left">
<ng-content select="custom-filter-content"></ng-content>
</div>
<!-- Search Box -->
<div class="form-group pull-right">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-search"></i></span>
<input type="text" class="form-control" [(ngModel)]="filter.searchTerm"
[disabled]="false"
(keyup.enter)="runQuery()"
placeholder="{{'global.label.search' | translate}}"/>
<div class="input-group-btn">
<button type="button" class="btn btn-default" (click)="reset()">
<i class="fa fa-refresh text-primary"></i>
</button>
</div>
</div>
</div>
<!-- Search Box End -->
<div *ngIf="isFiltered() && isSearchResultEmpty()">
<label>{{'global.label.nodata' | translate}}</label>
<ng-content select="table-no-data"></ng-content>
</div>
</div>
<div *ngIf="isFiltered() && !isSearchResultEmpty()" class="form-control-static">
<ng-content select="table-content"></ng-content>
</div>
</div>
<!-- Tables End -->
</div>
<!-- Table Buttons -->
<div class="form-actions">
<button class="btn btn-inverse" (click)="showModal(ModalState.CREATE)">
<i class="glyphicon glyphicon-plus-sign text-warning"></i>
{{'global.label.addNew' | translate}}
</button>
<ng-content select="table-buttons"></ng-content>
</div>
<!-- Table Buttons End -->
</div>
</section>
<!-- Modal -->
<div bsModal #modal="bs-modal" data-backdrop="true" data-keyboard="false" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button (click)="modal.hide()" aria-label="Close" class="close" role="button">
<span aria-hidden="true">×</span>
</button>
<div [ngSwitch]="modalState">
<h4 class="modal-title" *ngSwitchCase="ModalState.CREATE">{{'global.label.addNew' | translate}}</h4>
<h4 class="modal-title" *ngSwitchCase="ModalState.UPDATE">{{'global.label.editRecord' | translate}}</h4>
</div>
</div>
<form #recordForm="ngForm" enctype="multipart/form-data">
<div class="modal-body">
<!-- Spinner -->
<div class="sk-fading-circle" *ngIf="status === PageStatus.LOADING || status === PageStatus.EASY_LOADING">
<div class="sk-circle1 sk-circle"></div>
<div class="sk-circle2 sk-circle"></div>
<div class="sk-circle3 sk-circle"></div>
<div class="sk-circle4 sk-circle"></div>
<div class="sk-circle5 sk-circle"></div>
<div class="sk-circle6 sk-circle"></div>
<div class="sk-circle7 sk-circle"></div>
<div class="sk-circle8 sk-circle"></div>
<div class="sk-circle9 sk-circle"></div>
<div class="sk-circle10 sk-circle"></div>
<div class="sk-circle11 sk-circle"></div>
<div class="sk-circle12 sk-circle"></div>
</div>
<!-- Spinner End -->
<ng-content select="modal-body-content"></ng-content>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-gray" (click)="modal.hide()">
{{'global.button.close' | translate}}
</button>
<span [ngSwitch]="modalState">
<button *ngSwitchCase="ModalState.CREATE" role="button" [disabled]="status === PageStatus.LOADING || !recordForm.form.valid" class="btn btn-success" (click)="onAddItem()">
<i class="fa fa-spinner fa-spin" [hidden]="status !== PageStatus.LOADING"></i>
{{'global.button.save' | translate}}
</button>
<button *ngSwitchCase="ModalState.UPDATE" role="button" [disabled]="status === PageStatus.LOADING || !recordForm.form.valid" class="btn btn-info" (click)="onUpdateItem()">
<i class="fa fa-spinner fa-spin" [hidden]="status !== PageStatus.LOADING"></i>
{{'global.button.update' | translate}}
</button>
</span>
</div>
</form>
</div>
</div>
</div>
基页list.component.ts
import {PageEvent} from "angular2-datatable-serverpagination";
import {
OnInit, Component, Input, ViewEncapsulation, ViewChild, Injectable
} from "@angular/core";
import {BasePageService} from "../../service/base-page.service";
import {PaginationResult} from "../../model/pagination-result";
import {BasePageFilter} from "../../model/base-page-filter";
import {BasePageResultItem} from "../../model/base-page-result-item";
import {ModalDirective} from "ng2-bootstrap";
import {AlertService} from "../../../../utils/alert.service";
import * as Models from '../../model/models'
import {NgForm} from "@angular/forms";
export enum PageType {
DEFAULT,
TAB
}
export enum PageStatus {
DONE,
LOADING,
EASY_LOADING,
ERROR
}
export enum ModalState {
CREATE,
UPDATE,
DELETE
}
@Component({
selector: 'app-base-page-list',
templateUrl: 'base-page-list.component.html',
styleUrls: ['../../elements.style.scss'],
encapsulation: ViewEncapsulation.None
})
export class BasePageListComponent<F extends BasePageFilter, I extends BasePageResultItem, S extends BasePageService<F, I>> implements OnInit {
@ViewChild("modal")
modal: ModalDirective;
@Input("recordForm")
recordForm: NgForm;
@Input("formErrors")
formErrors: any;
@Input("validationMessages")
validationMessages: any;
constructor(public alertService: AlertService) {
}
ngOnInit() {
if (!this.formErrors) {
this.formErrors = {};
if (this.validationMessages) {
for (let key of Object.keys(this.validationMessages)) {
this.formErrors[key] = '';
}
}
}
}
showModal(state: ModalState, item?) {
switch (state) {
case ModalState.CREATE:
//todo
break;
case ModalState.UPDATE:
//todo
break;
case ModalState.DELETE:
break;
default:
state = ModalState.CREATE;
break;
}
this.modalState = state;
this.modal.show();
}
}
这就是我从其他页面输入我的输入的例子,例如事件列表 的事件list.component.html
<app-base-page-list #basepage [parent]="this" [instanceClassName]="'EventModel'" [validationMessages]="formValidator">
<div class="page-title">
{{ 'event.list.title' | translate }}
</div>
<app-base-page-filter-field
[filter]="basepage.filter"
[labelMessageKey]="'global.label.name'"
[fieldName]="'_id'"
[fieldType]="'text'">
</app-base-page-filter-field>
<table-no-data></table-no-data>
<table-content>
<table [ngSwitch]='basepage.filter.orderByDirection' class="table table-striped table-hover"
[mfData]="basepage.items" #mf="mfDataTable"
(mfOnPageChange)="basepage.onPageChange($event)"
[mfAmountOfRows]="basepage.count"
[mfActivePage]="basepage.pageNumber"
[mfRowsOnPage]="basepage.pageSize">
<thead>
<tr>
<th class="hidden-sm-down">
<app-base-page-sort-field [filter]="basepage.filter"
[sortChangeListener]="basepage"
[labelMessageKey]="'global.label.name'"
[sortProperty]="'name'">
</app-base-page-sort-field>
</th>
<th class="hidden-sm-down">
<app-base-page-sort-field [filter]="basepage.filter"
[sortChangeListener]="basepage"
[labelMessageKey]="'global.label.startDate'"
[sortProperty]="'startDate'">
</app-base-page-sort-field>
</th>
<th class="hidden-sm-down">
<app-base-page-sort-field [filter]="basepage.filter"
[sortChangeListener]="basepage"
[labelMessageKey]="'global.label.endDate'"
[sortProperty]="'endDate'">
</app-base-page-sort-field>
</th>
<th class="hidden-sm-down">
<app-base-page-sort-field [filter]="basepage.filter"
[sortChangeListener]="basepage"
[labelMessageKey]="'global.label.description'"
[sortProperty]="'description'">
</app-base-page-sort-field>
</th>
<th class="hidden-sm-down">
<app-base-page-sort-field [filter]="basepage.filter"
[sortChangeListener]="basepage"
[labelMessageKey]="'global.label.createdDate'"
[sortProperty]="'createdAt'">
</app-base-page-sort-field>
</th>
<th>
{{'global.label.actions' | translate}}
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of mf.data"
[ngClass]="{'hovered': hoveringItem == item}"
(mouseover)="hoveringItem = item" (mouseleave)="hoveringItem = null">
<td>{{item.name}}</td>
<td>{{item.startDate | date: 'dd.MM.yyyy HH:mm'}}</td>
<td>{{item.endDate | date: 'dd.MM.yyyy HH:mm'}}</td>
<td>{{item.description}}</td>
<td>{{item.createdAt | date: 'dd.MM.yyyy HH:mm'}}</td>
<td>
<app-base-page-action-field
[item]="item"
[holder]="this">
</app-base-page-action-field>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="12">
<mfBootstrapPaginator [rowsOnPageSet]="[5, 10, 15, 25]"></mfBootstrapPaginator>
</td>
</tr>
</tfoot>
</table>
</table-content>
<table-buttons></table-buttons>
<!-- Modal -->
<modal-body-content>
<div class="row">
<div class="col-lg-12">
<app-base-page-input-field [labelMessageKey]="'organization.label'"
[holder]="this"
[fieldName]="'organization'"
[fieldType]="'select'"
[ajaxUrl]="'organization/list'"
[item]="instance"
[required]="true"
[columnClass]="'col-md-3'">
</app-base-page-input-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<app-base-page-input-field [labelMessageKey]="'global.label.name'"
[holder]="this"
[fieldName]="'name'"
[fieldType]="'text'"
[item]="instance"
[required]="true"
[validationCheckProperty]="'name'"
[columnClass]="'col-md-3'">
</app-base-page-input-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<app-base-page-input-field [labelMessageKey]="'global.label.description'"
[holder]="this"
[fieldName]="'description'"
[fieldType]="'textarea'"
[item]="instance"
[columnClass]="'col-md-3'">
</app-base-page-input-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<app-base-page-input-field [labelMessageKey]="'global.label.startDate'"
[holder]="this"
[fieldName]="'startDate'"
[fieldType]="'datetime'"
[item]="instance"
[required]="true"
[columnClass]="'col-md-3'">
</app-base-page-input-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<app-base-page-input-field [labelMessageKey]="'global.label.endDate'"
[holder]="this"
[fieldName]="'endDate'"
[fieldType]="'datetime'"
[item]="instance"
[required]="true"
[columnClass]="'col-md-3'">
</app-base-page-input-field>
</div>
</div>
</modal-body-content>
</app-base-page-list>
Everthing呈现完美,但在表单验证方面。它始终启动ng-valid状态。 'app-base-page-input-field'组件创建输入字段。 这是:
<div [ngSwitch]="fieldType" [ngClass]="{'form-group' : true}">
<label *ngIf="labelMessageKey && (fieldType !== 'singleImage' || fieldType !== 'dynamicRow')" class="col-form-label" [for]="fieldName">
<strong>{{ labelMessageKey | translate }}</strong>
</label>
<p *ngSwitchCase="'static'" class="form-control-static">{{item[fieldName]}}</p>
<input *ngSwitchCase="'text'" [id]="fieldName" class="form-control" type="text"
[(ngModel)]="item[fieldName]"
placeholder="{{ (placeholder || labelMessageKey) | translate }}"
[name]="fieldName"
[attr.required]="required ? 'required' : null">
</div>
任何帮助都会很高兴。谢谢。