Skip to content

Commit 75c80a0

Browse files
FranckyCwobba
authored andcommitted
[ModernSearch] Fixed #145 (#146)
* [ModernSearch] * Revert changes made to new SearchResultsContainer regarding new props handling. * [ModernSearch] - Fixed issue on group expand/collapse defaults #145
1 parent fc78e01 commit 75c80a0

File tree

5 files changed

+200
-159
lines changed

5 files changed

+200
-159
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { IRefinementValue } from "../../../../../models/ISearchResult";
2+
import { IGroup } from "office-ui-fabric-react/lib/components/GroupedList";
23

34
interface ILinkPanelState {
45
showPanel?: boolean;
5-
valueToRemove: IRefinementValue;
6-
expandedGroups?: string[];
6+
groups?: IGroup[];
7+
items?: JSX.Element[];
78
}
89

910
export default ILinkPanelState;

solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/LinkPanel.tsx

Lines changed: 102 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,31 @@ import * as update from 'immutabi
77
import {
88
GroupedList,
99
IGroup,
10-
IGroupDividerProps
10+
IGroupDividerProps,
11+
IGroupedList
1112
} from 'office-ui-fabric-react/lib/components/GroupedList/index';
1213
import { Scrollbars } from 'react-custom-scrollbars';
1314
import {Link} from 'office-ui-fabric-react/lib/Link';
1415
import {ActionButton} from 'office-ui-fabric-react/lib/Button';
1516
import styles from './LinkPanel.module.scss';
1617
import * as strings from 'SearchRefinersWebPartStrings';
1718
import TemplateRenderer from '../../Templates/TemplateRenderer';
18-
import { IRefinementResult } from '../../../../../models/ISearchResult';
19+
import { IRefinementResult, IRefinementValue } from '../../../../../models/ISearchResult';
1920
import IRefinerConfiguration from '../../../../../models/IRefinerConfiguration';
21+
import IFilterLayoutProps from '../IFilterLayoutProps';
22+
import { isEqual } from '@microsoft/sp-lodash-subset';
2023

2124
export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPanelState> {
2225

26+
private _groupedList: IGroupedList;
27+
2328
public constructor(props: ILinkPanelProps) {
2429
super(props);
2530

2631
this.state = {
2732
showPanel: false,
28-
expandedGroups: [],
29-
valueToRemove: null
33+
items: [],
34+
groups: []
3035
};
3136

3237
this._onTogglePanel = this._onTogglePanel.bind(this);
@@ -39,58 +44,6 @@ export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPan
3944

4045
public render(): React.ReactElement<ILinkPanelProps> {
4146

42-
let items: JSX.Element[] = [];
43-
let groups: IGroup[] = [];
44-
45-
if (this.props.refinementResults.length === 0) return <span />;
46-
47-
// Initialize the Office UI grouped list
48-
this.props.refinementResults.map((refinementResult, i) => {
49-
50-
// Get group name
51-
let groupName = refinementResult.FilterName;
52-
const configuredFilter = this.props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;});
53-
groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName;
54-
55-
groups.push({
56-
key: i.toString(),
57-
name: groupName,
58-
count: 1,
59-
startIndex: i,
60-
isDropEnabled: true,
61-
isCollapsed: this.state.expandedGroups.indexOf(groupName) === -1 ? true : false
62-
});
63-
64-
// Get selected values for this specfic refiner
65-
// This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components
66-
// In this case we use the refiners global state to recreate the 'local' state for this component
67-
const selectedFilter = this.props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName;});
68-
const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : [];
69-
70-
// Check if the value to remove concerns this refinement result
71-
let valueToRemove = null;
72-
if (this.state.valueToRemove) {
73-
if (refinementResult.Values.filter(value => {
74-
return value.RefinementToken === this.state.valueToRemove.RefinementToken || refinementResult.FilterName === this.state.valueToRemove.RefinementName; }).length > 0
75-
) {
76-
valueToRemove = this.state.valueToRemove;
77-
}
78-
}
79-
80-
items.push(
81-
<TemplateRenderer
82-
key={i}
83-
refinementResult={refinementResult}
84-
shouldResetFilters={this.props.shouldResetFilters}
85-
templateType={configuredFilter[0].template}
86-
valueToRemove={valueToRemove}
87-
onFilterValuesUpdated={this.props.onFilterValuesUpdated}
88-
language={this.props.language}
89-
selectedValues={selectedFilterValues}
90-
/>
91-
);
92-
});
93-
9447
const renderSelectedFilterValues: JSX.Element[] = this.props.selectedFilterValues.map((value) => {
9548

9649
// Get the 'display name' of the associated refiner for this value
@@ -105,25 +58,25 @@ export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPan
10558
return (
10659
<Label className={styles.filter}>
10760
<i className='ms-Icon ms-Icon--ClearFilter' onClick={() => {
108-
this.setState({
109-
valueToRemove: value
110-
});
61+
this._initItems(this.props, value);
62+
this._groupedList.forceUpdate();
11163
}}></i>
11264
{filterName}
11365
</Label>);
11466
});
11567

