Skip to content

Commit fd950f5

Browse files
authored
Merge branch 'master' into pbozhinov/fix-8052-10.2
2 parents 8bf3850 + 9c11c8b commit fd950f5

23 files changed

+492
-108
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ All notable changes for each version of this project will be documented in this
1515
- Added `aria-labelledby` property for the items list container(marked as `role="listbox"`). This will ensure the users of assistive technologies will also know what the list items container is used for, upon opening.
1616
- `IgxDatePicker`
1717
- **Breaking Change** - Deprecated the `label` property.
18+
- `igxGridActions`
19+
- Added `asMenuItems` Input for grid actions - `igx-grid-editing-actions`, `igx-grid-pinning-actions`. When set to true will render the related action buttons as separate menu items with button and label.
1820

1921

2022
### New Features
Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
<div class="igx-action-strip__actions">
22
<ng-content #content></ng-content>
33
<ng-container *ngIf="menuItems.length > 0">
4-
<button igxButton="icon" igxRipple [igxToggleAction]="dropdown"
5-
[overlaySettings]="menuOverlaySettings" (click)="$event.stopPropagation()"
6-
[igxDropDownItemNavigation]="dropdown">
4+
<button
5+
igxButton="icon"
6+
igxRipple
7+
[igxToggleAction]="dropdown"
8+
[overlaySettings]="menuOverlaySettings"
9+
(click)="$event.stopPropagation()"
10+
[igxDropDownItemNavigation]="dropdown"
11+
>
712
<igx-icon>more_vert</igx-icon>
813
</button>
9-
<igx-drop-down #dropdown>
10-
<igx-drop-down-item *ngFor="let item of menuItems">
11-
<div class="igx-drop-down__item-template">
12-
<ng-container *ngTemplateOutlet="item.templateRef; context: {$implicit: item}"></ng-container>
13-
</div>
14-
</igx-drop-down-item>
15-
</igx-drop-down>
1614
</ng-container>
15+
<igx-drop-down #dropdown [displayDensity]="displayDensity">
16+
<igx-drop-down-item
17+
*ngFor="let item of menuItems"
18+
class="igx-action-strip__menu-item"
19+
>
20+
<div class="igx-drop-down__item-template">
21+
<ng-container
22+
*ngTemplateOutlet="
23+
item.templateRef;
24+
context: { $implicit: item }
25+
"
26+
></ng-container>
27+
</div>
28+
</igx-drop-down-item>
29+
</igx-drop-down>
1730
</div>

projects/igniteui-angular/src/lib/action-strip/action-strip.component.spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,17 @@ describe('igxActionStrip', () => {
2424
const mockRenderer2 = jasmine.createSpyObj('Renderer2', ['appendChild', 'removeChild']);
2525
const mockContext = jasmine.createSpyObj('context', ['element']);
2626
const mockDisplayDensity = jasmine.createSpyObj('IDisplayDensityOptions', ['displayDensity']);
27+
const cdr = jasmine.createSpyObj('ChangeDetectorRef', ['detectChanges']);
2728

2829
it('should properly get/set hidden', () => {
29-
actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity);
30+
actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity, cdr);
3031
expect(actionStrip.hidden).toBeFalsy();
3132
actionStrip.hidden = true;
3233
expect(actionStrip.hidden).toBeTruthy();
3334
});
3435

3536
it('should properly show and hide using API', () => {
36-
actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity);
37+
actionStrip = new IgxActionStripComponent(mockViewContainerRef, mockRenderer2, mockDisplayDensity, cdr);
3738
actionStrip.show(mockContext);
3839
expect(actionStrip.hidden).toBeFalsy();
3940
expect(actionStrip.context).toBe(mockContext);
@@ -51,7 +52,9 @@ describe('igxActionStrip', () => {
5152
],
5253
imports: [
5354
IgxActionStripModule,
54-
IgxIconModule
55+
IgxIconModule,
56+
NoopAnimationsModule,
57+
IgxToggleModule
5558
]
5659
}).compileComponents();
5760
}));

