Data not getting shown in select box in material ui - javascript

I am working on a problem where on every click of icon ,we need to show one select box (taken from material ui) and this select has few options inside it .As we click the icon again ,we gain see the select box.The problem statement is something like this .
link to solution where i render a header instead of select box
What I see is that all the three options inside select box does not displayed ?
Here is the code .
includeblocks=()=>{
const {classes}=this.props;
let ClassData=[{
_id:101,title:'Lol1',
_id:102,title:'Lol2',
_id:103,title:'Lol3'
}];
let formtoinsert=<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Class</InputLabel>
<Select
value={this.state.classselected}
onChange={this.handleChange4}
inputProps={{
name: "classselected",
id: "age-simple"
}}
>
<MenuItem value="">
</MenuItem>
{ClassData.map(item => {
return(
<MenuItem value={item._id}>{item.title}</MenuItem>
);
})}
</Select>
</FormControl>;
table=[];
for (let i = 0; i < this.state.counter; i++) {
table.push(formtoinsert);
}
console.log("table",table);
return table;
}
I render this function in my render as jsx .What is the correct approach and where am I going wrong ?

I think the problem is that:
1) you have pretty strange ClassData array, it's just array of a single {_id: 103, title: "Lol3"} object. Should be something like this:
let ClassData = [
{_id:101,title:'Lol1'},
{_id:102,title:'Lol2'},
{_id:103,title:'Lol3'}
];
2) are you sure this.state.counter is greater than 0? :)
2.1) you'll get 'Each child in an array or iterator should have a unique "key"' error in console (because of non unique keys)
3) where is table defined?
should be
let table=[];
4) wrap your jsx in formtoinsert into '()' or even wrap as function with current counter step parameter (to fix 2.1 error)
Example code is here: https://jsfiddle.net/ybigus/fkxn3wvr/2/
Hope that helps

Related

onClick doesn't work on custom created element

Greetings
I have built a search and every time user types word it renders new checkboxes but new checkboxes don't work like they used to be none of the event listeners work on new checkboxes, when I'm clicking on checkboxes they just don't react, but in old ones, until search will render this they are working normally
//search in checkbox data
const checkOptions = (container, value, containerId) => {
for (let i = 0; i < props.unique[containerId].length; i++) {
let item = props.unique[containerId][i];
if (
props.unique[containerId][i] !== null &&
props.unique[containerId][i].includes(value)
) {
element = (
<label
onClick={(e) => {e.stopPropagation(); ifAnyChecked(e);}} key={i}>
<input onClick={(e) => {tableSearch(e);}} type="checkbox" value={item ? item : "empty"}/>
{item && item.length > 28 ? (
handleCheckbox(item)
) : (
<p>{item}</p>
)}
</label>
);
tempData += ReactDOMServer.renderToString(element);
}
}
container.innerHTML = tempData;
};
any idea what's happening?
Have you tried to use onChange event instead of onClick? As far as I know, input type checkbox doesn't have such an event like onClick.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
I used to get this problem when I was working with Vanilla JS whenever i render a new element then that element was not triggering my events. That was because they were generated on runtime so the event wasn't bound to that element. Now I think that thing is happening here as well. So I changed your code and put it inside a state now it is working. I hope I helped. Do let me know if this is not the solution that you were looking for but it solves your problem though
I put the html inside a state array then i mapped it out inside the newCheckBox div. I changed the input to controlled input with fieldValue state. Lastly i changed the new checkbox alert from onClick={alert("doesn't goes in")} to onClick={() => alert("I think its working now right?")}
Here is the complete code sandbox
https://codesandbox.io/s/polished-sea-vedvh?file=/src/App.js

Removing dropdown and text field from row removes incorrect field on State Change in ReactJS

