How to configure Material-UI Autocomplete with secondaryText on dynamic data - reactjs

I'm facing a issue and I feels like lacking documentation around this.
I'm build a site where I get an AutoComplete component to search for data in the database, and it's working fine, it gets the data, I've build validation working on this, everything goes ok.
If I use only one Text to render on the MenuItem it works fine, like display a name property I've got from database, but if I try to display something like Name as a primaryText and Size as a SecondaryText it simply doesn't render the autocomplete menuItem results, even being filled correctly.
For the record I'm trying to achieve something like this: https://cloud.githubusercontent.com/assets/9424409/17258323/33764c38-557b-11e6-808c-ac22287703d0.gif
But I can only make component work with something like this: https://cloud.githubusercontent.com/assets/9424409/17258376/66015990-557b-11e6-8c12-9016da6e1f2e.gif
Here is the code as it works and render my data, using only textKey:
this.dataSourceConfig = {text: 'textKey', value: 'valueKey', validationKey:'validationKey'};
this.state = {
dataSourceDrug:[{textKey: 'Text data goes here', valueKey: "", validationKey:'validation value goes here'}]}
render(){
return(
<AutoComplete
onNewRequest={this.onDrugNewRequest}
onUpdateInput={this.handleDrugUpdateInput}
searchText={this.state.valueDrug}
dataSource={this.state.dataSourceDrug}
dataSourceConfig={this.dataSourceConfig}
/>
)
}
So how can I configure this to work rendering primary and secondary text?
I've checked docs and even issues on git but it doesn't says much to me:
http://www.material-ui.com/#/components/auto-complete
https://github.com/callemall/material-ui/issues/4852
https://github.com/callemall/material-ui/blob/master/docs/src/app/components/pages/components/AutoComplete/ExampleDataSources.js

Ok, I found the answer thanks to the light #awzx answer brought to me.
I was working with dataSourceConfig and dataSource, and to work woth primary and secondary text, it does NOT work with dataSourceConfig, so I removed the attribute from my component
dataSourceConfig={this.dataSourceConfig}
And in my for to place the data I've done this:
var updatedDataSource = [];
for (var i = 0; i < response.length; ++i)
{
var _name = response[i].name;
var _size = response[i].size;
var _val = <MenuItem primaryText={_name} secondaryText={_size}/>
updatedDataSource.push({text:response[i].name, value:(_val), valueKey:response[i].id, validationKey:'validation string here'});
}
this.setState({dataSourceDrug:updatedDataSource});

You've to configure the secondary text in your dataSource like below (second example in Material UI documentation) :
import React from 'react';
import AutoComplete from 'material-ui/AutoComplete';
import MenuItem from 'material-ui/MenuItem';
const dataSource1 = [
{
text: 'text-value1',
value: (
<MenuItem
primaryText="text-value1"
secondaryText="☺"
/>
),
},
{
text: 'text-value2',
value: (
<MenuItem
primaryText="text-value2"
secondaryText="☺"
/>
),
},
];

Related

React Native List Component that looks like iOS native lists

Does anybody know if there is any built-in React Native component that render lists like this?
It shouldn't be super hard to implement this from scratch
If you want the exactly same design there are probably three or so components that you need to write
Heres pseudo code
const settings = [
{
items : [{
icon : SomeIcon,
label : "Notifications",
action: () => ...navigate somewhere
},
...more items
]
}
]
...more code
return
<FlatList>
{settings.map(setting =>{
return <SettingSection>
{setting.items.map(item =>{
return <Item/>
})
}
</SettingSection>
})}
</FlatList>
You can try to do it by yourself but if you want exactly the same view, here i found a npm package for you. https://www.npmjs.com/package/react-native-settings-list . it is efficient and customizable.

React Tabulator - How to display table horizontally

