Actual Behaviour :
I'm loading a dynamic form in a FlatList and I'm supposed to add few rows with TextInputs based on a condition. For example, I have a checkbox. When I check the checkbox, I have to add a dropdown and two TextInputs and when I uncheck the checkbox, I have to remove these three. My issue is that when I check the checkbox and enter some value in the TextInputs and uncheck the checkbox, then the value in the last TextInput is getting assigned to another TextInput which is not related to these conditions.
Expected Behaviour :
The last TextInput value should not get assigned to another TextInput which is not related to checkbox conditions on unchecking the checkbox.
Here is my code for the TextInput :
_onChangeText(e, item, index) {
console.log("abc123 ", item);
let count = "false";
let note;
if (this.state.inputsValues.length === 0 && item.blocks.question !== undefined) {
if (item.blocks.question.prompt !== "Notes") {
note = {
note: e.nativeEvent.text.replace(/\n/g, ''),
id: item.blocks.question.prompt
};
} else {
note = {
note: e.nativeEvent.text.replace(/\n/g, ''),
id: item.blocks.block_pos
};
}
this.setState({ inputsValues: [...this.state.inputsValues, note] }, () => {
console.log("length === 0", this.state.inputsValues);
});
} else {
this.state.inputsValues.map((res, idx) => {
if (item.blocks.question !== undefined && res.id === item.blocks.question.prompt) {
res.note = e.nativeEvent.text.replace(/\n/g, '');
count = "true";
}
});
if (count === "false") {
if (item.blocks.question.prompt !== "Notes") {
note = {
note: e.nativeEvent.text.replace(/\n/g, ''),
id: item.blocks.question.prompt
};
} else {
note = {
note: e.nativeEvent.text.replace(/\n/g, ''),
id: item.blocks.block_pos
};
}
this.setState({ inputsValues: [...this.state.inputsValues, note] }, () => {
// console.log("gvrtgrtgt", this.state.inputsValues);
});
}
}
}
<NBTextField
itemStyles={[styles.itemStyles, { height: width / 6 }]}
value={inputsValues[index] !== undefined && inputsValues[index].note}
onEndEditing={e => this._onChangeText(e, item)}
onChangeText={this.getInputValue}
onSubmitEditing={() => Keyboard.dismiss()}
inputStyles={[styles.inputStyles, { height: width / 6 }]}
placeholder="Enter here"
/>
Environment :
react-native : 0.61.1
Screenshot :
Below code works for me in mycase
_onChangeText(e, item, index) {
if (item.blocks.block_type === 'question') {
this.state.mainData[index].answer = e.nativeEvent.text;
this.setState({
mainData: this.state.mainData,
});
}
}
<NBTextField
itemStyles={styles.itemStyles}
value={item.answer}
onEndEditing={e => this._onChangeText(e, item, index)}
onChangeText={e => this.getInputValue(e, item, index)}
onSubmitEditing={() => Keyboard.dismiss()}
inputStyles={styles.inputStyles}
/>
Related
I am trying to use multiselect feature of react-native-dropdown-picker which is working fine for selecting item, I can select multiple Items and can get its values too, but my problem is I am not able to show defaultValue on screen load.
I am fetching data from server and then trying to show on dropdown-picker
const AccountSelection = (props) => {
const [accountId, setAccount] = useState([])
const [accountList, setAccountList] = useState([])
const [defaultAccount, setDefaultAccount] = useState([])
useEffect(() => {
getAccounts()
}, [])
const getAccounts = () => {
axiosConfig.get('/accounts')
.then((response) => {
if (response.status == 200) {
const accountData = response.data.payload.data
const accountNames = accountData.map((item) => ({ label: item.name, value: item.id, selected: item.id == store.usersDefaultValues.account_id ? true : false }))
setAccountList(accountNames)
setDefaultAccount(accountNames.find(item => item.selected == true ? item.value : null))
}
}
})
.catch((error) => {
console.log("axios error", error);
})
}
return (
<View>
<DropDownPicker
placeholder="Select Account"
value={accountId}
items={accountList}
onChangeItem={(val) => setAccountId(val)}
defaultValue={defaultAccount}
multiple={true}
activeItemStyle={{ backgroundColor: '#F5CCF8' }}
></DropDownPicker>
</View>
)
}
On screen Load I am getting blank dropdown-picker, where it should show 1 Item Selected.
In DropDownPickerProps in react-native-dropdown-picker optional selected key is available but it is not working
items: {
label: any;
value: any;
icon?: () => JSX.Element;
hidden?: boolean;
disabled?: boolean;
selected?: boolean;
}[];
Please share if anyone have solution for this. Thank you.
The defaultValue attribute is not longer supported in react-native-dropdown-picker. If you want to select a default value, you simply need to set the 'value' variable to the default value's value.
You can read more in this issue: https://github.com/hossein-zare/react-native-dropdown-picker/issues/511#issuecomment-1049110163.
I developing application for android-tv I need set focus in TouchableOpacity.
How can i do this?
My example of focus detection on Android TV
enableTVEventHandler() {
this.evtHandler = new TVEventHandler();
this.evtHandler.enable(this, this.handleTVRemoteEvent);
}
disableTVEventHandler() {
if (this.evtHandler) {
this.evtHandler.disable();
delete this.evtHandler;
}
}
handleTVRemoteEvent = (cmp, event) => {
const { eventType, tag } = event;
if (tag !== this.nodeHandle) {
return;
}
if (eventType === "focus") {
this.setState({ isFocus: true });
if (this.props.focus !== undefined) {
this.props.focus();
}
}
if (eventType === "blur") {
this.setState({ isFocus: false });
}
}
After working for a while i found this solution:
<TouchableHighlight
onPress={this.props.onPress}
onFocus={() => {
this.setState({
currentStyle: 'blue',
})
}}
onBlur={() => {
this.setState({
currentStyle: 'white',
})
}}
>
{this.props.children}
</TouchableHighlight>
Is it possible to build a todo list with react native that can
add new TexInput with the return key
focus the new TextInput when created
remove TextInputs with the delete key if the TextInput is empty and focus another input
I have a basic list that can add items and focus them but not remove items.
https://snack.expo.io/#morenoh149/todo-list-textinput-spike
import * as React from 'react';
import { TextInput, View } from 'react-native';
export default class App extends React.Component {
currentTextInput = null
state = {
focusedItemId: 0,
items: [
{ id: 0, text: 'the first item' },
{ id: 1, text: 'the second item' },
],
};
addListItem = index => {
let { items } = this.state;
const prefix = items.slice(0, index + 1);
const suffix = items.slice(index + 1, items.length);
const newItem = { id: Date.now(), text: '' };
let result = prefix.concat([newItem]);
result = result.concat(suffix);
this.setState({
focusedItemId: newItem.id,
items: result,
});
};
focusTextInput() {
// focus the current input
this.currentTextInput.focus();
}
componentDidUpdate(_, pState) {
// if focused input id changed and the current text input was set
// call the focus function
if (
pState.focusedItemId !== this.state.focusedItemId
&& this.currentTextInput
) {
this.focusTextInput();
}
}
render() {
const { focusedItemId } = this.state;
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
{this.state.items.map((item, idx) => (
<TextInput
style={{ borderWidth: 1, borderColor: 'black' }}
value={item.text}
ref={item.id === focusedItemId
? c => this.currentTextInput = c
: null}
autoFocus={item.id === focusedItemId}
onChangeText={text => {
const newItems = this.state.items;
newItems[idx].text = text;
this.setState({
items: newItems,
});
}}
onSubmitEditing={event => this.addListItem(idx)}
/>
))}
</View>
);
}
}
To remove items you can add a callback to the onKeyPress and check if it was the Backspace (delete) key and if the text field was empty already. If so, you remove the item from the item list.
onKeyPress={({ nativeEvent: { key: keyValue } }) => {
if(keyValue === 'Backspace' && !items[idx].text) {
this.removeListItem(idx)
}
}}
In the removeListItem function you can remove the item at the index and update the selected id to the id previous in the list to focus this one.
removeListItem = index => {
const { items } = this.state;
const newItems = items.filter(item => item.id !== items[index].id)
this.setState({
focusedItemId: items[index - 1] ? items[index - 1].id : -1,
items: newItems.length ? newItems : [this.createNewListItem()],
});
}
Please find the full working demo here: https://snack.expo.io/#xiel/todo-list-textinput-spike
I'm trying to build a simple quiz. I would like to change the background of a button to green if it's correct and to red if it's incorrect onPress. My questions is how do I select only ONE of the buttons? Currently I can only get all of the buttons to turn colour.
export default class TestScreen extends React.Component {
constructor(props){
super(props);
this.qno = 0
this.score = 0
const jdata = jsonData.quiz.quiz1
arrnew = Object.keys(jdata).map( function(k) { return jdata[k] });
this.state = {
question : arrnew[this.qno].question,
options : arrnew[this.qno].options,
correctoption : arrnew[this.qno].correctoption,
countCheck : 0,
back_colour: 'gray',
answered: false,
}
}
change_colour(ans) {
if(this.state.answered == false){
if(ans == this.state.correctoption){
Alert.alert('Correct!');
this.setState({ back_colour: 'green'})
}
else {
Alert.alert('Wrong!');
this.setState({ back_colour: 'red'})
}
this.setState({ answered: true })
}
else {
// Do nothing
}
}
render() {
let _this = this
const currentOptions = this.state.options
const options = Object.keys(currentOptions).map( function(k) {
return ( <View key={k} style={{margin:10}}>
<Button color={_this.state.back_colour} onPress={() => _this.change_colour(k)} title={currentOptions[k]} />
</View>)
});
}
}
yeah its great and easy with react . You can use ids for this purpose.
example ..
validateUser = id => {
const newItems = items.map(item => {
if(item.id === id ) {
then check anwer here
and trun status true or false ..
}
})
}
items.map(item function() {
<Button color={item.status ? 'red' : 'black' } onPress={() =>
this.validateAnswer(item.id)}>
})
and your item object in your array should be like this ..
{
id: '0',
status: true/false
}
i think this will help .
I want to implement a drop system where if drop targets are nested you can cycle between them using the mouse scroll wheel (or have an automatic cycle happen after a certain amount of time) this will be particularly useful because many of the nested targets occupy the exact same areas on screen.
I'm presently thinking that I could use a callback passed down from the container that could be used by drop targets to register/de-register themselves when their hover function is called/when isOver prop changes but it's very coupled and I have to pass props into the DropTargets from the container, in the real world application there will be an unknown number of levels between container and drop target so I'd likely have to set up some kind of callback system, overall its not an ideal solution. Also I'm not sure how to ensure the correct order when cycling as the drop targets don't know how deeply nested they are (see code below for how I've implemented this). Is there a cleaner way to implement such a system?
#DragDropContext(HTML5Backend)
export default class Container extends Component {
constructor (props) {
super(props);
this.state = {
bins: []
};
this.status = {};
this._cycle = this.cycle.bind(this);
this._register = this.register.bind(this);
this._deregister = this.deregister.bind(this);
}
componentWillUnmount () {
if (this.timer) {
window.clearInterval(this.timer);
}
}
register (name) {
if (this.state.bins.findIndex(e => e === name) === -1) {
this.setState({
bins: this.state.bins.concat(name)
});
if (!this.timer) {
this.cycledBins = [];
this.timer = window.setInterval(this._cycle, 3000);
this._cycle();
}
}
}
deregister (name) {
if (this.state.bins.findIndex(e => e === name) !== -1) {
const bins = this.state.bins.filter((e) => e === name);
this.setState({
bins
});
if (!bins.length) {
window.clearInterval(this.timer);
this.timer = undefined;
}
}
}
cycle () {
this.status = {};
const bins = this.state.bins;
let activeBin = -1;
for (let i = 0; i < bins.length; i += 1) {
if (this.cycledBins.findIndex(bin => bin === bins[i]) === -1) {
activeBin = bins[i];
break;
}
}
if (activeBin === -1) {
activeBin = bins[0];
this.cycledBins = [];
}
this.cycledBins.push(activeBin);
this.activeBin = activeBin;
this.status[activeBin] = {
isActive: true,
isOnlyActive: bins.length === 1
}
this.forceUpdate();
}
render () {
return (
<div>
bins = {JSON.stringify(this.state.bins)}<br />
cycledBins = {JSON.stringify(this.cycledBins)}
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Dustbin name="Outer" register={this._register} deregister={this._deregister} status={this.status["Outer"]} >
<Dustbin name="Middle" register={this._register} deregister={this._deregister} status={this.status["Middle"]} >
<Dustbin name="Inner" register={this._register} deregister={this._deregister} status={this.status["Inner"]} />
</Dustbin>
</Dustbin>
</div>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Box name='Glass' />
<Box name='Banana' />
<Box name='Paper' />
</div>
</div>
);
}
}
const boxTarget = {
hover(props) {
props.register(props.name);
}
};
#DNDDropTarget('Box', boxTarget, (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()//,
//canDrop: monitor.canDrop()
}))
export default class Dustbin extends Component {
static propTypes = {
connectDropTarget: PropTypes.func.isRequired,
isOver: PropTypes.bool.isRequired//,
//canDrop: PropTypes.bool.isRequired
};
componentWIllMount () {
if (!this.props.isOver) {
this.props.deregister(this.props.name);
}
}
componentWillReceiveProps (nextProps) {
if (nextProps.isOver !== this.props.isOver && !nextProps.isOver) {
this.props.deregister(this.props.name);
}
}
render() {
const { canDrop, isOver, connectDropTarget, status } = this.props;
const isOnlyActive = status && status.isOnlyActive;
let isActive = status && status.isActive;
if (!isOver && isActive) {
isActive = false;
}
return connectDropTarget(
<div>
<DropTarget position={BEFORE} shown={isActive} />
{ isActive && !isOnlyActive ? '(' + this.props.name + ')' : undefined }
{ this.props.children ? this.props.children : (
<div style={style}>
{ isActive ?
'Release to drop' :
'Drag a box here'
}
</div>
) }
<DropTarget position={AFTER} shown={isActive} />
</div>
);
}
}