I have a row which includes a React-Select Dropdown and an input field. I am trying to Remove a specific row by its index. I am passing the index in my handler function and want to remove both the fields from the row. The input field is getting removed correctly, but the dropdown value is not getting removed from the same row and it deletes the dropdown from the last index.
I am removing the row with the help of index in this handler
Removing the row by its index:
handleRemoveSocial(idx) {
let someArray = this.state.SocialData;
someArray.splice(idx, 1);
this.setState({ SocialData: someArray });
}
I am rendering the Select Dropdown and Textbox with the help of map method, mapping to the array in my state. Now, How can i map the Select dropdown value from the same row when i remove the textbox. I have included the Sandbox link in this post.
{this.state.SocialData.map((Social, idx) => (
<div className="form-group" key={idx}>
<label htmlFor={"socialprofile"} className="control-label">
Social profile
</label>
<div className="form-input-container select-social-link">
<Select
data-id={idx}
className="profile-module-select-container"
classNamePrefix="profile-module-select"
options={options}
onChange={(selected) => {
this.handleSocialNameChange(selected.value, idx);
}}
onMenuOpen={() => {
this.setState({
selectMenuOpen: true
});
}}
onMenuClose={() => {
this.setState({
selectMenuOpen: false
});
}}
components={{
IndicatorSeparator: () => null
}}
placeholder={"Select"}
isSearchable={false}
isClearable={false}
/>
</div>
<div className="form-input-container input-social-link">
<input
type="text"
id={`${SocialData[idx].socialname}-${idx}`}
className="social-form-control"
placeholder={`Social Url - ${Social.socialname}`}
value={SocialData[idx].name}
onChange={(e) =>
this.handleInputVlaueChange(e.target.value, idx)
}
/>
SANDBOX
This is where the problem is happening within handleSocialNameChange() Handler when change event is fired here.
onChange={(selected) => {
this.handleSocialNameChange(selected.value, idx);
}}
Using index as ids is overall not a good idea. Because they mess up things later and we have to add additional logic to the code as well.
We can use uuid() library or a trick new Date().getTime().toString() for our Ids efficiently.
Working code of CODESANDBOX Link:
https://codesandbox.io/s/reasontosmile-n6ww4?file=/src/App.js
Enjoy :)
You cannot set the index value as key. That will cause issues when adding and removing elements.
Also, don't use array.splice use array.filter. The splice will mutate the original state array.

Material UI select not showing label

I'm having a heck of a time with Material UI's "Select" - about 10 hours into trying to get one working the way I'd like. I'd really appreciate some help.
This question is related to a previous one: Select MenuItem doesn't show when JSX saved to state and I suspect that if the "why" were answered on that, I might get a better idea of what's going on.
What I'm trying to accomplish is having a Select that does the following normal things:
has all the UI goodies (shows the question in the select spot, then
moves the question smaller and out of the way after you select a
non-null selection)
upon selecting something, the label shows up (as one would expect in
a drop down) rather than a blank (as I have been experiencing - check
previous question)
no warnings in the console about 'value' being undefined
when I click away from the select after selecting something, I don't
want the question label to move back on top of the answer like this:
I want a 'none' option that returns the select back to it's "empty"
form (That is to say, the question label shows at normal size in the
select)
I can set a selection to be selected by default
These shouldn't be hard tasks, but I can't for the life of me get it. It' rather embarrassing.
Then, upon selecting something, I want to save that selection (along
with the other selection options) to state (so I can save it to
localStorage so the larger form doesn't 'reset' upon page refresh)
Either way, I've currently got this JSX - effectively a cut-and-paste from the material ui demos with a map for the MenuItems:
<FormControl className={classes.formControl}>
<InputLabel htmlFor={this.props.label}>{this.props.label}</InputLabel>
<Select
value={this.state.selectLabel}
onChange={this.handleSelectChange}
inputProps={{
name: 'selectLabel',
id: this.props.label,
}}
>
{this.props.value.map(valueLabelPair =>
<MenuItem
key={this.props.XMLvalue + "_" + valueLabelPair.label}
value={valueLabelPair.value}
>
{valueLabelPair.label}
</MenuItem>
)}
</Select>
</FormControl>
the handleSelectChange looks like this -- again, exactly the same as the material UI demo.
handleSelectChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
This kind of works except the console gives me the following error:
Failed prop type: The prop value is marked as required in
SelectInput, but its value is undefined.
and the selected option and question label go on top of each other after you click away, like so:
Further, if I try to add in this code (in the componentDidMount function) with the goal of being able to pass in the 'selected'/default option...
componentDidMount() {
for (var i = 0; i < this.props.value.length; i++) {
if(this.props.value[i].selected) {
// *works* console.log("selected found: " + this.props.value[i].label);
this.setState({selectLabel:this.props.value[i].label});
}
}
}
it does not update the give me a default answer and also gives me the following additional error in the console (in addition to all issues above):
Warning: A component is changing an uncontrolled input of type hidden
to be controlled. Input elements should not switch from uncontrolled
to controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component.
What am I missing?
Just define selectLabel into constructor:
constructor () {
super()
this.state = {
selectLabel:'',
}
}
I am unsure as to why the above solution did not work.
However, I rebuilt the Select to return "option" elements instead of "MenuItem" elements with the following function:
buildSelectOptions(optionsPairs) { // note, this references props and blank option could be split out for reuse
var JSX_return = [];
if (this.props.includeBlank && this.props.includeBlank === true) {
JSX_return.push(<option key="nada" value="" />);
}
for (var optionLabel in optionsPairs) {
JSX_return.push(<option key={optionLabel} value={optionsPairs[optionLabel]}>{optionLabel}</option>);
}
return JSX_return;
}
My render now looks like this:
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-native-simple">{this.props.label}</InputLabel>
<Select
native
value={this.state.value}
onChange={this.handleSelectChange('value')}
inputProps={{
name: this.props.label,
id: this.props.id,
}}
>
{this.buildSelectOptions(this.props.options)}
</Select>
<FormHelperText>{this.props.helperText}</FormHelperText>
</FormControl>
And the event handler looks like this:
handleSelectChange = name => event => { //FUTURE: combine the handlers (or split out question types to sub-components)
this.setState({ [name]: event.target.value },
() => this.props.stateChangeHandler(this)
);
};
the props passed to this object look like this:
{
"key": "test4",
"id": "test4",
"label": "Question Label 4",
"XMLValue": "XMLQ4",
"type": "DropDown",
"includeBlank": true,
"helperText": "PCodes FTW!",
"options": {
"No oe": "NA",
"My1": "One",
"My2": "Two",
"My3": "three"
},
"value": "One"
}
One of the key concepts for me was to learn that the value field on the Select element should be pointed at an item in this.state. Then, the onChange needs to pass the name of that state variable (which, confusingly, I have named 'value') to the eventHandler function.
The double arrow function header (curried function) of the handleSelectChange function still confuses me... (I don't understand how the 'event' property is getting there, given I'm calling this function with a single parameter)... but this works for now and I can try to refactor into syntax I am comfortable with (ie: function(a, b) { *do something* } ) at some future date. (yeah....)
Add class radio_label :
<FormControlLabel value="male" label="Male" control={<Radio />} className="radio_label"/>
Add css property :
.radio_label{
color:black
}

Dynamically adding input fields and keeping track of what was entered

I am wanting to dynamically create input field values for each category a user creates, the issue is how can I keep track of what the user enters into the input field. As I cannot create X amount of states as it is dynamic. Any tips would be much appreciated, my code is shown below:
var categories = newData.map((category,index) => {
console.log(category)
return (
<div className="content row marginCenter" key={category._id}>
<p>{category.category}</p>
<input type="text" /> //How do I keep track of what was entered for this input field??
<button onClick={() => this.addCategoryLink(category._id)}>Add
link</button>
</div>
)
})
I am wondering how to bind that to the button element
The React docs have a section related to the core of this question:
https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers
Assuming your state holds an array of "categories" objects- essentially, I think what you're looking for boils down to something like this in your map function:
{this.state.categories.map(category => (
<input
type="text"
onChange={event => this.handleCategoryChange(category, event)}
value={category.value}
/>
)}
And then a change handler that looks something like this:
handleCategoryChange = (category, event) => {
const value = event.currentTarget.value;
this.setState(state => {
// Create a copy of the categories array:
const categories = [...state.categories];
// Create a copy of the category, with an updated value:
categories[category.index] = {
...category,
value
};
// Update state with the new values:
return { categories };
});
};
Here's a simple demo:
https://codesandbox.io/s/woqpwvl777
i have other Way for doing this , Of course this way just working well in some situation , forExample when you have just 1 or 3 value
i think you wanna create Input , and there Input are dynamic , and you want define that , if user click in first Button , you get and use first TextInput (value)
in my way ( again i say this : this way just well in some situation ) , we Create data Json like this
[
{ id: n ,
category: 'some',
value: ''
}
in this structure Value key , in the mounting contain nothing or null value if the Value not defined before
for now i create one handler method and this method, called after onChange Event fired on
<input onChange={(e) => this.getValue(category.id,e)} />
that element , this means when user start fill input onChange event handle function and update your state
getValue(id,e) {
let thisId = id-1;
let vs = this.state.c;
vs[thisId].value = e.target.value;
this.setState({
c:vs
});
let v = this.state.c[thisId];
console.log(v);
}
i create Pen in this address -> https://codepen.io/hamidrezanikoonia/pen/vRyJRx?editors=1111
you can check console , for more details ( open console tab in codepen )
and for more details , i create two method , the first fired when input (text) filled ( onChange event ) , and the other fired when clicked on button ( click event )

react-selectize createFromSearch showing additional overlay

I am using react-selectize component for customizable dropdown which allows users to add new options.
<Dropdown
options={myOptions}
value={selectedValue}
onValueChange={value => {
this.valueUpdated(emptyStringToNull(value));
}}
createFromSearch={this.createFromSearch}
/>
My createFromSearch and onValueChange functions are as below;
createFromSearch: function(options, search){
if (search.length === 0 || (options.map(function(option){
return option.label;
})).indexOf(search) > -1)
return null;
else {
return {'label': search, 'value': search};
}
},
onValueChange: function(text) {
// update the value in state
},
Everything works fine other than this small UI issue. It shows duplicate options soon after I click .
When I click anywhere in the screen it removes this duplicate layover and showing properly. Can anyone please suggest is it styling issue or any other thing I need to do?
I able to fix this issue by trying several things. I was overriding onValueChange method of the component and passed only the value to the actual onValueChange method as below;
const onValueChangeInDropdown = props => value => {
if (value) {
props.onValueChange(value.value);
} else {
props.onValueChange(null);
}
};
This cause the above styling issue since component couldn't find out item.newOption attribute. So solution is when adding newly created item for the option list add it as item.newOption = 'true' and pass the whole item object to onValueChange method.

Categories

Resources