projects/igniteui-angular/src/lib/action-strip/action-strip.component.ts

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@ import {
1010
ContentChildren,
1111
QueryList,
1212
ViewChild,
13-
TemplateRef
13+
TemplateRef,
14+
AfterContentInit,
15+
IterableDiffers,
16+
OnInit,
17+
ChangeDetectorRef,
18+
AfterViewInit
1419
} from '@angular/core';
1520
import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/density';
1621
import { IgxDropDownComponent } from '../drop-down/public_api';
1722
import { CloseScrollStrategy, OverlaySettings } from '../services/public_api';
23+
import { IgxGridActionsBaseDirective } from './grid-actions/grid-actions-base.directive';
1824

1925
@Directive({
2026
selector: '[igxActionStripMenuItem]'
@@ -51,11 +57,12 @@ export class IgxActionStripMenuItemDirective {
5157
templateUrl: 'action-strip.component.html'
5258
})
5359

54-
export class IgxActionStripComponent extends DisplayDensityBase {
60+
export class IgxActionStripComponent extends DisplayDensityBase implements AfterContentInit, AfterViewInit {
5561
constructor(
5662
private _viewContainer: ViewContainerRef,
5763
private renderer: Renderer2,
58-
@Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions: IDisplayDensityOptions) {
64+
@Optional() @Inject(DisplayDensityToken) protected _displayDensityOptions: IDisplayDensityOptions,
65+
public cdr: ChangeDetectorRef) {
5966
super(_displayDensityOptions);
6067
}
6168

@@ -129,15 +136,73 @@ export class IgxActionStripComponent extends DisplayDensityBase {
129136
* @internal
130137
*/
131138
@ContentChildren(IgxActionStripMenuItemDirective)
132-
public menuItems: QueryList<IgxActionStripMenuItemDirective>;
139+
public _menuItems: QueryList<IgxActionStripMenuItemDirective>;
140+
141+
142+
/**
143+
* ActionButton as ContentChildren inside the Action Strip
144+
* @hidden
145+
* @internal
146+
*/
147+
@ContentChildren(IgxGridActionsBaseDirective)
148+
public actionButtons: QueryList<IgxGridActionsBaseDirective>;
149+
150+
/**
151+
* Menu Items list.
152+
* @hidden
153+
* @internal
154+
*/
155+
public get menuItems() {
156+
const actions = [];
157+
this.actionButtons.forEach(button => {
158+
if (button.asMenuItems) {
159+
const children = button.buttons;
160+
if (children) {
161+
children.toArray().forEach(x => actions.push(x));
162+
}
163+
}
164+
});
165+
return [... this._menuItems.toArray(), ... actions];
166+
}
133167

134168
/**
135169
* Reference to the menu
136170
* @hidden
137171
* @internal
138172
*/
139173
@ViewChild('dropdown')
140-
private menu: IgxDropDownComponent;
174+
public menu: IgxDropDownComponent;
175+
176+
/**
177+
* @hidden
178+
* @internal
179+
*/
180+
ngAfterContentInit() {
181+
this.actionButtons.forEach(button => {
182+
button.strip = this;
183+
});
184+
this.actionButtons.changes.subscribe(change => {
185+
this.actionButtons.forEach(button => {
186+
button.strip = this;
187+
});
188+
});
189+
}
190+
191+
ngAfterViewInit() {
192+
this.menu.onSelection.subscribe(($event) => {
193+
const newSelection = ($event.newSelection as any).elementRef.nativeElement;
194+
let allButtons = [];
195+
this.actionButtons.forEach( actionButtons => {
196+
if (actionButtons.asMenuItems) {
197+
allButtons = [... allButtons, ... actionButtons.buttons.toArray()];
198+
}
199+
});
200+
const button = allButtons.find(x => newSelection.contains(x.container.nativeElement));
201+
if (button) {
202+
button.onActionClick.emit();
203+
}
204+
});
205+
}
141206

142207
/**
143208
* Showing the Action Strip and appending it the specified context element.
@@ -160,6 +225,7 @@ export class IgxActionStripComponent extends DisplayDensityBase {
160225
if (this.context && this.context.element) {
161226
this.renderer.appendChild(context.element.nativeElement, this._viewContainer.element.nativeElement);
162227
}
228+
this.cdr.detectChanges();
163229
}
164230

165231
/**

projects/igniteui-angular/src/lib/action-strip/action-strip.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IgxToggleModule } from '../directives/toggle/toggle.directive';
99
import { IgxButtonModule } from '../directives/button/button.directive';
1010
import { IgxIconModule } from '../icon/public_api';
1111
import { IgxRippleModule } from '../directives/ripple/ripple.directive';
12+
import { IgxGridActionButtonComponent } from './grid-actions/grid-action-button.component';
1213

1314
/**
1415
* @hidden
@@ -19,7 +20,8 @@ import { IgxRippleModule } from '../directives/ripple/ripple.directive';
1920
IgxActionStripMenuItemDirective,
2021
IgxGridPinningActionsComponent,
2122
IgxGridEditingActionsComponent,
22-
IgxGridActionsBaseDirective
23+
IgxGridActionsBaseDirective,
24+
IgxGridActionButtonComponent
2325
],
2426
entryComponents: [
2527
],
@@ -28,7 +30,8 @@ import { IgxRippleModule } from '../directives/ripple/ripple.directive';
2830
IgxActionStripMenuItemDirective,
2931
IgxGridPinningActionsComponent,
3032
IgxGridEditingActionsComponent,
31-
IgxGridActionsBaseDirective
33+
IgxGridActionsBaseDirective,
34+
IgxGridActionButtonComponent
3235
],
3336
imports: [CommonModule, IgxDropDownModule, IgxToggleModule, IgxButtonModule, IgxIconModule, IgxRippleModule]
3437
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<ng-container *ngIf="!asMenuItem">
2+
3+
<ng-container *ngIf="!asMenuItem">
4+
<button igxButton="icon" igxRipple (click)="handleClick($event)">
5+
<igx-icon *ngIf="iconSet" [fontSet]="iconSet" [name]="iconName">{{iconName}}</igx-icon>
6+
<igx-icon *ngIf="!iconSet" >{{iconName}}</igx-icon>
7+
</button>
8+
</ng-container>
9+
10+
<ng-container *ngIf="asMenuItem">
11+
<div #container [className]='containerClass'>
12+
<igx-icon *ngIf="iconSet" [fontSet]="iconSet" [name]="iconName">{{iconName}}</igx-icon>
13+
<igx-icon *ngIf="!iconSet" >{{iconName}}</igx-icon>
14+
<label *ngIf='asMenuItem' igxLabel>{{labelText}}</label>
15+
</div>
16+
</ng-container>
17+
</ng-container>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Component, Input, TemplateRef, ViewChild, Output, EventEmitter, ElementRef } from '@angular/core';
2+
@Component({
3+
selector: 'igx-grid-action-button',
4+
templateUrl: 'grid-action-button.component.html'
5+
})
6+
7+
export class IgxGridActionButtonComponent {
8+
9+
@ViewChild('container')
10+
public container: ElementRef;
11+
12+
/**
13+
* Event emitted when action button is clicked.
14+
* @example
15+
* ```html
16+
* <igx-grid-action-button (onActionClick)="startEdit($event)"></igx-grid-action-button>
17+
* ```
18+
*/
19+
@Output()
20+
onActionClick = new EventEmitter<Event>();
21+
22+
/**
23+
* Reference to the current template.
24+
* @hidden
25+
* @internal
26+
*/
27+
@ViewChild(TemplateRef)
28+
public templateRef: TemplateRef<any>;
29+
30+
/**
31+
* Whether button action is rendered in menu and should container text label.
32+
*/
33+
@Input()
34+
public asMenuItem = false;
35+
36+
/**
37+
* Name of the icon to display in the button.
38+
*/
39+
@Input()
40+
public iconName: string;
41+
42+
/**
43+
* Additional Menu item container element classes.
44+
*/
45+
@Input()
46+
public classNames: string;
47+
48+
/** @hidden @internal */
49+
get containerClass(): string {
50+
return 'igx-action-strip__menu-button ' + (this.classNames || '');
51+
}
52+
53+
/**
54+
* The name of the icon set. Used in case the icon is from a different icon set.
55+
*/
56+
@Input()
57+
public iconSet: string;
58+
59+
/**
60+
* The text of the label.
61+
*/
62+
@Input()
63+
public labelText: string;
64+
65+
/**
66+
* @hidden
67+
* @internal
68+
*/
69+
public handleClick(event) {
70+
this.onActionClick.emit(event);
71+
}
72+
}

projects/igniteui-angular/src/lib/action-strip/grid-actions/grid-actions-base.directive.ts

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,54 @@
1-
import { Directive, Inject } from '@angular/core';
1+
import { takeUntil } from 'rxjs/operators';
2+
import { IgxGridActionButtonComponent } from './grid-action-button.component';
3+
import { Directive, Inject, Input, AfterViewInit, QueryList, ViewChildren,
4+
OnInit, IterableDiffers, IterableChangeRecord, OnDestroy } from '@angular/core';
25
import { IgxActionStripComponent } from '../action-strip.component';
36
import { IgxRowDirective } from '../../grids/public_api';
47
import { IgxIconService } from '../../icon/icon.service';
8+
import { Subject } from 'rxjs';
59

610
@Directive({
711
selector: '[igxGridActionsBase]'
812
})
9-
export class IgxGridActionsBaseDirective {
10-
constructor(@Inject(IgxActionStripComponent) protected strip: IgxActionStripComponent, protected iconService: IgxIconService) { }
13+
export class IgxGridActionsBaseDirective implements AfterViewInit {
14+
constructor(protected iconService: IgxIconService,
15+
protected differs: IterableDiffers) { }
16+
17+
public strip: IgxActionStripComponent;
18+
19+
@ViewChildren(IgxGridActionButtonComponent)
20+
public buttons: QueryList<IgxGridActionButtonComponent>;
21+
22+
/**
23+
* Gets/Sets if the action buttons will be rendered as menu items. When in menu, items will be rendered with text label.
24+
* @example
25+
* ```html
26+
* <igx-grid-pinning-actions [asMenuItems]='true'></igx-grid-pinning-actions>
27+
* <igx-grid-editing-actions [asMenuItems]='true'></igx-grid-editing-actions>
28+
* ```
29+
*/
30+
@Input()
31+
asMenuItems = false;
32+
33+
/**
34+
* @hidden
35+
* @internal
36+
*/
37+
get grid() {
38+
return this.strip.context.grid;
39+
}
40+
41+
/**
42+
* @hidden
43+
* @internal
44+
*/
45+
ngAfterViewInit() {
46+
if (this.asMenuItems) {
47+
this.buttons.changes.subscribe((change: QueryList<IgxGridActionButtonComponent>) => {
48+
this.strip.cdr.detectChanges();
49+
});
50+
}
51+
}
1152

1253
/**
1354
* Getter to be used in template
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1+
12
<ng-container *ngIf="isRowContext">
2-
<button igxButton="icon" [disabled]="disabled" igxRipple (click)="startEdit($event)">
3-
<igx-icon>edit</igx-icon>
4-
</button>
5-
<button *ngIf="addRow" igxButton="icon" [disabled]="disabled" igxRipple (click)="addChild($event)">
6-
<igx-icon fontSet="imx-icons" name="add-row"></igx-icon>
7-
</button>
8-
<button igxButton="icon" [disabled]="disabled" class="igx-action-strip__delete" igxRipple (click)="deleteRow($event)">
9-
<igx-icon>delete</igx-icon>
10-
</button>
3+
<igx-grid-action-button *ngIf="!disabled" [asMenuItem]="asMenuItems" iconName="edit" [labelText]="grid.resourceStrings.igx_grid_actions_edit_label" (onActionClick)="startEdit($event)"></igx-grid-action-button>
4+
<igx-grid-action-button *ngIf="addRow" [asMenuItem]="asMenuItems" iconName="add-row" iconSet="imx-icons" [labelText]="grid.resourceStrings.igx_grid_actions_add_label" (onActionClick)="addChild($event)"></igx-grid-action-button>
5+
<igx-grid-action-button *ngIf="!disabled" class="igx-action-strip__delete" classNames='igx-action-strip__menu-item--danger' [asMenuItem]="asMenuItems" iconName="delete" [labelText]="grid.resourceStrings.igx_grid_actions_delete_label" (onActionClick)="deleteRow($event)"></igx-grid-action-button>
116
</ng-container>
7+

0 commit comments

Comments
 (0)