Identify which [SelectField] [DropDownMenu] fired onChange - material-ui

I am programmatically rendering multiple SelectField and DropDownMenu components. I am trying to work with a single onChange handler functions, but I'm have not found a way to reference specific SelectField / DropDownMenu that triggered the event so I can update state accordingly.
The params passed for the onChange event seem not to contain any helpful information to identify the firing components. Any ideas?

Here's an example of how this can be done
https://jsfiddle.net/davidebarros/k9ng7bk9/
This is assuming you are familiar with the es6 arrow function syntax.
state = {
dropDown1: 1,
dropDown2: 4,
selectfield1: null,
selectfield2: null
}
onChange = (type) => (event, index, value) => {
this.setState({
[type]: value
})
//In your render method
<SelectField
floatingLabelText="Select Field 1"
value={this.state.selectfield1}
onChange={this.onChange("selectfield1")}>
<MenuItem value={1} primaryText="Select 1, value 1" />
<MenuItem value={2} primaryText="Select 1, value 2" />
</SelectField>

Related

React bootstrap Typeahead error on backspace

Im using react Bootstrap Typeahead in my code, problem is whenever I use backspace to remove my selection and when I reach a point where there is no letter, my code breaks and I get below error.
**Uncaught Invariant Violation: One or more options does not have a valid label string. Check the labelKey prop to ensure that it matches the correct option key and provides a string for filtering and display.
My Typeahead Code :
<Typeahead
id="empName"
options={this.state.EmployeeNameOptions}
selected={[this.state.EmployeeName]}
placeholder="Enter Employee Name"
style={{ zIndex: 9999999 }}
onInputChange={text => {
this.setState({
EmployeeName: text,
})
}}
onChange={(e, val) => {
this.handleChange(e, val);
}}
/>
You're using onInputChange and onChange incorrectly. Every time you type inside the input, onInputChange is updating your state and changing the value for selected, leading to unexpected results. Meanwhile, onChange provides an array of the selected values its argument, not an event and value. Try the following instead:
<Typeahead
...
options={this.state.EmployeeNameOptions}
selected={this.state.selectedEmployee}
onChange={(selected) => {
this.setState({ selectedEmployee: selected });
}}
/>

How to handle state in Material UI Data Grid's components

I'm attempting to add search functionality to a data grid component. In order to achieve this, I'm adding an input element to the table using the components.header prop as follows (I've omitted irrelevant code):
const Table = () => {
const filterRows = (rows) => {
return rows;
};
const [searchTerm, setSearchTerm] = useState("");
const Header = () => (
<input
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
/>
);
return (
<div style={{ height: 500 }}>
<DataGrid
rows={searchTerm ? filterRows(orders) : orders}
columns={orderColumns}
components={{
header: () => <Header />
}}
/>
</div>
);
};
The issue I'm having is that the input element loses focus each time a character is entered into the input in the header. Presumably, this is because it updates state, which triggers a re-render. This makes it impossible to share and access state of anything contained inside the Data Grid's components because it requires a React.FC argument and won't accept a ReactElement so the input is always re-rendered.
Am I missing something or is this actually not possible with Material UI's Data Grid? It seems like a pretty expected use-case to have something stateful in the header that we'd want to access like a controlled input component in order to use it as a kind of "Tool bar" as mentioned in the Material UI docs.
I've created a code sandbox to replicate the issue here: https://codesandbox.io/s/compassionate-keldysh-z995k?file=/src/App.js:246-726.
Cheers.

onSortChanged not triggering

using ag-grid 21.0.1,
my onSortChanged handler is not triggering when the user changes the grid sort by clicking on the column header.
function sortHandler(sortEvent: SortChangedEvent) {
sortEvent.api.refreshCells({
columns: sortEvent.api.getSortModel().map((c: any) => c.colId)
});
}
return (
<AgGridReact
headerHeight={headerHeight}
rowData={data}
gridOptions={gridOptions}
pinnedBottomRowData={footerRow}
pinnedTopRowData={headerRow}
onSortChanged={sortHandler}
/>
doesn't matter if I pass sortHandler as a prop to the react component or I declare it on the gridOptions object

In Reactjs how do I update the correct value in the parent state with a callback that's been passed to a nested child component?

I've been on this one for days, and all my reading hasn't helped me find a clean solution for this particular case.
Issue
I can send a parent state value and callback down to a nested component, but once the callback is triggered in the child I don't know how I can send the updated value back to the parent so it can update the correct value.
For instance
Parent Component (Has values and the callback)
Child Component (Values and callback is passed here)
Grand Child Component (Values Updated here and callback triggered)
What is SEEMS to cause the Issue
It seems the issue is I need the original key name in order for "setState" to update the correct value in the parent component(or at least it seems that way), but the child component only has original value and new updated value and has no access to the key associated with original value in the parent component.
Important Notes on Best Practice Surrounding this question
-From what I understand it is bad practice to use refs to handle nested situations like this.
-It seems like there is a cleaner solution than sending a prop for the key and another for the value.
-I'm assuming also that flux might provide a solution to this issue but I feel that there is a basic component to component communication technique or principle that I'm missing here.
Here is a bare bones example of what I'm dealing with.
/*All the values need to be updated here so that the inputs can used for calculation and then sent to a component that displays the output*/
var Calculator =
React.createClass({
getInitialState:function(){
return {
value1: "Enter value 1", /*These values are passed to a nested child component, can't figure how to update the right one*/
value2: "Enter value 2",
}
},
update: function(update){
this.setState(
update
);
},
render: function () {
return (
<div>
<h2>Input</h2>
<Input onClick={this.handleClick} update={this.update} value1={this.state.value1} value2={this.state.value2} /> //pass the values here
<h2>Output</h2>
<Output />
</div>
);
},
handleClick: function () {
//want to update the state for the correct value here
}
});
/* A compenent that is a middle layer between the parent and nested child component I'm working with*/
var Input =
React.createClass({
update: function(){
this.props.update();
},
render:function(){
return (
<div>
<p><InputComponent update={this.update} value={this.props.value1} /> / <InputComponent value={this.props.value2}/></p>//passing down values again
<p><ButtonComponent onClick={this.props.onClick} /></p>
</div>
)
}
});
/*This is the child component that gets the value and call back from the top level component. It will get updates to the values and send them back to change state of the parent component.*/
var InputComponent =
React.createClass({
handleChange: function(event) {
this.props.update();
},
render: function() {
return <input type="text" value={this.props.value} onChange={this.handleChange} />; //this props value has no key associated with it. Cant't make update object ie {originalkey:newValue}
}
});
/* This component is triggered to carry out calculations in the parent class.*/
var ButtonComponent =
React.createClass({
render:function(){
return <button onClick={this.handleClick}> {this.props.txt} </button>
},
handleClick: function(){
this.props.onClick();
}
});
/*The inputs will be calculated and turned to outputs that will displayed here.This component doesn't matter for the question so I left it empty*/
var Output =
React.createClass({
});
Here's an example I just put together on jsfiddle.
Instead of putting update in setState, we pass a value to update from the child component and let the parent set its state.
In the parent, we have:
_update: function(val){
this.setState({
msg: val
});
},
render: function() {
return (
<div>
<p>Message: {this.state.msg}</p>
<Child _update={this._update} />
</div>
);
}
And in the child, we have a _handleClick function that calls the parent _update function with values:
_handleClick: function(){
this.props._update(React.findDOMNode(this.refs.text).value);
},
render: function(){
return (
<div>
<input type="text" ref="text" />
<button onClick={this._handleClick}>Update</button>
</div>
);
}

Kendo knockout dropdownlist change Event not firing

<input data-bind="kendoDropDownList: { data:$root.brands,
value: BrandID,
dataTextField: 'Name',
dataValueField: 'BrandID'},
event: { change: $root.saveItem }" />
Does anyone know why wouldn't the change event fire if this is inside a kendo window??
I am using knockout-kendo.js.
For Change Event Firing
<input data-bind="kendoDropDownList:{ data :$root.brands,
value :BrandID,
dataTextField :'Name',
dataValueField :'BrandID',
change :$root.saveItem}"/>
Here is sample of change event firing