11668
const renderAvailableFilters = <GroupedList
11769
ref='groupedList'
118-
items={items}
70+
componentRef={ (g) => { this._groupedList = g; }}
71+
items={this.state.items}
11972
onRenderCell={this._onRenderCell}
12073
className={styles.linkPanelLayout__filterPanel__body__group}
12174
groupProps={
12275
{
12376
onRenderHeader: this._onRenderHeader
12477
}
12578
}
126-
groups={groups} />;
79+
groups={this.state.groups} />;
12780

12881
const renderLinkRemoveAll = this.props.hasSelectedValues ?
12982
(<div className={`${styles.linkPanelLayout__filterPanel__body__removeAllFilters} ${this.props.hasSelectedValues && "hiddenLink"}`}>
@@ -180,15 +133,22 @@ export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPan
180133
}
181134

182135
public componentDidMount() {
183-
this._initExpandedGroups(this.props.refinementResults, this.props.refinersConfiguration);
136+
this._initGroups(this.props);
137+
this._initItems(this.props);
184138
}
185139

186140
public componentWillReceiveProps(nextProps: ILinkPanelProps) {
187-
this.setState({
188-
valueToRemove: null
189-
});
141+
let shouldReset = false;
142+
143+
if (!isEqual(this.props.refinersConfiguration, nextProps.refinersConfiguration)) {
144+
shouldReset = true;
145+
}
146+
147+
this._initGroups(nextProps, shouldReset);
148+
this._initItems(nextProps);
190149

191-
this._initExpandedGroups(nextProps.refinementResults, nextProps.refinersConfiguration);
150+
// Need to force an update manually because nor items or groups update will be considered as an update by the GroupedList component.
151+
this._groupedList.forceUpdate();
192152
}
193153