I'm using react-tabulator for a component: http://tabulator.info/docs/4.0/frameworks
I have put the component on the page in my app but am struggling to do anything with the styling. Right now, the component just displays everything vertically and looks really bad:
I want to display this horizontally in something that looks like a normal tabular format. I would also like to change column width. I've found limited documentation examples. Someone did ask a similar question and in this StackOverflow thread: How to style react-tabulator table? but I've not been able to edit the styles.css stylesheet to do anything useful.
Here is my component code:
import React from 'react'
import { ReactTabulator } from 'react-tabulator'
import 'react-tabulator/lib/styles.css';
const TabularData = (props) => {
const dataArray = []
//gets just first streelights record
for (const [i, v] of props.streetlights.features.entries()) {
if (i < 1) {
dataArray.push(v.properties); // properties of each item is what contains the info about each streetlight
}
}
let columns = [
{title:"WORKLOCATI", field:"WORKLOCATI"},
{title:"WORKREQUES", field:"WORKREQUES"},
{title:"WORK_EFFEC", field:"WORK_EFFEC"},
{title:"WORK_REQUE", field:"WORK_REQUE"},
]
return (
<ReactTabulator
columns={columns}
layout={"fitData"}
data={dataArray}
/>
)
}
export default TabularData
The css in react-tabulator/lib/styles.css is just the most base-level css.
Try importing one of the pre-built themes:
import "react-tabulator/css/bootstrap/tabulator_bootstrap.min.css";
There are a whole bunch of them in the css folder, and you can use them as a basis for creating your own.
Minimum working example here.
To get the right styling you will also have to import tabulator.min.css in your module, which is the theme, according to here.
Your imports should look like this:
import { ReactTabulator } from 'react-tabulator'
import 'react-tabulator/lib/styles.css';
import 'react-tabulator/lib/css/tabulator.min.css'; // theme
Without it, it looks like the image you posted:
With it, it looks like this:
In the folder node_modules/react-tabulator/css you can find more themes.

React variable component name - all lower case?

I am trying to render icons that are set in the back end for each service on the page. The data comes from an api and includes the correct names for the icons. I am importing the needed icons from react-icons before hand...
I tried it this way:
//Services and icons
var serviceICON = this.state.services.map(service => {
let Icon = service.Icon
return <tr><td><Icon /></td><td> {service.serviceName}</td></tr>
});
This almost works - the only problem is that the icons are not rendered. Instead the html looks like this:
<fabed></fabed>
I don't understand why this happens. The api delivers the correct name (=> FaBed), so why is this rendering as all lower case?
Thanks a lot for your help in advance!
Edit:
The complete array for one of the services would look like this:
id: 2
serviceName: "Hotel"
trip: 6
Icon: "FaBed"
created_at: "2020-07-08T06:45:02.239Z"
updated_at: "2020-07-22T07:52:05.066Z"
I am mapping through each of these and try to output the code above. As you can see "Icon" comes with the correct spelling. So I don't understand why it is rendered in all lower case...
Basically what is happening here is Icon is just a string so the react framework treats it differently.
html tags vs react components
<Icon />
is converted to
React.createElement(Icon, {});
Choosing the Type at Runtime
You'll notice here the key is using a map to match a string value with an actual React Component. For your case you'll need to map service.Icon to the relevant (imported) Icon Component.
import FaBed from '...';
...
const icons = {
...
"FaBed": FaBed,
...
};
...
var serviceICON = this.state.services.map(service => {
let Icon = icons[service.Icon];
return <tr><td><Icon /></td><td> {service.serviceName}</td></tr>
});

React-Intl pass translation as string variable and not object

