Skip to content

Commit 64aca03

Browse files
authored
Merge branch '18.1.x' into dpetev/ssr-error-theme-service
2 parents 4c9ab4d + 51a7e29 commit 64aca03

File tree

8 files changed

+299
-11
lines changed

8 files changed

+299
-11
lines changed

projects/igniteui-angular-elements/src/app/app.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,22 @@ import { registerConfig } from "../analyzer/elements.config";
3131
import { createIgxCustomElement } from './create-custom-element';
3232
import { IgxGridStateComponent } from '../lib/state.component';
3333
import { ELEMENTS_TOKEN } from 'igniteui-angular/src/lib/core/utils';
34+
import { IgxIconBroadcastService } from '../lib/icon.broadcast.service';
3435

3536
@NgModule({
3637
imports: [
3738
BrowserModule,
3839
BrowserAnimationsModule
3940
],
4041
providers: [
41-
{ provide: ELEMENTS_TOKEN, useValue: true }
42+
{ provide: ELEMENTS_TOKEN, useValue: true },
43+
IgxIconBroadcastService
4244
],
4345
// bootstrap: []
4446
})
4547
export class AppModule {
4648

47-
constructor(private injector: Injector) {}
49+
constructor(private injector: Injector, private _iconBroadcast: IgxIconBroadcastService) {}
4850

4951
ngDoBootstrap() {
5052

projects/igniteui-angular-elements/src/index.html

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ <h3 class="ig-typography__h6">Flat Grid (column groups, toolbar, paginator, row
7373
<igc-toggle-button value="medium">Medium</igc-toggle-button>
7474
<igc-toggle-button value="large" selected>Large</igc-toggle-button>
7575
</igc-button-group>
76+
<button id="toggleIcon">Change Filter Icon</button>
7677
</div>
7778

7879
<h3 class="ig-typography__h6">Standalone paginator</h3>
@@ -112,10 +113,18 @@ <h3 class="ig-typography__h6">Flat Grid (MRL column layout)</h3>
112113
import { html, nothing } from "/lit-html.js";
113114
import { Directive, directive } from "/directive.js";
114115

115-
import { defineComponents, IgcSelectComponent, IgcComboComponent, IgcButtonComponent, IgcButtonGroupComponent } from "igniteui-webcomponents";
116+
import { defineComponents, IgcSelectComponent, IgcComboComponent, IgcButtonComponent, IgcButtonGroupComponent, registerIconFromText, setIconRef } from "igniteui-webcomponents";
116117
// import "igniteui-webcomponents/themes/light/bootstrap.css";
117118

118119
defineComponents(IgcSelectComponent, IgcComboComponent, IgcButtonComponent, IgcButtonGroupComponent);
120+
121+
122+
const buildIcon =
123+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg>';
124+
const thumbUpIcon =
125+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z"/></svg>';
126+
let icon = thumbUpIcon;
127+
119128
const grid1 = document.getElementById('grid1');
120129
const grid2 = document.getElementById('grid2');
121130
const buttonGroup = document.querySelector('igc-button-group');
@@ -196,6 +205,7 @@ <h3 class="ig-typography__h6">Flat Grid (MRL column layout)</h3>
196205

197206
document.getElementById("saveState").addEventListener("click", saveState);
198207
document.getElementById("restoreState").addEventListener("click", restoreState);
208+
document.getElementById("toggleIcon").addEventListener("click", toggleIcon);
199209
const stateComponent = document.getElementById('state');
200210
stateComponent.options = {
201211
paging: false
@@ -220,6 +230,25 @@ <h3 class="ig-typography__h6">Flat Grid (MRL column layout)</h3>
220230
stateComponent.applyState(obj);
221231
}
222232
}
233+
234+
function toggleIcon() {
235+
if (icon !== thumbUpIcon) {
236+
icon = thumbUpIcon;
237+
registerIconFromText("filter_list", thumbUpIcon, "customSet");
238+
setIconRef('filter_list', 'default', {
239+
name: 'filter_list',
240+
collection: 'customSet',
241+
});
242+
243+
} else {
244+
icon = buildIcon;
245+
registerIconFromText("filter_list", buildIcon, "customSet2");
246+
setIconRef('filter_list', 'default', {
247+
name: 'filter_list',
248+
collection: 'customSet2',
249+
});
250+
}
251+
}
223252
</script>
224253

225254
<!-- IgxTreeGridComponent -->
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { ActionType, BroadcastIconsChangeMessage, IgxIconBroadcastService, SvgIcon, } from './icon.broadcast.service';
3+
import { Component, SecurityContext } from '@angular/core';
4+
import { IconMeta, IgxIconService } from 'igniteui-angular';
5+
import { wait } from 'igniteui-angular/src/lib/test-utils/ui-interactions.spec';
6+
7+
describe('Icon broadcast service', () => {
8+
let fixture: ComponentFixture<BroadcastServiceComponent>;
9+
let broadcastChannel: BroadcastChannel;
10+
let events: BroadcastIconsChangeMessage[] = [];
11+
const buildIcon =
12+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"/></svg>';
13+
14+
beforeEach(async () => {
15+
await TestBed.configureTestingModule({
16+
imports: [],
17+
providers: [IgxIconBroadcastService]
18+
})
19+
.compileComponents();
20+
});
21+
22+
beforeEach(() => {
23+
broadcastChannel = new BroadcastChannel("ignite-ui-icon-channel");
24+
broadcastChannel.onmessage = (e: MessageEvent<BroadcastIconsChangeMessage>) => {
25+
events.push(e.data);
26+
}
27+
fixture = TestBed.createComponent(BroadcastServiceComponent);
28+
});
29+
30+
afterEach(() => {
31+
events = [];
32+
broadcastChannel.close();
33+
});
34+
35+
describe('Broadcast Events', () => {
36+
it('should correctly process event of icons registering on channel.', async() => {
37+
// simulate a new icon being registered on channel
38+
const icons: Map<string, Map<string, SvgIcon>> = new Map();
39+
const icon: Map<string, SvgIcon> = new Map()
40+
icon.set("customIcon", { svg: buildIcon });
41+
icons.set("customCollection", icon);
42+
const message: BroadcastIconsChangeMessage = {
43+
actionType: ActionType.RegisterIcon,
44+
collections: icons
45+
};
46+
broadcastChannel.postMessage(message);
47+
fixture.detectChanges();
48+
await wait(50);
49+
fixture.detectChanges();
50+
const iconService = fixture.componentInstance.iconService;
51+
const svg = iconService.getSvgIcon("customIcon", "customCollection");
52+
expect(svg).not.toBeUndefined();
53+
});
54+
55+
it('should correctly process event of setting an icon reference on channel.', async() => {
56+
const refs: Map<string, Map<string, IconMeta>> = new Map();
57+
const ref: Map<string, IconMeta> = new Map()
58+
ref.set("customIcon", {name: "customIcon", family: "customCollection" });
59+
refs.set("customCollection", ref);
60+
const message: BroadcastIconsChangeMessage = {
61+
actionType: ActionType.RegisterIcon,
62+
references: refs
63+
};
64+
broadcastChannel.postMessage(message);
65+
fixture.detectChanges();
66+
await wait(50);
67+
fixture.detectChanges();
68+
69+
const iconService = fixture.componentInstance.iconService;
70+
const serviceRef = iconService.getIconRef("customIcon", "customCollection");
71+
expect(serviceRef.family).toBe("customCollection");
72+
expect(serviceRef.name).toBe("customIcon");
73+
});
74+
75+
it('should send a request to sync state from any peer already on the channel on init.', async() => {
76+
await wait(50);
77+
expect(events.length).toBe(1);
78+
expect(events[0].actionType).toBe(ActionType.SyncState);
79+
});
80+
81+
it('should correctly process event of synching full state of icons on channel.', async() => {
82+
const icons: Map<string, Map<string, SvgIcon>> = new Map();
83+
const icon: Map<string, SvgIcon> = new Map()
84+
icon.set("customIcon", { svg: buildIcon });
85+
icons.set("customCollection", icon);
86+
const refs: Map<string, Map<string, IconMeta>> = new Map();
87+
const ref: Map<string, IconMeta> = new Map()
88+
ref.set("customIcon", {name: "customIcon", family: "customCollection" });
89+
refs.set("customCollection", ref);
90+
const message: BroadcastIconsChangeMessage = {
91+
actionType: ActionType.SyncState,
92+
collections: icons,
93+
references: refs
94+
};
95+
broadcastChannel.postMessage(message);
96+
await wait(50);
97+
const iconService = fixture.componentInstance.iconService;
98+
const svg = iconService.getSvgIcon("customIcon", "customCollection");
99+
expect(svg).not.toBeUndefined();
100+
const serviceRef = iconService.getIconRef("customIcon", "customCollection");
101+
expect(serviceRef.family).toBe("customCollection");
102+
expect(serviceRef.name).toBe("customIcon");
103+
});
104+
})
105+
});
106+
107+
@Component({
108+
template: `
109+
`,
110+
standalone: true,
111+
providers: [IgxIconBroadcastService, IgxIconService]
112+
})
113+
export class BroadcastServiceComponent {
114+
constructor(public iconBroadcast: IgxIconBroadcastService, public iconService: IgxIconService) {}
115+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Injectable, Optional } from '@angular/core';
2+
import { PlatformUtil } from '../../../igniteui-angular/src/lib/core/utils';
3+
import { IconMeta, IgxIconService } from '../../../igniteui-angular/src/lib/icon/icon.service';
4+
5+
6+
export interface SvgIcon {
7+
svg: string;
8+
title?: string;
9+
}
10+
11+
export type Collection<T, U> = Map<T, U>;
12+
13+
export enum ActionType {
14+
SyncState = 0,
15+
RegisterIcon = 1,
16+
UpdateIconReference = 2,
17+
}
18+
19+
export interface BroadcastIconsChangeMessage {
20+
actionType: ActionType;
21+
collections?: Collection<string, Map<string, SvgIcon>>;
22+
references?: Collection<string, Map<string, IconMeta>>;
23+
}
24+
25+
/** @hidden @internal **/
26+
@Injectable()
27+
export class IgxIconBroadcastService {
28+
private iconBroadcastChannel: BroadcastChannel;
29+
constructor(
30+
protected _iconService: IgxIconService,
31+
@Optional() private _platformUtil: PlatformUtil
32+
) {
33+
if (this._platformUtil?.isBrowser) {
34+
// open broadcast channel for sync with wc icon service.
35+
this.iconBroadcastChannel = new BroadcastChannel("ignite-ui-icon-channel");
36+
this.iconBroadcastChannel.onmessage = (event) => {
37+
const message = event.data as BroadcastIconsChangeMessage;
38+
if (message.actionType === ActionType.SyncState ||
39+
message.actionType === ActionType.RegisterIcon) {
40+
this.updateIconsFromCollection(message.collections);
41+
}
42+
43+
if (message.actionType === ActionType.SyncState ||
44+
message.actionType === ActionType.UpdateIconReference) {
45+
this.updateRefsFromCollection(message.references);
46+
}
47+
};
48+
// send message to sync state
49+
this.iconBroadcastChannel.postMessage({
50+
actionType: ActionType.SyncState
51+
});
52+
}
53+
}
54+
55+
private updateIconsFromCollection(collections: Collection<string, Map<string, SvgIcon>>) {
56+
if (!collections) return;
57+
const collectionKeys = collections.keys();
58+
for (const collectionKey of collectionKeys) {
59+
const collection = collections.get(collectionKey);
60+
for (const iconKey of collection.keys()) {
61+
const value = collection.get(iconKey).svg;
62+
this._iconService.addSvgIconFromText(iconKey, value, collectionKey);
63+
}
64+
}
65+
}
66+
67+
private updateRefsFromCollection(collections: Collection<string, Map<string, any>>) {
68+
if (!collections) return;
69+
const collectionKeys = collections.keys();
70+
for (const collectionKey of collectionKeys) {
71+
const collection = collections.get(collectionKey);
72+
for (const iconKey of collection.keys()) {
73+
const collectionName = collection.get(iconKey).collection;
74+
this._iconService.setIconRef(iconKey, 'default', {
75+
family: collectionName,
76+
name: iconKey
77+
});
78+
}
79+
}
80+
}
81+
82+
}

projects/igniteui-angular/src/lib/grids/filtering/base/grid-filtering-row.component.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,13 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
8181

8282
@Input()
8383
public get value(): any {
84-
return this.expression ? this.expression.searchVal : null;
84+
return this._value;
8585
}
8686

8787
public set value(val) {
88-
if (!val && val !== 0 && this.expression.searchVal) {
88+
if (!val && val !== 0 && (this.expression.searchVal || this.expression.searchVal === 0)) {
8989
this.expression.searchVal = null;
90+
this._value = null;
9091
const index = this.expressionsList.findIndex(item => item.expression === this.expression);
9192
if (index === 0 && this.expressionsList.length === 1) {
9293
this.filteringService.clearFilter(this.column.field);
@@ -98,11 +99,15 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
9899
return;
99100
}
100101
} else {
102+
if (val === '') {
103+
return;
104+
}
101105
const oldValue = this.expression.searchVal;
102106
if (isEqual(oldValue, val)) {
103107
return;
104108
}
105109

110+
this._value = val;
106111
this.expression.searchVal = DataUtil.parseValue(this.column.dataType, val);
107112
if (this.expressionsList.find(item => item.expression === this.expression) === undefined) {
108113
this.addExpression(true);
@@ -194,6 +199,7 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
194199
private isKeyPressed = false;
195200
private isComposing = false;
196201
private _cancelChipClick = false;
202+
private _value = null;
197203
private _icons = [
198204
{
199205
name: 'clear',
@@ -289,6 +295,7 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
289295
const selectedItem = this.expressionsList.find(expr => expr.isSelected === true);
290296
if (selectedItem) {
291297
this.expression = selectedItem.expression;
298+
this._value = this.expression.searchVal;
292299
}
293300

294301
this.filteringService.grid.localeChange
@@ -512,6 +519,7 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
512519
this.removeExpression(indexToDeselect, this.expression);
513520
}
514521
this.resetExpression();
522+
this._value = this.expression.searchVal;
515523
this.scrollChipsWhenAddingExpression();
516524
}
517525

@@ -685,7 +693,7 @@ export class IgxGridFilteringRowComponent implements AfterViewInit, OnDestroy {
685693
item.isSelected = !item.isSelected;
686694
if (item.isSelected) {
687695
this.expression = item.expression;
688-
696+
this._value = this.expression.searchVal;
689697
this.focusEditElement();
690698
}
691699
}

0 commit comments

Comments
 (0)