antd design select placeholder issues - javascript

I am using antd design in my React app.
Here's a code snippet where I am facing the issues :
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = "{this.state.company}"
name = "company"
onSelect = "{this.handleCompanyChange}"
>
Now it shows the correct value selected if this.state.company is not null. But if this.state.company is empty or null, placeholder doesn't shows up.
How can I solve this issue so that the placeholder appears if value is null?

set this.state.company to be undefined instead of null.

you should update as below:
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = {this.state.company || undefined} ---- update this line
name = "company"
onSelect = "{this.handleCompanyChange}"
>

It should be set to undefined instead of null or "" empty string.
this.props.form.setFieldsValue({
myFieldName: undefined
})

I have faced the the same issue, heres the solution:
Code snippet for ant design select
<Select key="1" value={this.getStateValue()} showSearch allowClear placeholder='Select Weight' onChange={onWeightChange}>
{options}
</Select>
where getStateValue will be this:
getStateValue = () => {
const { value } = this.state;
if (value) {
return value;
}
}

I changed from:
const [value, updateValue] = useState("");
To:
const [value, updateValue] = useState(undefined);
And it worked!

If you are using Form.create() of the Antd then there is another cool way to set/get the value of the form. Note that in this method the components (Select and others) have to be inside a <Form> element. Also the enclosing class should be passed in Form.create() object as props, as shown below:
export default connect(mapStateToProps, mapDispatchToProps)(Form.create()(YourClassName));
This way we have this.props.form available in the props. This will have an important function named getFieldDecorator, as shown below:
const { getFieldDecorator } = this.props.form;
Every Input component must be wrapped inside a , see below:
<FormItem>
{ getFieldDecorator('prefix', {
initialValue: '86',
})(
<Select style={{ width: 70 }}>
<Option value="86">+86</Option>
<Option value="87">+87</Option>
</Select>
);}
</FormItem>
As you can see above, this is more easier way to set initial value to the form elements.
Note that at times when you need to set values of the form elements in functions programatically then you can use setFieldsValue, setFields etc.
Before using getFieldsValue getFieldValue setFieldsValue and so on, please make sure that corresponding field had been registered with getFieldDecorator.
Please refer https://ant.design/components/form/?locale=en-US#Form-fields for more information on coordinated controls.
Example:
componentDidMount() {
if (someCheckHere){
this.props.form.setFieldsValue({
company: userData.companyName
})
}
}

Check the image posted, you need to target the name and try to set it to null if its an empty string, this should work.

Related

React select - change the way selected values are shown

I am using react select control in my ReactJs based application. I am using this as a multi-select control. But once the user selects more than 1 value, instead of showing all the selected values, I want to show the first selected value + N. So if two values are selected, I want to say 'XYZ' + 1. If only one value is selected I will say 'XYZ'. here is a working example
You need to override ValueContainer like below. working sandbox
const ValueContainer = props => {
let length = props.getValue().length;
return (
<components.ValueContainer {...props}>
{length > 1 ? (
<>
{props.children[0][0]}
{!props.selectProps.menuIsOpen && `${length - 1} Items`}
{React.cloneElement(props.children[1])}
</>
) : (
<>{props.children}</>
)}
</components.ValueContainer>
);
};
In Select you need to override
<Select
components={{ValueContainer}}
hideSelectedOptions={false}
...
/>

event.target.value - how to get the key value?

There was a need to add a drop-down list with a choice of accounts. The chosen value is processed through "event.target.value". This handler takes the value visible to the user, but I only need the 'key' value of the selected record where the stored "account.Id". I've tried get access to key, but it doesn't seem to work.
First experience with JS, so apologize in advance if the question is incorrect or elementary.
Page:
<select class="slds-select" name = "accountSelect" onchange={changeHandler2} >
<template for:each={allAccounts.data} for:item="account">
<option key={account.Id} value={account.Id}>{account.Name}</option>
</template>
</select>
Handler:
changeHandler(event) {
if (field === 'accountSelect') {
this.accountId = event.target.options[event.target.selectedIndex].getAttribute('key');
}
}
Did you tried to use the data to get it :
changeHandler(event) {
if (field === 'accountSelect') {
this.accountId = allAccounts.data.find(item => item.Id === event.target.value);
}
}

React Warning: flattenChildren(...): Encountered two children with the same key