194154
private _onRenderCell(nestingDepth: number, item: any, itemIndex: number) {
@@ -205,16 +165,7 @@ export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPan
205165
<div className={ styles.linkPanelLayout__filterPanel__body__group__header }
206166
style={props.groupIndex > 0 ? { marginTop: '10px' } : undefined }
207167
onClick={() => {
208-
209-
// Update the index for expanded groups to be able to keep it open after a re-render
210-
const updatedExpandedGroups =
211-
props.group.isCollapsed ?
212-
update(this.state.expandedGroups, { $push: [props.group.name] }) :
213-
update(this.state.expandedGroups, { $splice: [[this.state.expandedGroups.indexOf(props.group.name), 1]] });
214-
215-
this.setState({
216-
expandedGroups: updatedExpandedGroups,
217-
});
168+
props.onToggleCollapse(props.group);
218169
}}>
219170
<div className={styles.linkPanelLayout__filterPanel__body__headerIcon}>
220171
<i className={props.group.isCollapsed ? 'ms-Icon ms-Icon--ChevronDown' : 'ms-Icon ms-Icon--ChevronUp'}></i>
@@ -241,21 +192,86 @@ export default class LinkPanel extends React.Component<ILinkPanelProps, ILinkPan
241192
* @param refinementResults the refinements results
242193
* @param refinersConfiguration the current refiners configuration
243194
*/
244-
private _initExpandedGroups(refinementResults: IRefinementResult[], refinersConfiguration: IRefinerConfiguration[]) {
195+
private _initGroups(props: IFilterLayoutProps, shouldResetCollapse?: boolean) {
245196

246-
refinementResults.map((refinementResult, i) => {
197+
let groups: IGroup[] = [];
198+
props.refinementResults.map((refinementResult, i) => {
247199

248200
// Get group name
249201
let groupName = refinementResult.FilterName;
250-
const configuredFilter = refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;});
251-
groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName;
252-
const showExpanded = configuredFilter.length > 0 && configuredFilter[0].showExpanded ? configuredFilter[0].showExpanded : false;
253-
254-
if (showExpanded) {
255-
this.setState({
256-
expandedGroups: update(this.state.expandedGroups, { $push: [groupName] })
257-
});
202+
const configuredFilters = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;});
203+
groupName = configuredFilters.length > 0 && configuredFilters[0].displayValue ? configuredFilters[0].displayValue : groupName;
204+
let isCollapsed = true;
205+
206+
const existingGroups = this.state.groups.filter(g => { return g.name === groupName;});
207+
208+
if (existingGroups.length > 0 && !shouldResetCollapse) {
209+
isCollapsed = existingGroups[0].isCollapsed;
210+
} else {
211+
isCollapsed = configuredFilters.length > 0 && configuredFilters[0].showExpanded ? !configuredFilters[0].showExpanded : true;
258212
}
213+
214+
let group: IGroup = {
215+
key: i.toString(),
216+
name: groupName,
217+
count: 1,
218+
startIndex: i,
219+
isCollapsed: isCollapsed
220+
};
221+
222+
groups.push(group);
223+
});
224+
225+
this.setState({
226+
groups: update(this.state.groups, { $set: groups })
227+
});
228+
}
229+
230+
/**
231+
* Initializes items in for goups in the GroupedList
232+
* @param refinementResults the refinements results
233+
*/
234+
private _initItems(props: IFilterLayoutProps, refinementValueToRemove?: IRefinementValue): void {
235+
236+
let items: JSX.Element[] = [];
237+
238+
// Initialize the Office UI grouped list
239+
props.refinementResults.map((refinementResult, i) => {
240+
241+
const configuredFilter = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName; });
242+
243+
// Get selected values for this specfic refiner
244+
// This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components
245+
// In this case we use the refiners global state to recreate the 'local' state for this component
246+
const selectedFilter = props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName; });
247+
const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : [];
248+
249+
// Check if the value to remove concerns this refinement result
250+
let valueToRemove = null;
251+
if (refinementValueToRemove) {
252+
if (refinementResult.Values.filter(value => {
253+
return value.RefinementToken ===refinementValueToRemove.RefinementToken || refinementResult.FilterName === refinementValueToRemove.RefinementName; }).length > 0
254+
) {
255+
valueToRemove = refinementValueToRemove;
256+
}
257+
}
258+
259+
items.push(
260+
<TemplateRenderer
261+
key={i}
262+
refinementResult={refinementResult}
263+
shouldResetFilters={props.shouldResetFilters}
264+
templateType={configuredFilter[0].template}
265+
valueToRemove={valueToRemove}
266+
onFilterValuesUpdated={props.onFilterValuesUpdated}
267+
language={props.language}
268+
selectedValues={selectedFilterValues}
269+
/>
270+
);
271+
});
272+
273+
this.setState({
274+
items: update(this.state.items, { $set: items })
259275
});
260276
}
261277
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { IGroup } from "office-ui-fabric-react/lib/components/GroupedList";
2+
13
interface IVerticalState {
2-
expandedGroups?: string[];
4+
groups?: IGroup[];
5+
items?: JSX.Element[];
36
}
47

58
export default IVerticalState;

0 commit comments

Comments
 (0)