Fluent UI dropdown selection - reactjs

I am using fluent ui dropdown So, when i click on dropdown the first option is selected by default without selecting. If i click on dropdown and without selecting if i click somewhere on the page nothing should be selected and dropdown should be closed is what i want. Please help me with this.
Below is the code which iam using:
<Dropdown
disabled={this.state.HideLocationFilter}
selectedKey={selectedItem1 ? selectedItem1.key : undefined}
onChange={this._onChange1}
placeholder="Location"
options={[
{ key: 'UK', text: 'UK' },
{ key: 'Hyderabad', text: 'Hyderabad' },
{ key: 'Bangalore', text: 'Bangalore' },
{ key: 'Ahmedabad', text: 'Ahmedabad' },
{ key: 'Pune', text: 'Pune' },
{ key: 'Mumbai', text: 'Mumbai' },
{ key: 'USA', text: 'USA' }
]}
styles={dropdownStyles}
/>
private _onChange1 = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
console.log(`Selection change: ${item.text} ${item.selected ? 'selected' : 'unselected'}`);
if(item.selected == true)
{
this.setState({ selectedItem1: item });
}
};
Initially it is like this:location dropdown
When i click on dropdown it is selecting by default(find picture of the same):dropdown when clicked

There is an issue currently that when you press on the default option and click outside of the browser window and then click back in the dropdown selects the first option.
The solution for this is to looked at the type of event and short circuit the onChange if the type === 'focus':
const onChange = useCallback((e, value) => {
if (e.type === 'focus') return
// do if not type 'focus'
}, [])
In my situation I needed also to trigger a re-render and augmented the above as such:
const onChange = useCallback((callback) => (e, value) => {
if (e.type === 'focus') return callback()
// do if not type 'focus'
}, [])
Then when calling it:
<Dropdown
{...props}
onChange={onChange(() => setOnChangeTriggered(true))}
/>

Related

React form select element validation

