There is a problem, when i type anything in search field, suggest variants looks weird ( on the picture) because endings is cut. I want to cut down not a single word, but a sentence( first part of suggest ).
export const SkillAutoSuggestOption = (
props: React.HTMLAttributes<HTMLLIElement>,
option: any,
state: AutocompleteRenderOptionState,
getName: (option: any) => string
): React.ReactNode => {
const matches = match(getName(option), state.inputValue, { insideWords: true })
const parts = parse(getName(option), matches)
const path = () => {
if ('skillPathForAutoSuggest' in option) {
return option.skillPathForAutoSuggest
} else return getNodePath(option)
}
return (
<ListItem {...props} key={option.skill_id}>
{option.isCategory && <SCircleIcon />}
{parts.map((part, index) => (
<SLabel key={index} style={part.highlight ? { color: tannBlue } : {}}>
{part.text}
</SLabel>
))}
<SSkillPath>{path()}</SSkillPath>
</ListItem>
)
}
Can you add the getNodePath, parse and match functions source code/the source library if you use any? The problem is not related to rendering the list part but is related to how these functions work.
Related
I've been struggling over this error for a while now. It happens when I try to open react-bootstrap Modal with dynamically passed lazy component referrence and props to render it inside. It worked with classic import.
First row points to some react's internal lazy handler:
This is how modals are handled inside my ModalProvider:
const ModalList = React.memo(({ modalList, closeModalByIndex, confirmModalExitByIndex }) =>
modalList.map((modalDef, index) => {
const closeModal = () => closeModalByIndex(index);
const onConfirmExitChange = (confirmExit) => confirmModalExitByIndex(index, confirmExit);
const props = { ...modalDef, key: index, closeModal, onConfirmExitChange };
switch (modalDef.type) {
case TYPE_LIST:
return (
<React.Suspense fallback={fallback}>
<ListModal {...props} />
</React.Suspense>
);
case TYPE_FORM:
return (
<React.Suspense fallback={fallback}>
<FormModal {...props} />
</React.Suspense>
);
case TYPE_LIST_MULTI:
return (
<React.Suspense fallback={fallback}>
<ListMultiModal {...props} />
</React.Suspense>
);
default:
return null;
}
})
);
And this is how it is passed:
const openListModal = (Component, componentProps) => openModal(Component, componentProps, TYPE_LIST);
Anyone with deeper understanding what could possibly cause this?
Found out by trial by error. It was caused by immer's produce function which builds read-only deep copy of object.
setModalList(
produce(modalList, (modalList) => {
modalList.push({ Component, componentProps, type, show: true });
})
);
I have the following functional component and de-structuring the parameter props:
const MyTimes = ({ myWindowGroup, name, fieldArrayName }) => (
<FieldArray
name={name}
render={(arrayHelpers) => (
<React.Fragment>
{myWindowGroup.fieldArrayName.map((myTime, index) => (
and I am calling the component with the following props:
<MyTimes
myWindowGroup={myWindowGroup}
fieldArrayName={"myTimes"}
name={`myWindowGroups.${index}.myTimes`}
/>
My question is as I am new to React and that is, how can I pass/use the fieldArrayName={"myTimes"} string value of myTimes into the MyTime component above so that I can replace the value of fieldArrayName.map to be myTimes.map ?
I've tried it the way it is and not working.
Use dynamic keys. See Bracket Notation.
myWindowGroup[fieldArrayName].map(....
const myWindowGroup = {
myTimes: ['This is the value array you want'],
foo: [],
};
console.log(myWindowGroup['myTimes']);
console.log(myWindowGroup['foo']);
You can just do
{myWindowGroup[fieldArrayName].map((myTime, index) => (
As I understand your question correctly, you can achieve desired output by following
const MyTimes = ({ myWindowGroup, name, fieldArrayName }) => (
<FieldArray
name={name}
render={(arrayHelpers) => (
<React.Fragment>
{myWindowGroup[fieldArrayName].map((myTime, index) => (
// your logic here
))}
I'm totally new to using Typescript and having problems rendering a component but also passing in an onClick function. How can I pass in an onClick function to the CarItem Like this? I think it's trying to treat the onMenuClick as a proeprty of ICar but it isn't and shouldn't be. The onMenuClick shouldn't be part of the ICar interface. It is merely a function. I've put a simple example below.
interface ICar {
name: string,
colour: string,
manufacturer: string
}
const CarGrid : React.FC<ICarGridProps> = car => {
return (
<CarItem {...car} onMenuClick={onClick} />
)
}
const CarItem : React.FC<ICar> = (car, onMenuClick) => {
return (
<div onClick={() => onMenuClick(car.name)}>{car.name}</div>
);
}
Thanks all.
There are a few things wrong here:
I've corrected the return of CarGrid and type def and params of CarItem
interface ICar {
name: string,
colour: string,
manufacturer: string
}
const CarGrid : React.FC<ICarGridProps> = car => {
return (
<CarItem car={car} onMenuClick={onClick} />
)
}
const CarItem : React.FC<{car: ICar, onMenuClick: Function}> = ({car, onMenuClick}) => {
return (
<div onClick={() => onMenuClick(car.name)}>{car.name}</div>
);
}
Or if you want to spread the car object into CarItem, it should be refactored:
...
<CarItem {...car} onMenuClick={onClick} />
...
const CarItem : React.FC<ICar&{onMenuClick: Function}> = ({name, onMenuClick}) => {
return (
<div onClick={() => onMenuClick(name)}>{name}</div>
);
}
While I wrote my component as much DRY as I could, I wonder if there is a better way to render ConnectButton through a map function that takes [linkedIn, twitter, researchGate] as an array. I tried different things, but that's as good as I could get it. (I simplified the code a bit to the relevant. The original version is by a lot longer.)
const Component = () => {
const ConnectButton = ({ icon, title }) => (
<MenuItem>
<ListItemIcon className={classes.listItemIcon}>
<Icon className={classes.connectIcon} icon={icon} />
</ListItemIcon>
<ListItemText primary={title} />
</MenuItem>
);
const renderConnectMenu = () => {
if (!profileInfo) {
return;
}
const linkedIn = profileInfo.linkedIn;
const twitter = profileInfo.twitter;
const researchGate = profileInfo.researchGate;
return (
<div>
{linkedIn && <ConnectButton icon={faLinkedin} title="LinkedIn" />}
{twitter && <ConnectButton icon={faTwitter} title="Twitter" />}
{researchGate && (
<ConnectButton icon={faResearchgate} title="Research Gate" />
)}
</div>
);
};
render(
<>
[...]
{renderConnectMenu()}
[...]
</>
);
};
There are 3 properties that define the rendering of a button: a field from profileInfo, icon and title. So we will need an array of objects with these properties in order to render them with .map.
I am not sure what kind of date the profileInfo fields hold so I named the property as shouldRender based on its usage.
const renderConnectMenu = () => {
if (!profileInfo) {
return;
}
const buttons = [
{
shouldRender: profileInfo.linkedIn,
icon: faLinkedin,
title: 'LinkedIn',
},
{
shouldRender: profileInfo.twitter,
icon: faLinkedin,
title: 'Twitter',
},
{
shouldRender: profileInfo.researchGate,
icon: faLinkedin,
title: 'Research Gate',
},
];
return (
<div>
{buttons.map(
(button) =>
button.shouldRender && (
<ConnectButton
key={button.title}
icon={button.icon}
title={button.title}
/>
),
)}
</div>
);
};
It might look a bit weird when you have a few items to render. So I wouldn't recommend this approach if there are just 2-3 items unless there is a possibility of extending the list. It's okay to keep it as it is now.
https://marmelab.com/react-admin/Inputs.html#arrayinput
Examples cover cases where you have an array of objects:
backlinks: [
{
date: '2012-08-10T00:00:00.000Z',
url: 'http://example.com/foo/bar.html',
},
{
date: '2012-08-14T00:00:00.000Z',
url: 'https://blog.johndoe.com/2012/08/12/foobar.html',
}
]
is it possible to have it work with just an array of strings?
backlinks: ['a', 'b', 'c']
I was able to execute the inputs variant, as opposed to the fields variant, by simply not providing a source attribute for the inner TextField, and sourcing the array in the actual ArrayField. Then of course just use a SimpleFormIterator. Clearly React favors the use of keys, treating array types like maps, for the most part.
<ArrayInput source="my-source">
<SimpleFormIterator>
<TextInput />
</SimpleFormIterator>
</ArrayInput>
Here is my working code based on #fzaninotto's post in react-admin Issues:
import Chip from '#material-ui/core/Chip'
const TextArrayField = ({ record, source }) => {
const array = record[source]
if (typeof array === 'undefined' || array === null || array.length === 0) {
return <div/>
} else {
return (
<>
{array.map(item => <Chip label={item} key={item}/>)}
</>
)
}
}
TextArrayField.defaultProps = { addLabel: true }
Usage:
<TextArrayField source="tags">
<SingleFieldList>
<ChipField source="id" />
</SingleFieldList>
</TextArrayField>
Maybe you can create your own Field component which can able to take source and record as props.
function populateList(numbers) {
return numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
}
const SimpleArray = ({source, record = {}}) =>
<ul>
{
populateList(record[source])
}
</ul>;
SimpleArray.defaultProps = {
addLabel: true,
label: 'List'
};
SimpleArray.propTypes = {
label: PropTypes.string,
record: PropTypes.object,
source: PropTypes.string
};
export default SimpleArray;
And easily use it inside any form element like :
<SimpleShowLayout>
<TextField source="id"/>
<TextField label="Title" source="title" className={classes.name}/>
<TextField source="title"/>
<NumberField source="defaultItemCount"/>
<RichTextField source="description"/>
<NumberField source="priceInNumber"/>
<SimpleArray source="attributeArray" label="Product Attributes" />
</SimpleShowLayout>
My solution expands a bit on the answer from #kcrawford
In my case, I needed to output the array of URLs. Simplified version of the code
const MassMessageEdit: FC<any> = (props) => (
<Edit {...props}>
<SimpleForm {...props}>
...
<ArrayField source="onesignalUrls">
<URLs />
</ArrayField>
</CreateEditForm>
</Edit>
)
const URLs: React.FC<{ ids?: string[] }> = (props) => {
if (!props["ids"]) return null
return (
<ul>
{props["ids"].map((link, key) => (
<li key={key}>
<a href={JSON.parse(link) as string} rel="noopener noreferrer" target="_blank">
Notification {key + 1}
</a>
</li>
))}
</ul>
)
}
ArrayField passes the values array as ids, which can later be parsed and rendered