Autosuggest field and variants - javascript

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

React: Cannot assign to read only property '_status' of object '#<Object>'

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 });
})
);

Passing props inorder to use the string value

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
))}

React typscript - component with interface and additional props

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>
);
}

Restructure repetitive component to get rendered within a map function

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.

React-admin Array input with array of strings/numbers

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

Categories