Skip to content

Commit

Permalink
#123 - Added sorting functionality to the collection data control
Browse files Browse the repository at this point in the history
  • Loading branch information
estruyf committed Dec 6, 2018
1 parent f1ad080 commit 5c5d3a4
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"new": [
],
"enhancements": [
"`PropertyFieldCodeEditor`: Added the functionality to sort the items in the collection [#123](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/123)"
],
"fixes": [
"`PropertyFieldCollectionData`: Issue with debounce validation overriding the inserted values [#113](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/113)",
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 1.13.0

**Enhancements**

- `PropertyFieldCodeEditor`: Added the functionality to sort the items in the collection [#123](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/123)

**Fixes**

- `PropertyFieldCollectionData`: Issue with debounce validation overriding the inserted values [#113](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/113)
Expand Down
4 changes: 4 additions & 0 deletions docs/documentation/docs/about/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 1.13.0

**Enhancements**

- `PropertyFieldCodeEditor`: Added the functionality to sort the items in the collection [#123](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/123)

**Fixes**

- `PropertyFieldCollectionData`: Issue with debounce validation overriding the inserted values [#113](https://github.com/SharePoint/sp-dev-fx-property-controls/issues/113)
Expand Down
19 changes: 10 additions & 9 deletions docs/documentation/docs/controls/PropertyFieldCollectionData.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,17 @@ PropertyFieldCollectionData("collectionData", {

The `PropertyFieldCollectionData` control can be configured with the following properties:

| Property | Type | Required | Description |
| Property | Type | Required | Description | Default Value |
| ---- | ---- | ---- | ---- |
| key | string | yes | An unique key that indicates the identity of this control. |
| label | string | yes | Property field label displayed on top. |
| panelHeader | string | yes | Label to be used as the header in the panel. |
| panelDescription | string | no | Property that allows you to specify a description in the collection panel. |
| manageBtnLabel | string | yes | Label of the button to open the panel. |
| fields | ICustomCollectionField[] | yes | The fields to be used for the list of collection data. |
| value | string | yes | The collection data value. |
| disabled | boolean | no | Specify if the control is disabled. |
| key | string | yes | An unique key that indicates the identity of this control. | |
| label | string | yes | Property field label displayed on top. | |
| panelHeader | string | yes | Label to be used as the header in the panel. | |
| panelDescription | string | no | Property that allows you to specify a description in the collection panel. | |
| manageBtnLabel | string | yes | Label of the button to open the panel. | |
| fields | ICustomCollectionField[] | yes | The fields to be used for the list of collection data. | |
| value | string | yes | The collection data value. | |
| enableSorting | boolean | no | Specify if you want to be able to sort the items in the collection. | false |
| disabled | boolean | no | Specify if the control is disabled. | false |

Interface `ICustomCollectionField`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export interface IPropertyFieldCollectionDataProps {
* The collection data value.
*/
value: any[];
/**
* Specify if you want to enable sorting
*/
enableSorting?: boolean;
/**
* Specify if the control is disabled.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Link } from 'office-ui-fabric-react/lib/components/Link';
import { Checkbox } from 'office-ui-fabric-react/lib/components/Checkbox';
import * as strings from 'PropertyControlStrings';
import { ICustomCollectionField, CustomCollectionFieldType, FieldValidator } from '..';
import { Dropdown } from 'office-ui-fabric-react/lib/components/Dropdown';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';
import { Callout, DirectionalHint } from 'office-ui-fabric-react/lib/components/Callout';
import { CollectionIconField } from '../collectionIconField';
import { clone, findIndex, sortBy } from '@microsoft/sp-lodash-subset';
Expand Down Expand Up @@ -367,14 +367,42 @@ export class CollectionDataItem extends React.Component<ICollectionDataItemProps
}
}

/**
* Retrieve all dropdown options
*/
private getSortingOptions(): IDropdownOption[] {
let opts: IDropdownOption[] = [];
const { totalItems } = this.props;
for (let i = 1; i <= totalItems; i++) {
opts.push({
text: i.toString(),
key: i
});
}
return opts;
}

/**
* Default React render
*/
public render(): React.ReactElement<ICollectionDataItemProps> {
const { crntItem } = this.state;
const opts = this.getSortingOptions();

return (
<div className={`${styles.tableRow} ${this.props.index === null ? styles.tableFooter : ""}`}>
{
(this.props.sortingEnabled && this.props.totalItems) && (
<span className={`${styles.tableCell}`}>
<Dropdown options={opts} selectedKey={this.props.index + 1} onChanged={(opt) => this.props.fOnSorting(this.props.index, opt.key as number) } />
</span>
)
}
{
(this.props.sortingEnabled && this.props.totalItems === null) && (
<span className={`${styles.tableCell}`}></span>
)
}
{
this.props.fields.map(f => (
<span className={`${styles.tableCell} ${styles.inputField}`}>{this.renderField(f, crntItem)}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ export interface ICollectionDataItemProps {
fields: ICustomCollectionField[];
index?: number;
item?: any;
sortingEnabled?: boolean;
totalItems?: number;

fAddItem?: (item: any) => void;
fAddInCreation?: (item: any) => void;
fUpdateItem?: (idx: number, item: any) => void;
fDeleteItem?: (idx: number) => void;
fValidation?: (idx: number, isValid: boolean) => void;
fOnSorting?: (oldIdx: number, newIdx: number) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { CollectionDataItem } from '../collectionDataItem';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/components/Button';
import { Icon } from 'office-ui-fabric-react/lib/components/Icon';
import * as strings from 'PropertyControlStrings';
import { cloneDeep } from '@microsoft/sp-lodash-subset';
import { cloneDeep, sortBy } from '@microsoft/sp-lodash-subset';

export class CollectionDataViewer extends React.Component<ICollectionDataViewerProps, ICollectionDataViewerState> {
private readonly SORT_IDX = "sortIdx";

constructor(props: ICollectionDataViewerProps) {
super(props);

Expand All @@ -22,19 +24,32 @@ export class CollectionDataViewer extends React.Component<ICollectionDataViewerP
* componentDidMount lifecycle hook
*/
public componentDidMount(): void {
let crntItems = this.props.value ? sortBy(cloneDeep(this.props.value), this.SORT_IDX) : [];
crntItems = crntItems.map((item, idx) => {
if (!item[this.SORT_IDX]) {
item[this.SORT_IDX] = idx + 1;
}
return item;
});
// Update the sort propety
crntItems = this.updateSortProperty(crntItems);
this.setState({
crntItems: this.props.value ? cloneDeep(this.props.value) : []
crntItems: sortBy(crntItems, this.SORT_IDX)
});
}

/**
* Add a new item to the collection
*/
private addItem = (item: any) => {
this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => ({
crntItems: [...prevState.crntItems, item],
inCreationItem: null
}));
this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => {
let crntItems = [...prevState.crntItems, item];
crntItems = this.updateSortProperty(crntItems);
return {
crntItems,
inCreationItem: null
};
});
}

/**
Expand All @@ -54,9 +69,15 @@ export class CollectionDataViewer extends React.Component<ICollectionDataViewerP
*/
private deleteItem = (idx: number) => {
this.setState((prevState: ICollectionDataViewerState): ICollectionDataViewerState => {
const { crntItems } = prevState;
let { crntItems } = prevState;
crntItems.splice(idx, 1);
return { crntItems };

// Update the sort propety
crntItems = this.updateSortProperty(crntItems);

return {
crntItems: sortBy(crntItems, this.SORT_IDX)
};
});
}

Expand Down Expand Up @@ -110,6 +131,54 @@ export class CollectionDataViewer extends React.Component<ICollectionDataViewerP
}
}

/**
* Move an item in the array
*
* @param crntItems
* @param oldIdx
* @param newIdx
*/
private moveItemTo(crntItems: any[], oldIdx: number, newIdx: number): any[] {
if (newIdx > -1 && newIdx < crntItems.length) {
const removedElement = crntItems.splice(oldIdx, 1)[0];
if (removedElement) {
crntItems.splice(newIdx, 0, removedElement);
}
}
return crntItems;
}

/**
* Update the sort property
*
* @param crntItems
*/
private updateSortProperty(crntItems: any[]): any[] {
// Update the sort order
return crntItems.map((item, itemIdx) => {
item[this.SORT_IDX] = itemIdx + 1;
return item;
});
}

/**
* Update the sort order
*/
private updateSortOrder = (oldIdx: number, newIdx: number) => {
this.setState((prevState: ICollectionDataViewerState) => {
const { crntItems } = prevState;
let newOrderedItems = cloneDeep(crntItems);
newOrderedItems = this.moveItemTo(newOrderedItems, oldIdx, newIdx - 1);
newOrderedItems = this.updateSortProperty(newOrderedItems);
newOrderedItems = sortBy(newOrderedItems, this.SORT_IDX);
console.log(newOrderedItems);

return {
crntItems: newOrderedItems
};
});
}

/**
* Save the collection data
*/
Expand All @@ -132,6 +201,11 @@ export class CollectionDataViewer extends React.Component<ICollectionDataViewerP
<div>
<div className={styles.table}>
<div className={`${styles.tableRow} ${styles.tableHead}`}>
{
this.props.enableSorting && (
<span className={styles.tableCell}></span>
)
}
{
this.props.fields.map(f => (
<span className={styles.tableCell}>{f.title} { f.required && <Icon className={styles.required} iconName="Asterisk" /> }</span>
Expand All @@ -142,20 +216,25 @@ export class CollectionDataViewer extends React.Component<ICollectionDataViewerP
</div>
{
(this.state.crntItems && this.state.crntItems.length > 0) && (
this.state.crntItems.map((item, idx) => (
this.state.crntItems.map((item, idx, allItems) => (
<CollectionDataItem key={idx}
fields={this.props.fields}
index={idx}
item={item}
totalItems={allItems.length}
sortingEnabled={this.props.enableSorting}
fUpdateItem={this.updateItem}
fDeleteItem={this.deleteItem}
fValidation={this.validateItem} />
fValidation={this.validateItem}
fOnSorting={this.updateSortOrder} />
))
)
}
<CollectionDataItem fields={this.props.fields}
index={null}
item={null}
sortingEnabled={this.props.enableSorting}
totalItems={null}
fAddItem={this.addItem}
fAddInCreation={this.addInCreation} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styles from '../PropertyFieldCollectionDataHost.module.scss';
import { Async } from 'office-ui-fabric-react/lib/Utilities';
import { ICollectionNumberFieldProps, ICollectionNumberFieldState } from '.';
import { ICustomCollectionField } from '..';
import { isEqual } from '@microsoft/sp-lodash-subset';

export class CollectionNumberField extends React.Component<ICollectionNumberFieldProps, ICollectionNumberFieldState> {
private async: Async;
Expand Down Expand Up @@ -30,6 +31,20 @@ export class CollectionNumberField extends React.Component<ICollectionNumberFiel
this.valueChange(this.props.field, this.props.item[this.props.field.id]);
}

/**
* componentWillUpdate lifecycle hook
*
* @param nextProps
* @param nextState
*/
public componentWillUpdate(nextProps: ICollectionNumberFieldProps, nextState: ICollectionNumberFieldState): void {
if (!isEqual(nextProps.item, this.props.item)) {
this.setState({
value: nextProps.item[nextProps.field.id]
});
}
}

/**
* Value change event handler
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export default class PropertyControlsTestWebPart extends BaseClientSideWebPart<I
manageBtnLabel: "Manage collection data",
panelDescription: "This is the description which appears in the panel.",
value: this.properties.collectionData,
enableSorting: true,
fields: [
{
id: "Title",
Expand Down

0 comments on commit 5c5d3a4

Please sign in to comment.