[ADF-2859] fixes for the conditional visibility and disabled states (#3465)

* fixes for the conditional visibility and disabled states

* update docs

* cleanup code

* remove unused code
This commit is contained in:
Denys Vuika
2018-06-11 12:53:09 +01:00
committed by Eugenio Romano
parent 1d69f5c407
commit 6f2cbdf697
9 changed files with 89 additions and 84 deletions

View File

@@ -279,13 +279,13 @@
</data-columns> </data-columns>
<content-actions> <content-actions>
<!-- Conditional actions demo -->
<content-action <content-action
target="all" target="all"
title="Action for 'custom' node" title="Action for 'custom' node"
[disabled]="isCustomActionDisabled" [disabled]="isCustomActionDisabled"
(execute)="runCustomAction($event)"> (execute)="runCustomAction($event)">
</content-action> </content-action>
<!-- Conditional actions demo -->
<content-action <content-action
icon="get_app" icon="get_app"
title="Download this file now!" title="Download this file now!"
@@ -298,12 +298,6 @@
handler="download" handler="download"
[visible]="false"> [visible]="false">
</content-action> </content-action>
<content-action
icon="get_app"
title="This can be toggled"
handler="download"
[visible]="showCustomDownloadAction">
</content-action>
<!-- common actions --> <!-- common actions -->
<content-action <content-action
icon="get_app" icon="get_app"
@@ -448,12 +442,6 @@
</mat-slide-toggle> </mat-slide-toggle>
</section> </section>
<section>
<mat-slide-toggle color="primary" [(ngModel)]="showCustomDownloadAction">
Toggle custom download action
</mat-slide-toggle>
</section>
<section> <section>
<mat-slide-toggle [color]="'primary'" [(ngModel)]="multiselect">{{'DOCUMENT_LIST.MULTISELECT_CHECKBOXES' | <mat-slide-toggle [color]="'primary'" [(ngModel)]="multiselect">{{'DOCUMENT_LIST.MULTISELECT_CHECKBOXES' |
translate}} translate}}

View File

@@ -170,9 +170,6 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild(InfinitePaginationComponent) @ViewChild(InfinitePaginationComponent)
infinitePaginationComponent: InfinitePaginationComponent; infinitePaginationComponent: InfinitePaginationComponent;
@Input()
showCustomDownloadAction = false;
permissionsStyle: PermissionStyleModel[] = []; permissionsStyle: PermissionStyleModel[] = [];
infiniteScrolling: boolean; infiniteScrolling: boolean;
supportedPages: number[]; supportedPages: number[];
@@ -514,7 +511,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
} }
canDownloadNode = (node: MinimalNodeEntity): boolean => { canDownloadNode = (node: MinimalNodeEntity): boolean => {
if (node && node.entry && node.entry.name === 'For Sale.docx') { if (node && node.entry && node.entry.name === 'custom') {
return true; return true;
} }
return false; return false;

View File

@@ -324,12 +324,10 @@ allow the item being copied/moved to be the destination if it is itself a folder
### Conditional visibility ### Conditional visibility
The Content-action component allows you to control visibility with the help of the `visible` The `<content-action>` component allows you to control visibility with the help of the `visible` property and supports the following scenarios:
property which can receive its value in three main ways:
- direct `boolean` value - direct value of `boolean` type
- binding to a `boolean` property - binding to a property of the `Function` type that evaluates condition and returns `boolean` value
- binding to a `Function` property that evaluates the condition and returns a `boolean` value
#### Using direct boolean value #### Using direct boolean value
@@ -342,30 +340,7 @@ property which can receive its value in three main ways:
</content-action> </content-action>
``` ```
#### Binding to a boolean property #### Using a property of the Function type
```html
<content-action
icon="get_app"
title="This can be toggled"
handler="download"
[visible]="showCustomDownloadAction">
</content-action>
```
The markup above relies on the `showCustomDownloadAction` property declared in your
component class:
```ts
export class MyComponent {
@Input()
showCustomDownloadAction = true;
}
```
#### Binding to a Function property
```html ```html
<content-action <content-action
@@ -409,7 +384,6 @@ funcName = (parameters): boolean => {
Similar to `visible` property, it is possible to control the `disabled` state with the following scenarios: Similar to `visible` property, it is possible to control the `disabled` state with the following scenarios:
- direct value of `boolean` type - direct value of `boolean` type
- binding to a property of the `boolean` type
- binding to a property of the `Function` type that evaluates condition and returns `boolean` value - binding to a property of the `Function` type that evaluates condition and returns `boolean` value
#### Using direct value of boolean type #### Using direct value of boolean type
@@ -423,28 +397,6 @@ Similar to `visible` property, it is possible to control the `disabled` state wi
</content-action> </content-action>
``` ```
#### Using a property of the boolean type
```html
<content-action
target="all"
title="Action for 'custom' node"
[disabled]="shouldDisableAction"
(execute)="runCustomAction($event)">
</content-action>
```
The markup above relies on the `shouldDisableAction` property declared at your component class level:
```ts
export class MyComponent {
@Input()
shouldDisableAction = true;
}
```
#### Using a property of the Function type #### Using a property of the Function type
```html ```html

View File

@@ -42,4 +42,15 @@ export class ContentActionListComponent {
} }
return false; return false;
} }
unregisterAction(action: ContentActionModel): boolean {
if (this.documentList && action) {
const idx = this.documentList.actions.indexOf(action);
if (idx >= 0) {
this.documentList.actions.splice(idx, 1);
return true;
}
}
return false;
}
} }

