How to exclude some options from React Select options - reactjs

I have around 50 options to be shown in the react select options. But I want to exclude some of the options with logic to already posted values.
The purpose is, that we have a form where we add values from the drop-down list. if one item is been added then that should not have to be shown in the dropdown list.
refactored code:
export default function App() {
const choices = [
{
value: 0,
label: "Container empty to shipper"
},
{
value: 1,
label: "Container pickup at shipper"
},
{
value: 2,
label: "Container arrival at first POL (Gate in)"
},
{
value: 3,
label: "Container loaded at first POL"
}
];
const postedList = [
"Container empty to shipper",
"Container pickup at shipper"
];
return (
<div className="App">
<h1>Select Box</h1>
<Select
isClearable={false}
// here the choices should be 2 eliminating the other 2 whose labels are matching to postedlist
options={choices}
defaultValue={choices[0]}
onChange={(choice) => console.log(choice.value)}
/>
</div>
);
}
Currently, it's rendering all 4 choices available but I want to return only 2 of them whose labels are not matching to postedlist
I also have created Codesandbox. If you want to see it there.

You can use Array.prototype.filter() and Array.prototype.includes() to filter out already posted items. Then use the filteredList as input to the Select component as below.
const filteredList = choices.filter(({ label }) =>
!postedList.includes(label)
);
return (
<div className="App">
<h1>Select Box</h1>
<Select
isClearable={false}
options={filteredList}
defaultValue={filteredList[0]}
onChange={(choice) => console.log(choice.value)}
/>
</div>
);

You can dynamically filter items and exclude them with the includes method.
<Select
options = {choices.filter((choice) => !postedList.includes(choice.label))}
...
/>

Related

Custom data attributes on Fluent UI dropdown

I have a requirement to add custom data attributes to the Fluent UI dropdown.
In javascript/html I could add them like this.
option data-passign="true" data-minpt="3" data-maxpt="6" value="7">Data Quality</option
Can someone help me achieve this in Fluent UI + React?
In FluentUI/React, it's much easier than that, no need for data- attributes, you can just add your custom data directly to the options list (and get it back in the event handlers, or as the selected value if you are using "controlled" scenario). Means, if you don't have a specific requirement to store additional item data in the HTML data attributes for "something else" (like ui-automation tool), then you could go with something like this (note the data property):
const YourComponent = (props) => {
const options = [
{ key: '7',
text: 'Data Quality',
data: { passign: true, minpt: 3, maxpt: 7 }
},
{ key: '42',
text: 'Weather Quality',
data: { passign: true, minpt: 100500, maxpt: 42 }
},
];
const onChange = (evt, item) => {
const itemData = item.data;
console.log(item.key, item.text, itemData);
};
return (
<Dropdown
label="Select something"
options={options}
defaultSelectedKey='7'
onChange={onChange}
/>
);
}
If you want a "controlled" control instead (this one is "uncontrolled"), check out the sample page for the Dropdown:
https://developer.microsoft.com/en-us/fluentui#/controls/web/dropdown

How would I iterate through array and display input boxes based on values?

