How to have two text inputs communicate with each other (React Native) - react-native

I am new to React Native, and currently have two text input boxes and I would like it that when I change one the value shown in the other also changes. But then you will be allowed to edit the second text input and this will in tune change the first one. And so on...
I have tried setting the placeholder as the value, then that will change as the first text input changes, but it only works until you edit the text box.
Essentially I cannot figure out a way to have a text input and output on top of each other.

state = { valueOne: '', valueTwo: '' }
changeValueOne = (valueOne) => {
this.setState({
valueOne,
valueTwo: `${valueOne}-foo`
})
}
changeValueTwo = (valueTwo) => {
this.setState({
valueOne: `${valueTwo}-bar`,
valueTwo
})
}
render() {
const { valueOne, valueTwo } = this.state
return (
<View>
<Input onChangeText={this.changeValueOne} value={valueOne} />
<Input onChangeText={this.changeValueTwo} value={valueTwo} />
</View>
)
}

Related

How to make a DetailsList header shows tooltip

How to configure detailsHeader properly to make it show tooltip for the header text?
In each column, I've added ariaLabel, name, key, fieldName and have tried the top answer in this post but does not work: How to render a column header with both text and a tooltip icon in Fabric DetailsList
I am using "#fluentui/react": "^8.11.1"
private renderFixedDetailsHeader: IRenderFunction<IDetailsHeaderProps> = (props, defaultRender) => {
if (!props) {
return null;
}
const onRenderColumnHeaderTooltip: IRenderFunction<IDetailsColumnRenderTooltipProps> =
(tooltipHostProps: any) => {
return (
<TooltipHost content={tooltipHostProps.column.name}>
{tooltipHostProps.column.name}
</TooltipHost>
);
}
return (
<Sticky stickyPosition={StickyPositionType.Header} isScrollSynced>
{defaultRender!({
...props,
onRenderColumnHeaderTooltip,
})}
</Sticky>
);
}
// render Detail Header
public render(): JSX.Element {
return (
<ShimmeredDetailsList
columns={this.state.columns}
items={this.state.items}
onRenderItemColumn={this.props.onRenderItemColumn}
enableShimmer={this.props.isLoading}
setKey={this.props.setKey}
key={this.props.setKey}
selectionMode={SelectionMode.none}
onShouldVirtualize={() => false}
onRenderRow={this.props.showBlueBackgroundGrid ? this._onRenderRow : undefined}
onRenderDetailsHeader={this.renderFixedDetailsHeader}
/>
);
}
// Render detail list.
The fluent UI provides us onRenderDetailHeader to create our own custom header. You can return the custom header with tooltip or your own styles also.

Auto Calculate Input Fields

Please could someone help answer this:
I have 2 NumberInput controls, one input and the other is disabled. I need to input number in the first input field, the disabled field to show this number/100. The two NumberInput will have source fields that will save to the current record in the simpleform.
How do I do this in react-admin
Thanks
Easiest way is to use the method described in the docs under section Linking two inputs
In essence: You can create your own input component where you can access the form values via the hook useFormState. Then just assign the desired value transformed the way you want e.g. divided by 100.
Edit
Found one more even cleaner way - using the final-form-calculate to create a decorator and pass it to the <FormWithRedirect /> component like so:
import createDecorator from 'final-form-calculate'
const calculator = createDecorator(
// Calculations:
{
field: 'number1', // when the value of foo changes...
updates: {
number2: (fooValue, allValues) => allValues["number1"] * 2
}
})
...
<FormWithRedirect
...
decorators={[calculator]}
/>
Check out this code sandbox
Using FormDataConsumer
<FormDataConsumer>
{({ formData }) => (
<NumberInput defaultValue={formData.my_first_input / 100} source="second_input"/>
)}
</FormDataConsumer>
Using the useFormState hook
import { useFormState } from 'react-final-form';
...
const { values: { my_first_input }} = useFormState({ subscription: { values: true } });
...
<NumberInput defaultValue={my_first_input / 100} source="second_input"/>
Source: https://marmelab.com/react-admin/Inputs.html#linking-two-inputs
Dynamic
You need to use the useForm hook of react-final-form to make your input dynamic:
import { useForm, useFormState } from 'react-final-form';
...
const {change} = useForm();
const { values: { my_first_input }} = useFormState({ subscription: { values: true } });
useEffect(() => {
change('my_second_input', my_first_input / 100);
}, [change, my_first_input]);
...
<NumberInput defaultValue={my_first_input / 100} source="second_input"/>
I got a shorter solution to this question:
All I did was to do the calculation within FormDataConsumer. Now, I am able to get the calculated value and it updates the correct record in the array.
Thanks
<FormDataConsumer>
{({
formData, // The whole form data
scopedFormData, // The data for this item of the ArrayInput
getSource, // A function to get the valid source inside an ArrayInput
...rest
}) => {
if (typeof scopedFormData !== 'undefined') {
scopedFormData.total = scopedFormData.quantity * scopedFormData.unitprice;
return (
<NumberInput disabled defaultValue={scopedFormData.total} label="Total" source={getSource('total')} />
)
} else {
return(
<NumberInput disabled label="Total" source={getSource('total')} />
)
}
}}

