$ cat package.json
{
"name": "flowerbid",
"version": "0.1.0",
"private": true,
"homepage": "https://kirilligum.gitlab.io/flowerbid/",
"dependencies": {
"@uifabric/styling": "^6.38.0",
"firebase": "^5.6.0",
"firebase-tools": "^6.1.2",
"grommet-css": "^1.6.0",
"mermaid": "^8.0.0-rc.8",
"node-sass": "^4.11.0",
"npm": "^6.4.1",
"office-ui-fabric-react": "^6.109.0",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-router-dom": "^4.3.1"
},
"devDependencies": {
"react-scripts": "^2.1.1"
},
"scripts": {
"start": "set PORT=3006 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
import React from 'react';
import { DetailsList, SelectionMode} from 'office-ui-fabric-react/lib-commonjs/DetailsList';
import { ComboBox } from 'office-ui-fabric-react/lib-commonjs/ComboBox';
export default class Tryselect extends React.Component {
state = {
items : [ {value: 'one', data:['a','b']}, {value: 'two', data:['c','d']} ],
}
render(){
return (
<DetailsList
items={this.state.items}
selectionMode={SelectionMode.none}
onRenderItemColumn={this._renderItemColumn}
/>
)
}
_renderItemColumn = (item, index, column) => {
const fieldContent = item[column.fieldName || ''];
switch (column.fieldName) {
case 'data':
return <ComboBox
allowFreeform={false}
autoComplete="on"
defaultSelectedKey={item.data[0]}
options={
item.data.map(x=>{return {key:x,text:x}})
}/>;
default:
return <span>{fieldContent}</span>;
}
}
}
1) click on the combo box in row 1
2) select 'b'
3) click on the combo box in row 2
4) select 'd
i) at (3) the value in the row 1 combo box disappears
ii) at (4) the value in the row 1 combo box is absent
i) see b in row 1 combo box
ii) see b in row 1 combo box
Are you willing to submit a PR to fix? Yes
Requested priority: Blocking
Products/sites affected: (if applicable)
Looked at this a bit and I think the issue is with the way the ComboBox options are being created. On each render, the code is creating a new array of options, and the ComboBox is designed to reset the currently selected item when it gets a new array of options.
You can fix this by creating the arrays of options ahead of time and saving them somewhere--in this codepen, I put them in state, but you could put them wherever makes the most sense in your real code. https://codepen.io/ecraig12345/pen/VqmaKL
Let me know if this helps.
(Next time, if you could put your code in a codepen that would be super helpful--there's a template at http://aka.ms/fabricpen.)
@ecraig12345, its _generally_ a good practice to avoid initializing non-primitives in Component render calls, correct? I ask because of some reading I've done recently while analyzing DetailsList perf.
@KevinTCoughlin fieldContent initialization is from the DetailList documentation
@ecraig12345
I'm actually passing the table data and the choices as a prop or,actually, {...this.state}
When I modify the code after two selections (select first row, then select second row checkboxes), the selection disappear.
https://codepen.io/kirilligum/pen/wRogLV
const { DetailsList, SelectionMode, ComboBox } = window.Fabric;
class Tryselect extends React.Component {
render(){
return (
<DetailsList
items={this.props.tableItems}
selectionMode={SelectionMode.none}
onRenderItemColumn={this._renderItemColumn}
/>
)
}
_renderItemColumn = (item, index, column) => {
const fieldContent = item[column.fieldName || ''];
switch (column.fieldName) {
case 'data':
console.log('hi',this.props.items.map(x => ({ key: x, text: x })))
return <ComboBox
allowFreeform={false}
autoComplete="on"
defaultSelectedKey={this.props.items.map(x => ({ key: x, text: x }))[1].key}
options={this.props['items'].map(x => ({ key: x, text: x }))}
/>;
default:
return <span>{fieldContent}</span>;
}
}
}
class Parent extends React.Component {
state = {
tableItems: [ {value: 'one', data:['a','b']}, {value: 'two', data:['c','d']} ],
items:['a','b']
}
render (){
return <Tryselect {...this.state}/>
}
}
ReactDOM.render(
<Parent/>,
document.getElementById('content')
);
@KevinTCoughlin
fieldContentinitialization is from theDetailListdocumentation
Hence my question. Currently, DetailsList and its components' render code initializes non-primitives _a ton_. Its why I came across this recommendation on the net. We hope to fix them going forward if it is the recommended way. Anyway unrelated to the issue at hand _I guess_.
It often leads to issues with virtualization and inner component state.
@KevinTCoughlin You're probably right about not initializing non-primitives inline, due to perf and bugs like this. We should really try and keep anti-patterns out of our documentation, so I'll work on updating the DetailsLIst documentation to initialize things ahead of time.
i remove initialization const fieldContent = item[column.fieldName || ''];
the combobox still goes blank
@kirilligum The problem is this line, not the fieldContent one: options={this.props['items'].map(x => ({ key: x, text: x }))}
If you create the options from the items only once and save them somewhere (private member, state, whatever) like in the codepen I linked earlier, that should prevent the options from disappearing.
ok. sounds good. thank you
Just updated my codepen to be closer the new code you shared. https://codepen.io/ecraig12345/pen/VqmaKL?editors=0010
@ecraig12345 , you are amazing. thank you!