如何解决故事书控件Addon Angular NgRx ComponentStore交互因args更改而中断
我尝试将Storybook与控件插件一起使用。我要显示的组件是具有NgRx ComponentStore的可扩展行(https://stackblitz.com/angular/ygjybeoorkn?file=src%2Fapp%2Ftable-expandable-rows-example.ts)的角材料样本表。我创建了一个具有更新程序和选择器的ComponentStore以及使用物料表和故事的自定义组件,如下所示:
NgRx ComponentStore
export interface Element {
position: number,name: String,weight: number,symbol: String,description: String
}
export interface ElementsTableState {
elements: Element[],isLoading: boolean,selectedElement: Element
}
@Injectable()
export class ElementsTableStore extends ComponentStore<ElementsTableState> {
constructor() {
super({
isLoading: false,elements: [],selectedElement: null
})
}
// *********** Updaters *********** //
readonly setElements = this.updater((state,value: Element[]) => ({
...state,elements: value || [],selectedElement: null
}));
readonly selectElement = this.updater((state,value: Element) => {
console.log(value);
return {
...state,selectedElement: value
}});
readonly setLoading = this.updater((state,value: boolean) => ({
...state,isLoading: value || false
}));
// *********** Selectors *********** //
readonly vm$ = this.select(
this.state$,(state) => ({
elements: state.elements,isLoading: state.isLoading,selectedElement: state.selectedElement
})
);
}
要在Storybook中显示的组件
import { Component,OnInit,Input,ChangeDetectionStrategy,Output,ViewEncapsulation} from '@angular/core';
import {animate,state,style,transition,trigger} from '@angular/animations';
import { Observable } from 'rxjs';
import { ElementsTableStore,Element } from './elements-table.store'
@Component({
selector: 'qadash-elements-table',templateUrl: './elements-table.component.html',styleUrls: ['./elements-table.component.css'],animations: [
trigger('detailExpand',[
state('collapsed',style({height: '0px',minHeight: '0'})),state('expanded',style({height: '150px'})),transition('expanded <=> collapsed',animate('225ms cubic-bezier(0.4,0.0,0.2,1)')),]),],changeDetection: ChangeDetectionStrategy.OnPush,providers: [ElementsTableStore],})
export class ElementsTableComponent implements OnInit {
columnsToDisplay: string[] = ['name','weight','symbol','position'];
expandedElement = {}
@Input set data(dataSource: Element[]) {
this.elementsTableStore.setElements(dataSource);
}
@Input set loading(isLoading: boolean) {
this.elementsTableStore.setLoading(isLoading)
}
readonly vm$
constructor(private readonly elementsTableStore: ElementsTableStore) {
this.vm$ = this.elementsTableStore.vm$;
}
ngOnInit(): void {
setTimeout(() => {
this.elementsTableStore.setElements([
{
position: 1,name: 'Hydrogen',weight: 1.0079,symbol: 'H',description: `Hydrogen is a chemical element with symbol H and atomic number 1. With a standard atomic weight of 1.008,hydrogen is the lightest element on the periodic table.`
},{
position: 2,name: 'Helium',weight: 4.0026,symbol: 'He',description: `Helium is a chemical element with symbol He and atomic number 2. It is a colorless,odorless,tasteless,non-toxic,inert,monoatomic gas,the first in the noble gas group in the periodic table. Its boiling point is the lowest among all the elements.`
},{
position: 1,the first in the noble gas group in the periodic table. Its boiling point is the lowest among all the elements.`
}
])
},5000)
}
}
组件模板
<ng-container *ngIf="vm$ | async as vm">
<table mat-table
[dataSource]="vm.elements" multiTemplateDataRows
class="mat-elevation-z8">
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
<th mat-header-cell *matHeaderCellDef> {{column}}</th>
<td mat-cell *matCellDef="let element"> {{element[column]}}</td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
<div class="example-element-detail"
[class.example-expanded-element-detail]="vm.selectedElement === element"
[@detailExpand]="element === vm.selectedElement ? 'expanded' : 'collapsed'">
<div class="example-element-diagram">
<div class="example-element-position"> {{element.position}}</div>
<div class="example-element-symbol"> {{element.symbol}}</div>
<div class="example-element-name"> {{element.name}}</div>
<div class="example-element-weight"> {{element.weight}}</div>
</div>
<div class="example-element-description">
{{element.description}}
<span class="example-element-description-attribution"> -- Wikipedia </span>
</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
class="example-element-row"
[class.example-expanded-row]="vm.selectedElement === element"
(click)="elementsTableStore.selectElement(vm.selectedElement === element ? null : element)">
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
<div *ngIf="vm.isLoading" class="overlay">
<div class="overlay-content">
<mat-progress-spinner
color="primary"
mode="indeterminate">
</mat-progress-spinner>
</div>
</div>
</ng-container>
css文件
:host {
position: relative;
width: 100%;
}
.overlay-content {
height:100%;
position:relative;
display: flex;
justify-content: center;
align-items: center;
}
.overlay-content:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: .7;
z-index: -1;
background: #fff;
}
.overlay {
position:absolute;
top:0;
bottom:0;
left:0;
width: 100%;
height: 100%;
z-index: 99;
}
table {
width: 100%;
}
tr.example-detail-row {
height: 0px;
}
tr.example-element-row:not(.example-expanded-row):hover {
background: whitesmoke;
}
tr.example-element-row:not(.example-expanded-row):active {
background: #efefef;
}
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
height:0px;
}
.example-expanded-element-detail {
overflow: hidden;
display: flex;
height:100%;
}
.example-element-diagram {
min-width: 80px;
border: 2px solid black;
padding: 8px;
font-weight: lighter;
margin: 8px 0;
height: 104px;
}
.example-element-symbol {
font-weight: bold;
font-size: 40px;
line-height: normal;
}
.example-element-description {
padding: 16px;
}
.example-element-description-attribution {
opacity: 0.5;
}
故事
import { ElemensTableComponent } from './elements-table.component';
import { MatTableModule } from '@angular/material/table';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatIconModule } from '@angular/material/icon';
import { MatCardModule } from '@angular/material/card';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Story,Meta } from '@storybook/angular/types-6-0';
export default {
title: 'ElemensTableComponent',component: ElemensTableComponent,}
const Template: Story = (args) => ({
moduleMetadata: {
imports: [
BrowserAnimationsModule,MatTableModule,MatProgressSpinnerModule,MatCardModule,MatIconModule,]
},props: args
});
export const Basic = Template.bind({});
Basic.args = {
loading: false,data: [{
position: 1,hydrogen is the lightest element on the periodic table.`
},{
position: 2,the first in the noble gas group in the periodic table. Its boiling point is the lowest among all the elements.`
}
]
}
一切正常,直到我更改“数据”控件的值为止。表更新,但我无法再扩展表行。单击处理程序有效,并且调用了更新程序,但vm $ .selectedElement不再更改。另一方面,加载控件仍然有效。我认为这可能是由于元素的更新程序所致。这就是为什么我引入了超时功能。当通过超时功能更改数据源时,一切正常。如果我在调用超时功能之前更改了值,则无法扩展该表,直到超时功能启动为止。因此,我怀疑我缺少有关控件插件的内容。有什么想法吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。