How to change text input value into zero after onChangeText?

I am new in react native, and I have question about text input and state.
Let say I make an app to buy nature materials, for instance, sands. I have a buy page and a trade component. buy page has a button for buy and go to the next step. And the trade component inside the buy page has text input to input how much users want to buy. The state is come from the parent (buy page) and I send it via props to it's child (trade component)
I have a text input to bid a price, let's called in inputContainer. And beside it, there's a read-only text-input of the sand's mass, let's called it outputContainer. For example, let say 1 kg of sands have a price of $10. So, when I type 100 (dollars) in inputContainer, then the onchangetext works for outputContainer and returns 10 kg.
The problem is when I delete the value inputContainer until nothing is left, the outputContainer returns NaN. What I want is after deleting all input, the inputContainer automatically returns 0 so the outputContainer also returns 0
buy page.js
state = {
inputTextValue: '',
outputTextValue: ''
}
onChangeValue = inputValue => {
const qty = ParseInt(inputValue) / 10
if (inputValue === '') {
this.setState({
inputTextValue: '0'
});
} else {
this.setState({
inputTextValue: inputValue.replace(/\B(?=(\d{3})+(?!\d))/g, '.')
outputTextValue: qty.toString()
});
}
}
render(){
return (
<View>
<Trade
onChange={this.onChangeValue}
inputText={this.state.inputTextValue}
outputText={this.state.outputTextValue}
/>
</View>
)
}
in trade.js
type Props = {
inputText?: String,
outputText?: String
}
class Trade extends PureComponent<Props> {
static defaultProps = {
inputText: '',
outputText: '',
onChange: () => {}
}
render(){
const { inputText, outputText, onChange } = this.props;
return(){
<View>
<TextInput
onChangeText={onChange}
value={inputText}
/>
<TextInput
onChangeText={onChange}
value={outputText}
editable={false}
/>
</View>
}
}
}
From code above what I got is I do return 0, but when I want to type a new input, the 0 is still in front of the text input.
Well, let me show you the flow when I use that code:
Type the input
input: 100 output: 10
Deleting input
input: 0 output: 0
Type again
input: 0100 output: (ignore this)
What I want in number 3 is => input: 100 when I type 100
How I can achieve that? Thanks
You can try this
this.setState({
inputTextValue: '0',
outputTextValue: '0'
});
You must have to put the values of Input and Output into state and initially set their values to '0'

How to handle multi input in react native generically?

I'd like to know why this code doesn't work :
<TextInput
style={style.inputLogin}
onChangeText={this.handleInputChange}
value={this.state.login}
/>
with the function :
handleInputChange = (event) => {
console.log(event.target.name);
this.setState({
[name]: value
});
console.log("name => ", [name]);
console.log("value => ", value);
}
I tried many things but i can't get the targeted form.
Should I make one function for each input ? seems to be stupid :/
event only contains the value of the form.
Sure I could do this :
<TextInput
style={style.inputLogin}
onChangeText={(value) => this.setState({value}))
value={this.state.login}
/>
But this is not what I am looking for. I would like something more generic that works for every input
Please help me ;)
According to doc
onChangeText Callback that is called when the text input's text
changes. Changed text is passed as a single string argument to the
callback handler.
So the value passed by onChangeText is a string, not an event.
In your handleInputChange you can treat text like
handleInputChange = (text) => {
console.log(text);
// ...
}
In order to handle multiple textInput with just a function, customize it like:
<TextInput
style={style.inputLogin}
onChangeText={(text) => this.handleInputChange(text, "Something to tell your function you're calling it from first textinput")}
value={this.state.login}
/>
And then
handleInputChange = (text, fromWhichTextInputAreYouCallingMe) => {
console.log(text);
this.setState({
login: text
});
}

Can I use multiple or nested elements in the Label of a Picker Item in React Native?

I'm using React Native with NativeBase and would like to make the labels of my Picker more complicated than just one plain string of text.
But is it even possible to pass elements as the label, say multiple child elements wrapped in a single top-level element?
Or do Pickers only support plain text as labels?
As requested by bennygenel, here's a version of what I've tried:
export default class ThingPicker extends React.Component {
render() {
const {
initialThing,
things,
onThingChanged,
} = this.props;
const orderedThings = things.sort();
return (
<Picker
selectedValue={initialThing}
onValueChange={onThingChanged}>
{buildThingItems(orderedThings)}
</Picker>
);
}
}
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = th === "BMD" ? (<Text key={th} label={"foo"} value={"bar"}}>Hello</Text>)
: (<Picker.Item key={th} label={th} value={th} />);
return it;
});
}
Yes! It is possible, it just might not look very "right" for React/JSX code. Just create the elements you need and assign them to the label field:
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = (<Picker.Item
key={th}
label={currency === "BMD" ? (<Text>Hello</Text>) : th}
value={th} />);
return it;
});
}