I'm in the process of adding react-intl to a payment app I'm building but hitting a snag. I apologize if this has been addressed somewhere. I scoured the issues and documentation and couldn't find a direct answer on this (probably just overlooking it).
Use Case: Once a payment is processed I'd like to give the user the option to tweet a translated message indicating they've donated.
Problem: Twitter uses an iframe to "share tweets", and requires a text field as a string variable. When I pass my translation I get [object Object] in the tweet instead of the translated text. This makes sense based on my understanding of the translation engine. But I cant seem to find a way to pass a string rather than a translation object.
what I get when I use {translate('example_tweet')}
const translationText = object
what I need
const translationText = 'this is the translated text'
Question
How do I get the translated text as a string variable rather than an object to be rendered on a page?
Code
button
import { Share } from 'react-twitter-widgets'
import translate from '../i18n/translate'
export default function TwitterButton () {
return (
<Share
url='https://www.sampleSite.org' options={{
text: {translate('example_tweet')},
size: 'large'
}}
/>
)
}
translate
import React from 'react'
import { FormattedMessage } from 'react-intl'
const translate = (id, value = {}) => <FormattedMessage id={id} values={{ ...value }} />
export default translate
I was able to solve it without messing with react-intl. I built a function that scrapes the text I need from the page itself. So it really doesnt matter what the language is. I was hoping to figure out how to snag the translations as variables, but this gets the job done.
function makeTweetableUrl (text, pageUrl) {
const tweetableText = 'https://twitter.com/intent/tweet?url=' + pageUrl + '&text=' + encodeURIComponent(text)
return tweetableText
}
function onClickToTweet (e) {
e.preventDefault()
window.open(
makeTweetableUrl(document.querySelector('#tweetText').innerText, pageUrl),
'twitterwindow',
'height=450, width=550, toolbar=0, location=0, menubar=0, directories=0, scrollbars=0'
)
}
function TwitterButton ({ text, onClick }) {
return (
<StyledButton onClick={onClick}>{text}</StyledButton>
)
}

React intl template string throws a missed id warning

I'm trying to inject some values into translated sentence via react-intl.
Following official documentation I was able to define some template message into my Localization file and it looks like that.
ratingMsgTemplate: {
id: "_ratingMsg",
defaultMessage: "{pointCount, plural, one {{point}} other {{points}}}"
},
this field passed directly inside localization object.
than I'm using a custom Plural component which is very simple
import * as React from "react";
import { injectIntl } from "react-intl";
import { inject, observer } from "mobx-react";
const i18nPluralNumber = (props: any) => {
const { locale, intl, msgId, ...msgParams } = props;
let finalMessage;
if (!(msgId in locale.messages)) {
console.warn("Id not found in i18n messages list: " + msgId);
finalMessage = msgId;
} else {
finalMessage = locale.messages[msgId];
}
return (
<span className="plural-number-intl">
{intl.formatMessage(finalMessage, { ...msgParams })}
</span>
);
};
export default inject("locale")(injectIntl(observer(i18nPluralNumber)));
here is the example of use
<I18nPluralNumber
msgId="ratingMsgTemplate"
pointCount={shopPoints}
point={formatMessage("point")}
points={formatMessage("points")}
/>
It works like a charm except this pesky thing.
In console I'm receiving this message:
I18nPluralNumber.tsx:19 [React Intl] Missing message: "_ratingMsg" for locale: "de", using default message as fallback.
and it's correct because there is no any _ratingMsg id inside my translate file. Actually I added this id only because it's necessary following react-intl docs and without this ID it isn't working at all
Could anyone give some tip/advice how to manage this stuff?
I'll be appreciated for any info.
If it helps anyone. I didn't found any normal solution except this crutch.
I've added the id with this key and duplicated the defaultMessage for each of it.
eg
ratingMsgTemplate: {
id: "_ratingMsg",
defaultMessage: "{pointCount, plural, one {{point}} other {{points}}}"
},
I just create the id - _ratingMsg with the defaultMessage value
_ratingMsg: "{pointCount, plural, one {{point}} other {{points}}}",
ratingMsgTemplate: {
id: "_ratingMsg",
defaultMessage: "{pointCount, plural, one {{point}} other {{points}}}"
},
now it doesn't throws warning about missed ID and it works like a template string.
Weird but I didn'd find any better solution

Resources