I have a form with a select element that has 5 options and this form requires one of those options to be selected by the user in order to be valid. I am trying to implement form validation such that, when the user clicks on the select element, if the user were to click away from the select element without selecting an option, the error should be set for that element indicating to the user that this field is required.
I have tried to implement validation onBlur by checking if the country value has been set in state but if the user selects a country, then when the onBlur validation runs, the state isn't yet updated and the error will display even though the user has selected an option. How do I go about correctly implementing this validation?
const countries = [
{ value: "AU", text: "Australia" },
{ value: "NZ", text: "New Zealand" },
{ value: "UK", text: "United Kingdom" },
{ value: "MY", text: "Malaysia" },
{ value: "SG", text: "Singapore" },
];
const Form = function (props) {
const validateInput = (e) => {
console.log("validating input");
if (!props.country) {
console.log("set the error");
}
};
return (
<>
<Select
options={countries}
value={props.country}
onChange={props.setCountry}
placeholder="Select..."
id="country"
name="country"
invalid={props.errors.country}
onBlur={validateInput}
/>
</>
)

Update nested React state?

I'm trying to update part of a state object that is nested. This is the object:
const [buttonObject, setButtonObject] = useState({
intro: [
{
id: '123',
name: 'first_intro_name',
selected: false,
},
{
id: '124',
name: 'second_intro_name',
selected: false,
},
],
experience: [
{
id: '789',
name: 'first_experience_name',
selected: false,
},
{
id: '8910',
name: 'second_experience_name',
selected: false,
},
],
});
When a button is clicked I want to toggle the selected state. I'm using a click handler that looks like this:
const handleButtonClick = ({ id, selected }) => {
if (id === '123') {
buttonsObject.intro.map(
pref => (pref.selected = pref.id === id ? !pref.selected : selected)
);
setButtonsObject(buttonsObject);
} else if (id === '124') {
buttonsObject.intro.map(
pref => (pref.selected = pref.id === id ? !pref.selected : selected)
);
setButtonsObject(buttonsObject);
}
};
It would handle experiences as well. The issue is that right now it seems like rather than updating the object it just overwrites the object or creates a new one. It also doesnt pass that information back down to the component even though I have it routed correctly so it should.
Is there better/correct syntax for updating nested state like this?
Thanks.
instead of checking again with if condition use higher order array function and spread operator to get optimal solution.
setButtonObject(previous => {
return {
...previous,
info: previous.info.map(item => item.id === id ? {
...item,
selected: true
} ? item)
}
})

AG Grid, Capture the event on click of chevron

Ag-grid provides onCellClicked event for when a cell is clicked. But I noticed that it doesn't trigger when we click the chevron. I need to capture this event for analytics as a user might click the chevron directly rather than the cell itself. Any idea how to achieve this or what event to use here? I am using detailRenderer to render child rows, if that helps. Here is one of the columnDefs item:
{
headerName: "Line Item",
field: "displayLineNumber",
width: "100px",
sortable: false,
expandable: true,
onCellClicked: (event) => {
event.node.setExpanded(!event.node.expanded);
if (event.node.expanded === true) {
DataLayerUtils.pushEvent(
"click",
{
name: "Open Line Item",
type: "button",
},
{
click: {
category: "Quote Detail Table Interactions",
},
}
);
} else {
DataLayerUtils.pushEvent(
"click",
{
name: "Collapse Line Item",
type: "button",
},
{
click: {
category: "Quote Detail Table Interactions",
},
}
);
}
},
rowClass: ({ node, data }) => {
return `cmp-product-lines-grid__row ${
!data?.children || data.children.length === 0
? "cmp-product-lines-grid__row--notExpandable"
: ""
}`;
},
detailRenderer: ({ data }) => (
<section className="cmp-product-lines-grid__row cmp-product-lines-grid__row--expanded">
<ProductLinesChildGrid
gridProps={gridProps}
license={gridProps.agGridLicenseKey}
columnDefiniton={
whiteLabelMode ? whiteLabelCols() : quoteDetailsCols()
}
data={data.children}
onModelUpdateFinished={() => {
markupChanged(mutableGridData);
}}
/>
</section>
),
},
There's two ways to achieve this:
Implement the Grid Event rowGroupOpened (see: https://www.ag-grid.com/react-data-grid/grid-events/#reference-rowGrouping-rowGroupOpened)
This will be triggered whenever the user opens a group node.
onRowGroupOpened={(params) =>
console.log('onRowGroupOpened', params.expanded)
}
Implement the Grid Event cellMouseDown (see: https://www.ag-grid.com/react-data-grid/grid-events/#reference-selection-cellMouseDown) to capture the chevron click event.
This will be triggered only when the user clicks the expand chevron
onCellMouseDown={(params) => {
const isMasterRowGroupExpanded = params.event.target.classList.contains(
'ag-icon-tree-closed'
);
if (isMasterRowGroupExpanded) {
console.log('onCellMouseDown', params.value);
}
}}
See both of these approaches implemented in the following plunkr.

Semantic UI dropdown not setting value after selecting option

I am using React semantic ui. I am rendering a dropdown in Fieldset. I have written code such that, once a option is selected, the options is updated such that the selected option is removed from the list. But when I select an option from the dropdown, the selected value is not displayed, rather it shows empty.
Here is my code:
This is my dropdown code:
<Dropdown
name={`rows.${index}.mainField`}
className={"dropdown fieldDropdown"}
widths={2}
placeholder="Field"
fluid
selection
options={mainFieldOptions}
value={row.mainField}
onChange={(e, { value }) => {
setFieldValue(`rows.${index}.mainField`, value)
updateDropDownOptions(value)
}
}
/>
My options:
let mainField = [
{ key: "org", text: "org", value: "org" },
{ key: "role", text: "role", value: "role" },
{ key: "emailId", text: "emailId", value: "emailId" },
]
Also, I have:
const [mainFieldOptions, setMainFieldOptions] = useState(mainField)
And,
const updateDropDownOptions = (value:any) => {
let updatedOptions: { key: string; text: string; value: string }[] = []
mainFieldOptions.forEach(option => {
if(option.key != value){
updatedOptions.push({ key:option.key , text:option.key, value:option.key })
}
})
setMainFieldOptions(updatedOptions)
console.log("mainfield", mainField)
}
In onChange, if I dont call updateDropDownOptions() method, the dropdown value is set. But when I call the method, its giving blank value. Please help.
There are few changes required in your code,
You are pushing the entire initialValues when you are adding a row which is an [{}] but you need to push only {} so change your code to initialValues[0] in your push method.
Its not needed to maintain a additional state for the options. You can filter the options based on the selected option in other rows which is available in the values.rows .
Util for filtering the options
const getMainFieldOptions = (rows, index) => {
const selectedOptions = rows.filter((row, rowIndex) => rowIndex !== index);
const filteredOptions = mainField.filter(mainFieldOption => !selectedOptions.find(selectedOption => mainFieldOption.value === selectedOption.mainField));
return filteredOptions;
}
Call this util when rendering each row
values.rows.length > 0 &&
values.rows.map((row, index) => {
const mainFieldOptions = getMainFieldOptions(values.rows, index);
Working Sandbox

React Selecting dropdown option multiple times

I am wanting to be able to select a language I have called "Skip" more than one time without it disappearing from the dropdown. Currently, any language I select will disappear from the dropdown. Is this possible? Here's my code:
const languages = [
{ key: 'skip', text: 'Skip', value: 'Skip' },
{ key: 'english', text: 'English', value: 'English' },
{ key: 'french', text: 'French', value: 'French' },
]
handleAudioInputChange = (e, { name, value }) => this.setState( { [name]: value })
<Form.Select fluid search label='Audio Channels' name='audiochannelsValue' value={audiochannelsValue} options={languages} placeholder='Choose Audio Channels' onChange={this.handleAudioInputChange} multiple = "true"/>
I've tried multiple things such as hideSelectedOptions = {false}, but this does not seem to work. Any ideas?
If you only want a string based on the user input, you could do:
handleAudioInputChange = (e, { value }) => {
this.setState(prevState => {
const newVal = `${prevState.audiochannelsValue.length ? '/' : ''}${value}`;
return {
textValue: prevState.textValue.concat(newVal),
audiochannelsValue: value
};
});
}
This will build a string based on the previous state and separate each value with /. Haven't tested it, but it should generate (in order):
English
English/Skip
English/Skip/French
English/Skip/French/Skip

Resources