View File

@@ -132,8 +132,15 @@ export class ContentActionComponent implements OnInit, OnChanges, OnDestroy {
this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions.forEach(subscription => subscription.unsubscribe());
this.subscriptions = []; this.subscriptions = [];
this.documentActionModel = null; if (this.documentActionModel) {
this.folderActionModel = null; this.unregister(this.documentActionModel);
this.documentActionModel = null;
}
if (this.folderActionModel) {
this.unregister(this.folderActionModel);
this.folderActionModel = null;
}
} }
register(model: ContentActionModel): boolean { register(model: ContentActionModel): boolean {
@@ -143,6 +150,13 @@ export class ContentActionComponent implements OnInit, OnChanges, OnDestroy {
return false; return false;
} }
unregister(model: ContentActionModel): boolean {
if (this.list) {
return this.list.unregisterAction(model);
}
return false;
}
private generateAction(target: string): ContentActionModel { private generateAction(target: string): ContentActionModel {
const model = new ContentActionModel({ const model = new ContentActionModel({
title: this.title, title: this.title,

View File

@@ -13,6 +13,7 @@
[display]="display" [display]="display"
[noPermission]="noPermission" [noPermission]="noPermission"
[showHeader]="!isEmpty() && showHeader" [showHeader]="!isEmpty() && showHeader"
[rowMenuCacheEnabled]="false"
(showRowContextMenu)="onShowRowContextMenu($event)" (showRowContextMenu)="onShowRowContextMenu($event)"
(showRowActionsMenu)="onShowRowActionsMenu($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)" (executeRowAction)="onExecuteRowAction($event)"

View File

@@ -236,6 +236,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
private _pagination: BehaviorSubject<PaginationModel>; private _pagination: BehaviorSubject<PaginationModel>;
private layoutPresets = {}; private layoutPresets = {};
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
constructor(private documentListService: DocumentListService, constructor(private documentListService: DocumentListService,
private ngZone: NgZone, private ngZone: NgZone,
@@ -333,6 +334,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
ngOnInit() { ngOnInit() {
this.rowMenuCache = {};
this.loadLayoutPresets(); this.loadLayoutPresets();
this.data = new ShareDataTableAdapter(this.documentListService, this.thumbnailService, null, this.getDefaultSorting(), this.sortingMode); this.data = new ShareDataTableAdapter(this.documentListService, this.thumbnailService, null, this.getDefaultSorting(), this.sortingMode);
this.data.thumbnails = this.thumbnails; this.data.thumbnails = this.thumbnails;
@@ -444,9 +446,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
getNodeActions(node: MinimalNodeEntity | any): ContentActionModel[] { getNodeActions(node: MinimalNodeEntity | any): ContentActionModel[] {
let target = null;
if (node && node.entry) { if (node && node.entry) {
let target = null;
if (node.entry.isFile) { if (node.entry.isFile) {
target = 'document'; target = 'document';
} else if (node.entry.isFolder) { } else if (node.entry.isFolder) {
@@ -454,6 +457,14 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
} }
if (target) { if (target) {
const actions = this.rowMenuCache[node.entry.id];
if (actions) {
actions.forEach(action => {
this.refreshAction(action, node);
});
return actions;
}
let actionsByTarget = this.actions let actionsByTarget = this.actions
.filter(entry => { .filter(entry => {
const isVisible = (typeof entry.visible === 'function') const isVisible = (typeof entry.visible === 'function')
@@ -465,9 +476,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
.map(action => new ContentActionModel(action)); .map(action => new ContentActionModel(action));
actionsByTarget.forEach((action) => { actionsByTarget.forEach((action) => {
action.disabled = this.isActionDisabled(action, node); this.refreshAction(action, node);
}); });
this.rowMenuCache[node.entry.id] = actionsByTarget;
return actionsByTarget; return actionsByTarget;
} }
} }
@@ -475,6 +487,19 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
return []; return [];
} }
private refreshAction(action: ContentActionModel, node: MinimalNodeEntity) {
action.disabled = this.isActionDisabled(action, node);
action.visible = this.isActionVisible(action, node);
}
private isActionVisible(action: ContentActionModel, node: MinimalNodeEntity): boolean {
if (typeof action.visible === 'function') {
return action.visible(node);
}
return action.visible;
}
private isActionDisabled(action: ContentActionModel, node: MinimalNodeEntity): boolean { private isActionDisabled(action: ContentActionModel, node: MinimalNodeEntity): boolean {
if (typeof action.disabled === 'function') { if (typeof action.disabled === 'function') {
return action.disabled(node); return action.disabled(node);
@@ -484,7 +509,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
return true; return true;
} }
return false; return action.disabled;
} }
@HostListener('contextmenu', ['$event']) @HostListener('contextmenu', ['$event'])

View File

@@ -29,13 +29,15 @@ import { ContextMenuService } from './context-menu.service';
template: ` template: `
<button mat-button [matMenuTriggerFor]="contextMenu"></button> <button mat-button [matMenuTriggerFor]="contextMenu"></button>
<mat-menu #contextMenu="matMenu" class="context-menu"> <mat-menu #contextMenu="matMenu" class="context-menu">
<button *ngFor="let link of links" <ng-container *ngFor="let link of links">
mat-menu-item <button *ngIf="link.model?.visible"
[disabled]="link.model?.disabled" mat-menu-item
(click)="onMenuItemClick($event, link)"> [disabled]="link.model?.disabled"
<mat-icon *ngIf="showIcons && link.model?.icon">{{ link.model.icon }}</mat-icon> (click)="onMenuItemClick($event, link)">
{{ (link.title || link.model?.title) | translate }} <mat-icon *ngIf="showIcons && link.model?.icon">{{ link.model.icon }}</mat-icon>
</button> {{ (link.title || link.model?.title) | translate }}
</button>
</ng-container>
</mat-menu> </mat-menu>
` `
}) })

View File

@@ -155,6 +155,9 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
@Input() @Input()
noPermission: boolean = false; noPermission: boolean = false;
@Input()
rowMenuCacheEnabled = true;
noContentTemplate: TemplateRef<any>; noContentTemplate: TemplateRef<any>;
noPermissionTemplate: TemplateRef<any>; noPermissionTemplate: TemplateRef<any>;
loadingTemplate: TemplateRef<any>; loadingTemplate: TemplateRef<any>;
@@ -166,6 +169,8 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
private click$: Observable<DataRowEvent>; private click$: Observable<DataRowEvent>;
private differ: any; private differ: any;
private rowMenuCache: object = {};
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
private singleClickStreamSub: Subscription; private singleClickStreamSub: Subscription;
private multiClickStreamSub: Subscription; private multiClickStreamSub: Subscription;
@@ -297,6 +302,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
private initTable() { private initTable() {
this.data = new ObjectDataTableAdapter(this.rows, this.columns); this.data = new ObjectDataTableAdapter(this.rows, this.columns);
this.setupData(this.data); this.setupData(this.data);
this.rowMenuCache = {};
} }
private setupData(adapter: DataTableAdapter) { private setupData(adapter: DataTableAdapter) {
@@ -553,9 +559,18 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck,
} }
getRowActions(row: DataRow, col: DataColumn): any[] { getRowActions(row: DataRow, col: DataColumn): any[] {
let event = new DataCellEvent(row, col, []); const id = row.getValue('id');
this.showRowActionsMenu.emit(event);
return event.value.actions; if (!this.rowMenuCache[id]) {
let event = new DataCellEvent(row, col, []);
this.showRowActionsMenu.emit(event);
if (!this.rowMenuCacheEnabled) {
return event.value.actions;
}
this.rowMenuCache[id] = event.value.actions;
}
return this.rowMenuCache[id];
} }
onExecuteRowAction(row: DataRow, action: any) { onExecuteRowAction(row: DataRow, action: any) {