I am new to react and I created I have a json like this:
const parent: [{name:will, kids['child1', 'child2']}
{name: 'kia' kids['child1']}
{name: 'jim', kids['child1', 'child2']}]
I am having trouble accessing the values with this json. I am trying to create a list with all the name values in of array so I can put it in a dropdown but I keep getting 'undefined' when i try to print the list in my console.log
Also when I click the name I want to create input boxes based of the length of the kids list of the name selected. So for instance if I click 'will' in the dropdown, two input boxes will form with 'child1' and 'child2' being in both input boxes. but if i click "kia", one input box will form that already has "child 1" in it. Any ideas? I have having a lot of trouble accessing the values.
this is my attempt so far:
import Dropdown from 'react-dropdown';
parent: [{name:will, kids['child1', 'child2']}
{name: 'kia' kids['child1']}
{name: 'jim', kids['child1, 'child2']}]
class AppEX extends React.Component {
constructor() {
super();
this.state = {
parentnamelist: []
parentname: null
}
}
render() {
namelist: []
this.state.parent.map((e, key) => {
namelist.push({value:e.name,label:e.name})
})
return (
<select name="select" onChange={this.namelist}>
{num.map(function(n) {
return (<option value={n} selected={this.state.selected === n}>{n}</option>);
})}
</select>
any ideas?
There are various problems here.
The parent list was not well formatted, is should look like this:
const parent = [
{ name: "will", kids: ["child1", "child2"] },
{ name: "kia", kids: ["child1"] },
{ name: "jim", kids: ["child1", "child2"] }
]
You are using map in your render method to push parent names into a new list called namelist but you have to use forEach. map transforms a list while forEach does something to each member.
const namelist = [];
this.state.parent.forEach(e => {
namelist.push({ value: e.name, label: e.name });
});
Now render return:
The onChange handler must be a function, since you want to track the selected parent, I guess you want to save it to your state:
handleParentChoice = e => {
e.persist();
this.setState({
parentname: e.target.value
});
};
Then
return (
<div>
<select name="select" onChange={this.handleParentChoice}>
{namelist.map(n => (
<option key={n.value} value={n.value}>{n.label}</option>
))}
</select>
<br />
{this.state.parentname && // Shows below stuff only if parentname is not null
this.state.parent
.find(p => p.name === this.state.parentname) // Find the parent based on the saved name, then map the kids into input tags
.kids.map(k => <input key={k} type="text" />)}
</div>
);
Also, when you map something, every child should have a key prop.
See the code working here

How to show option name in Ant Design Select when using setFieldsValue

I'm using a component from Ant Design and recently I added a button to select all options. The functionality is ok but in the field it shows the option keys or ids instead of showing the option names.
My question is, is there any way to show the option names when using setFieldsValue method in a multi-select component?
I have tried pushing an object with different properties (id, name, key, value, title, etc) in this part selecteds.push(kid.id); but none of those works.
My select funtion looks like this
selectAllKids = () => {
const { kids } = this.props;
let selecteds = [];
kids.map(kid => {
selecteds.push(kid.id);
});
this.props.form.setFieldsValue({
kids: selecteds
});
};
and my component:
{getFieldDecorator("kids", {
rules: [
{
required: true,
message: "Selecciona alumnos"
}
]
})(
<Select
size="large"
mode="multiple"
placeholder="Selecciona alumnos"
loading={kidsLoading}
>
{kids.map(kid => (
<Option key={kid.id}>{kid.name}</Option>
))}
</Select>
)}
My current result is:
My expected result is:
Thanks in advance!
You should map to name and not to id:
this.props.form.setFieldsValue({
kids: kids.map(({ name }) => name)
});

Dynamically change the column name based on inputs

I'm using Office UI fabric Detail List component (https://developer.microsoft.com/en-us/fabric#/controls/web/detailslist). Is it possible to change the Column header name based on inputs to the Detail List?
I found a way to change the Footer(https://developer.microsoft.com/en-us/fabric#/controls/web/detailslist/customfooter) but not Header since DetailsHeader doesn't have onRenderItemColumn props in it.
Any help?
The DetailsColumn component seems to always render the column's name property value: https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/office-ui-fabric-react/src/components/DetailsList/DetailsColumn.base.tsx#L122.
Thus, I think you have to dynamically regenerate a new array of IColumn definitions each time your "inputs" change inside the render call of your component.
MyComponent:
state = { replaceSpaces: false, spaceReplacementChar: '_' };
columns = [{ name: 'Column 1', minWidth: 100, ... }];
...
getColumns(state) {
return this.columns.map((column) => {
return {
...column,
name: state.replaceSpaces
? column.name.replace(/\s/g, state.spaceReplacementChar)
: column.name
};
});
}
...
render() {
return (
<DetailsList
columns={this.getColumns(this.state)}
{...this.othertableProps}
/>
);
}

Is there a way to add headings separating data in react-virtualized

I have a <List /> inside an <InfiniteLoader />, inside an <AutoSizer />, also <WindowScroller /> and <WindowScroller /> 😁 (wow, so much hocs there) but for simplicity, I think my question could fit the same with a simple <List /> Component.
I'm not sure if there is a way to render some kind of separator or heading like a title for the section (piece of data) rendered below.
Since each item have a prop that allow to group the data in chunks, and I am receiving this data ordered and grouped like:
[
{
item: 1,
name: 'Banana',
kind: 'fruits',
},
{
item: 2,
name: 'Apple',
kind: 'fruits',
},
{
item: 3,
name: 'Watermelon',
kind: 'fruits',
},
{
item: 4,
name: 'Dog',
kind: 'animals',
},
{
item: 5,
name: 'Cat',
kind: 'animals',
},
{
item: 6,
name: 'Horse',
kind: 'animals',
},
//...
]
the idea is to render something like:
<ul>
<li className="fullWidth">
<h3>Fruits</h3>
</li>
<li>Banana</li>
<li>Apple</li>
<li>Watermelon</li>
<li className="fullWidth">
<h3>Animals</h3>
</li>
<li>Dog</li>
<li>Cat</li>
<li>Horse</li>
</ul>
Making some calculation in rowRenderer method?
Or, since I am wrapping the <List /> in an <InfiniteLoader /> I could pass an argument when fire loadMoreRows, but anyway I think I have to do some calculation in rowRenderer, the responsible for the final render.
This is possible, although much easier if your data is pre-sorted so that groups aren't interleaved. You basically have 2 options:
Pre-flatten your data into an array of 2 types of items. One type is a header and the other type is a child. If you want headers to be a different size than regular rows you'll need to also provide a rowHeight getter function that's able to distinguish between a header item and a child and return a different value. Your rowRenderer will also need to do the same.
Compare the current datum's "kind" to the one that came before it and include a header with the rendered row if they are different. This approach also requires a custom rowHeight getter but does not require any data flattening so it may be easier/faster. The only downside is that your header and row item will be within the same div (or li) if you approach this way.
Here's an example of option 2: https://plnkr.co/edit/l22Ir7?p=preview
And here is the relevant code bits:
function includeHeader(index) {
return (
index === 0 ||
list[index].kind !== list[index - 1].kind
);
}
function rowHeight({ index }) {
return includeHeader(index)
? ROW_HEIGHT_WITH_HEADER
: ROW_HEIGHT;
}
function rowRenderer({ index, isScrolling, key, style }) {
const datum = list[index];
return (
<div
className='Row'
key={key}
style={style}
>
{includeHeader(index) && (
<h3>{...}</h3>
)}
<div>{...}</div>
</div>
);
}

Resources