Could someone please explain how to fix this error
Warning: flattenChildren(...): Encountered two children with the same
key
I have replicated my code below, but for some reason CodePen is not showing the error.
var FilterOptions = React.createClass({
changeOption: function(type, e) {
var val = e.target.value;
this.props.changeOption(val, type);
},
render: function() {
return (
<div className="filter-options">
<div className="filter-option">
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions.map(function(option) {
return (<option key={option} value={option}>{option}</option>)
})}
</select>
</div>
</div>
);
}
});
Codepen
As a secondary question, I am pretty sure my reset is supposed to reset the values of the select boxes but this is also not working and just resetting the rendered results - not sure if this is related to the first problem?
Any help much appreciated
It is not a good idea to use the index as the key. A key is the only thing React uses to identify DOM elements. What happens if you push an item to the list or remove something in the middle? If the key is same as before React assumes that the DOM element represents the same component as before. But that is no longer true. From: https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
It is much better to use a unique string from each item you are mapping over as the key. Something like <option key={value.id}> or if a key does not exist, create a unique identifier by doing something like <option key={value.name + value.description}>.
Adding the index as value fixed this. Thanks #azium for your sugegstion.
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions.map(function(option, value) {
return (<option key={value} value={option}>{option}</option>)
})}
</select>
I'm a big fan of using key by combining index with some constant value rather than using key={value.name + value.description}:
key={'some-constant-value'+index}
This is because I can pass the key knowingly which compoent is it for. For eg. <ComponentA key={'compoent-a-'+i} />. Also, I follow this approach is because simple html convention matches like we give id="my-some-of-the-id" or something.
So, even if you want to use name and description as the key, you may use like this rather:
key={'some-constant-'+value.name+'-'+value.description}
This is just an opinion. Though, I follow html convention when writing props value.
actually you need to specify to each children a unique key,so for that you need to create another key,for example if you are getting data from the database so for that create a new column for example (id) and then add value of that column to your div or what matter you are looping on as a key
var FilterOptions = React.createClass({
changeOption: function(type, e) {
var val = e.target.value;
this.props.changeOption(val, type);
},
render: function() {
return (
<div className="filter-options">
<div className="filter-option">
<select id="product" name="Product" value={this.props.product} onChange={this.changeOption.bind(this, 'product')}>
<option value=''>Product</option>
{this.props.productOptions && this.props.productOptions.map(function(option) {
return (<option key={option.id} value={option}>{option}</option>)
})}
</select>
</div>
</div>
);
}
});
i hope this help anyone in the future.

Change country of intlTelInput from another select list

I want to change the country selected in the intl-Tel-Input based on another select list. e.g. if Malaysia is selected in the country select list, the intl-Tel-Input should be changed to malaysia and should display its flag and code. similary if the country is changed to United States, the intl-Tel-Input should change accordingly.
Any help is appreciated.
Regards.
I would simply create js object "kind of json format" containing all the country code with there specific names, and dynamically try to alter the input placeholder once the country selected matches using javascript
if you are using React, here is the solution
constructor(){
super()
this.state = {
updated:true
}
}
To keep tracking if country is being changed.
componentWillReceiveProps(nextProps){
if(this.props.selectedCountry !== nextProps.selectedCountry){
this.setState({
updated:false
})
}
}
tells you its going to change now
componentDidUpdate(nextProps){
if(this.props.selectedCountry !== nextProps.selectedCountry){
this.setState({
updated:true
})
}
}
Changed now.
render(){
const { selectedCountry } = this.props;
var countryCode = 'us'
if(selectedCountry)
countryCode = selectedCountry.toLowerCase()
var field = <Field
className="ibm-fullwidth urx-country"
name="phone"
onInputChange={this.onInputChange}
component={this.renderPhoneInput}
defaultCountry={countryCode}
/>
return (
<span>
{this.state.updated &&
<span>{field}</span>
}
</span>
)
}
Basically its is re-rendering on country change.

React defaultValue for Select with Dynamically Generated Options

Use the defaultValue or value props on instead of setting selected on .
<select defaultValue="react">
<option value="react">React</option>
<option value="angular">Angular</option>
</select>
defaultValue would work with the above select tag. However, it does not seem to work with options generated by loop.
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Probably options not fully been set when defaultValue was declared?
I could do manual assigning in componentDidUpdate() and onChange event.
But my question is - Is there any cleaner(better) way to solve it?
Thanks.
This is old, but since answer #1 is related to a controlled Select and the question seems to be related to uncontrolled Select I think is worth to leave some lines for future readers:
The problem is that for uncontrolled components React needs to know what are the options before the first render, since from that moment the defaultValue won't override the current value of the Select. This means that if you render the Select before the options it won't know what to select.
You can solve the problem avoiding the render before the options are available:
const RenderConditionally = ({ options, selected }) => options.length > 0 ? (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
) : null;
Or without ternary if you desire:
const RenderConditionally = ({ options, selected }) => {
if (options.length === 0) {
return null;
}
return (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
);
};
For users running into this issue, you can get the desired functionality by using the value prop, instead of defaultValue, e.g.:
<select value={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Most probably you have something wrong with option_id and options arrays structure, or selectedOptionId variable. The way you build your select component is ok.
I've made a fiddle where this code works fine:
render: function() {
let option_id = [0, 1];
let options = [{name: 'a'}, {name: 'b'}];
let selectedOptionId = 1
return (
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
)
}
The best solution that I could find is to set key attribute the same as defaultValue so it will be a different element.
Aftermaths are not researched by me but I believe it should be okay.

Categories