Skip to content

Commit a3531f6

Browse files
feat: add string array support to solo object properties
1 parent 5e67d66 commit a3531f6

File tree

5 files changed

+604
-40
lines changed

5 files changed

+604
-40
lines changed

README.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,64 @@ React.render(
143143
)
144144
```
145145

146+
## Solo Filtering ##
147+
148+
The `solo` prop allows you to filter data to show only specific values. It supports both single values and arrays for multi-value filtering.
149+
150+
### Single Value Filtering (Original Behavior)
151+
152+
```jsx
153+
<ReactPivot
154+
solo={{ firstName: 'John', state: 'NY' }}
155+
// ... other props
156+
/>
157+
```
158+
159+
### Array Value Filtering (New Feature)
160+
161+
```jsx
162+
<ReactPivot
163+
solo={{
164+
firstName: ['John', 'Jane', 'Bob'],
165+
state: ['NY', 'CA']
166+
}}
167+
// ... other props
168+
/>
169+
```
170+
171+
### Mixed Value Filtering
172+
173+
```jsx
174+
<ReactPivot
175+
solo={{
176+
firstName: ['John', 'Jane'], // Multiple values
177+
department: 'Engineering', // Single value
178+
state: ['NY', 'CA', 'TX'] // Multiple values
179+
}}
180+
// ... other props
181+
/>
182+
```
183+
184+
### Filtering Logic
185+
186+
- **Within arrays**: Uses OR logic (matches any value in the array)
187+
- **Between properties**: Uses AND logic (all properties must match)
188+
- **Empty arrays**: Filter out all rows for that property
189+
- **Display**: Array values are shown as comma-separated strings
190+
191+
### Example
192+
193+
```jsx
194+
// This configuration:
195+
solo={{
196+
state: ['NY', 'CA'],
197+
department: ['Sales', 'Marketing']
198+
}}
199+
200+
// Would match rows where:
201+
// (state === 'NY' OR state === 'CA') AND (department === 'Sales' OR department === 'Marketing')
202+
```
203+
146204
See it all together in [example/basic.jsx](https://github.com/davidguttman/react-pivot/blob/master/example/basic.jsx)
147205

148206
### Optional Arguments ###
@@ -154,7 +212,7 @@ csvTemplateFormat | boolean | apply template formatting to data before csv expor
154212
defaultStyles | boolean | apply default styles from style.css | true
155213
hiddenColumns | array | columns that should not display | []
156214
nPaginateRows | number | items per page setting | 25
157-
solo | object | item that should be displayed solo | null
215+
solo | object | item that should be displayed solo. Values can be strings or arrays of strings for multi-value filtering | null
158216
sortBy | string | name of column to use for record sort | null
159217
sortDir | string | sort direction, either 'asc' or 'desc' | 'asc'
160218
tableClassName | string | assign css class to table containing react-pivot elements | ''
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# feat: add string array support to solo object properties
2+
3+
## Project Goals
4+
5+
The goal of this feature is to enhance the filtering capabilities of the `ReactPivot` component by allowing the `solo` prop to accept arrays of strings. This enables multi-value filtering for a given dimension, providing more flexible and powerful data exploration for users.
6+
7+
## Approaches
8+
9+
### Approach 1 - Direct Implementation (Implemented Here)
10+
11+
This approach involves modifying the core logic of the `ReactPivot` component to natively support array values in the `solo` prop.
12+
13+
- **Core Logic Implementation:**
14+
- A new function, `getFilteredRows`, was introduced to filter the raw data based on the `solo` prop before any calculations are performed. This function iterates through the `solo` object and applies the following logic:
15+
- If a `solo` property value is an array, the function checks if the row's value for that dimension is present in the array (OR condition).
16+
- If a `solo` property value is a single string, it performs a direct comparison (existing AND condition).
17+
- The filtering combines multiple `solo` properties with AND logic.
18+
- The `setSolo` function was updated to handle array manipulation. When a value is selected:
19+
- If the existing `solo` value is an array, the new value is added or removed (toggled).
20+
- If the existing `solo` value is a single value, it's converted to an array when a second value is added.
21+
22+
- **UI Control for Solo Filters:**
23+
- To make this new functionality user-friendly, a new component, `SoloControl`, was created.
24+
- This new component provides a user interface for managing the `solo` filters. It displays each active filter and allows users to:
25+
- **Add values:** A dropdown menu for each dimension shows the unique values from the dataset, allowing users to add them to the filter.
26+
- **Remove values:** Each selected value in a filter can be individually removed.
27+
- **Remove filters:** The entire filter for a dimension can be removed.
28+
- The `SoloControl` component is rendered in the main `ReactPivot` component, and it communicates changes back to the parent component through the `onChange` prop.
29+
30+
- **Unique Value Extraction:**
31+
- To populate the dropdowns in the `SoloControl` component, a `getUniqueValues` function was added to `index.jsx`.
32+
- This function iterates through the dataset and extracts all unique values for each dimension, which are then passed to the `SoloControl` component.
33+
34+
#### Pros
35+
36+
- **Integrated Solution:** The feature is built directly into the component, providing a seamless experience for the user.
37+
- **High Performance:** Filtering is done in memory, and the `getFilteredRows` function is optimized for performance.
38+
- **Good User Experience:** The `SoloControl` component provides an intuitive way to manage complex filters.
39+
40+
#### Cons
41+
42+
- **Increased Complexity:** The core component's logic is now more complex, which could make future maintenance more challenging.
43+
- **Tightly Coupled:** The filtering logic is tightly coupled with the `ReactPivot` component, making it difficult to reuse in other contexts.
44+
45+
### Approach 2 - Custom Patch Layer
46+
47+
This approach involves creating a custom patch layer that intercepts the `rows` prop and applies the filtering logic before passing the data to the `ReactPivot` component.
48+
49+
- **Patch Layer:**
50+
- A higher-order component (HOC) would be created to wrap the `ReactPivot` component.
51+
- This HOC would be responsible for managing the `solo` state and filtering the `rows` prop before passing it to the `ReactPivot` component.
52+
- The `solo` prop of the `ReactPivot` component would not be used directly.
53+
54+
#### Pros
55+
56+
- **Separation of Concerns:** The filtering logic is decoupled from the `ReactPivot` component, making the code easier to maintain and reason about.
57+
- **Reusability:** The patch layer could be reused with other components that need similar filtering capabilities.
58+
- **Less Intrusive:** This approach does not require any changes to the core `ReactPivot` component.
59+
60+
#### Cons
61+
62+
- **Potential for Bugs:** The patch layer could introduce subtle bugs if it's not carefully implemented and tested.
63+
- **Less Performant:** The patch layer would add an extra layer of processing, which could impact performance, especially with large datasets.
64+
- **More Complex to Use:** Users would need to understand how to use the patch layer in addition to the `ReactPivot` component.
65+
66+
### Approach 3 - Wrapper Component
67+
68+
This approach involves creating a new wrapper component that encapsulates the `ReactPivot` component and provides the desired filtering functionality.
69+
70+
- **Wrapper Component:**
71+
- A new component, `FilterableReactPivot`, would be created.
72+
- This component would render the `ReactPivot` component and provide its own `solo` prop that supports arrays.
73+
- The `FilterableReactPivot` component would be responsible for managing the `solo` state and filtering the `rows` prop before passing it to the `ReactPivot` component.
74+
75+
#### Pros
76+
77+
- **Clear API:** The `FilterableReactPivot` component would provide a clear and concise API for users who need the filtering functionality.
78+
- **Good for a library:** This approach is well-suited for a library, as it provides a clean separation between the core component and the new functionality.
79+
- **Easy to maintain:** The filtering logic is contained within the `FilterableReactPivot` component, making it easy to maintain and update without affecting the core `ReactPivot` component.
80+
81+
#### Cons
82+
83+
- **Code Duplication:** The `FilterableReactPivot` component would duplicate some of the logic from the `ReactPivot` component, which could lead to maintenance issues.
84+
- **Less Flexible:** The `FilterableReactPivot` component would be less flexible than the patch layer approach, as it would be tightly coupled with the `ReactPivot` component.
85+
- **Increased Bundle Size:** The `FilterableReactPivot` component would add to the overall bundle size of the application.

example/demo.jsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ var hideRows = row => row.amountTotal < 1000
5858

5959
var Demo = createReactClass({
6060
getInitialState: function() {
61-
return {showInput: false}
61+
return {
62+
showInput: false,
63+
solo: {
64+
'Transaction Type': ['deposit','withdrawal']
65+
}
66+
}
6267
},
6368
toggleShow: function() {
6469
var showInput = this.state.showInput
@@ -73,6 +78,11 @@ var Demo = createReactClass({
7378
ReactPivot is a data-grid component with pivot-table-like functionality.
7479
</p>
7580

81+
<p>
82+
<strong>New Feature:</strong> Interactive Solo Control! When solo filters are applied, you can edit them using the dropdown interface.
83+
Change the dimension using the green dropdown, add multiple values to create arrays with OR logic, and click × to remove individual values.
84+
</p>
85+
7686
<p>
7787
Muggles will love you.
7888
</p>
@@ -90,7 +100,8 @@ var Demo = createReactClass({
90100
reduce={reduce}
91101
activeDimensions={['Transaction Type']}
92102
hideRows={hideRows}
93-
nPaginateRows={20} />
103+
nPaginateRows={20}
104+
solo={this.state.solo} />
94105
</div>
95106

96107
<div className={this.state.showInput ? '' : 'hide'}>

0 commit comments

Comments
 (0)