Setting input values on call function - React Native - react-native

I am having trouble with saving the value of text inputs(which i am fetching from an API) to an array. Currently I can save the values but if I try to edit one text input value, it will save the new value and still keep the old one as well. I want to save only the latest value when the 'onChangeText' has ended.
I appreciate any suggestion!
Here is my code:
textfieldsObject = () => {
const obje = this.props.navigation.state.params.item;
var keyvalue_to_json = JSON.parse(obje.keyValues);
var textinputName = [];
var foundTextFields = [];
for (let i = 0; i < keyvalue_to_json.inputFields.length; i++) {
if (keyvalue_to_json.inputFields[i].type === 'textfield') {
foundTextFields.push(<TextInput onEndEditing={(e) => {
keyvalue_to_json.inputFields[i].inputValues = e.nativeEvent.text;
this.myInputFields.myTextFields.push(keyvalue_to_json.inputFields[i])
}}
>{keyvalue_to_json.inputFields[i].placeholderText}</TextInput>)
}
}
return (
<View>
{foundTextFields}
</View>
)
}

You can't make a push every time you edit your textinput. You will get an array of every edit you made, I think that's not what you want.
Maybe this:
this.myInputFields.myTextFields.[i]=keyvalue_to_json.inputFields[i]

Related

React Native map "Undefined" is not a function

I'm trying to get data from API
but. I'm getting this error Error Image.
Here is my code.
const [datas, setDatas] = useState(" ");
const res = async () => {
const response = await axios.get("http://hasanadiguzel.com.tr/api/kurgetir");
setDatas(response.data.TCMB_AnlikKurBilgileri);
};
datas.map((item) => {
return (
<KurCard
title={item.Isim}
alis={item.BanknoteBuying}
satis={item.BanknoteSelling}
/>
);
});
How can I solve this?
I'm trying to map() datas, because I need it
Hi #n00b,
The data that datas is initially being set to an empty string, which does not have a map method. First, you need an empty array instead of an empty stringuseState([]). Now you can map.
const [datas, setDatas] = useState([]);
const res = async () => {
const response = await axios.get('http://hasanadiguzel.com.tr/api/kurgetir');
setDatas(response.data.TCMB_AnlikKurBilgileri);
};
{datas.length > 0 &&
datas.map((item) => {
return <KurCard title={item.Isim} alis={item.BanknoteBuying} satis={item.BanknoteSelling}/>
})
}
make sure you data. it has a length greater than 0 before trying to map over it.
Assuming your API request is valid, you would need to actually return something from the component itself and not just the array:
return datas.map((item) => {return <KurCard title={item.Isim} alis={item.BanknoteBuying} satis={item.BanknoteSelling}/>})

Is there a way to wait until a function is finished in React Native?

I'm trying to get information (true/false) from AsyncStorage in a function and create a string which is importent to fetch data in the next step. My problem is, the function is not finished until the string is required.
I tried many solutions from the internet like async function and await getItem or .done() or .then(), but none worked out for me.
//_getFetchData()
AsyncStorage.getAllKeys().then((result) => { //get all stored Keys
valuelength = result.length;
if (valuelength !== 0) {
for (let i = 0; i < valuelength; i++) {
if (result[i].includes("not") == false) { //get Keys without not
AsyncStorage.getItem(result[i]).then((resultvalue) => {
if (resultvalue === 'true') {
if (this.state.firstValue) {
this.state.channels = this.state.channels + "channel_id" + result[i];
console.log("channel: " + this.state.channels);
}
else {
this.state.channels = this.state.channels + "channel" + result[i];
}
}
});
}
return this.state.channels;
_fetchData() {
var channel = this._getFetchData();
console.log("channel required: " + channel);
}
The current behaviour is that the console displays first "channel required: " than "channel: channel_id0".
Aspects in your question are unclear:
You don't say when this.state.firstValue is set, and how that relates to what you are trying to accomplish.
You have a for-loop where you could be setting the same value multiple times.
You mutate the state rather than set it. This is not good, see this SO question for more on that.
There are somethings we can do to make your code easier to understand. Below I will show a possible refactor. Explaining what I am doing at each step. I am using async/await because it can lead to much tidier and easier to read code, rather than using promises where you can get lost in callbacks.
Get all the keys from AsyncStorage
Make sure that there is a value for all the keys.
Filter the keys so that we only include the ones that do not contain the string 'not'.
Use a Promise.all, this part is important as it basically gets all the values for each of the keys that we just found and puts them into an array called items
Each object in the items array has a key and a value property.
We then filter the items so that only the ones with a item.value === 'true' remain.
We then filter the items so that only the ones with a item.value !== 'true' remain. (this may be optional it is really dependent on what you want to do)
What do we return? You need to add that part.
Here is the refactor:
_getFetchData = async () => {
let allKeys = await AsyncStorage.getAllKeys(); // 1
if (allKeys.length) { // 2
let filteredKeys = allKeys.filter(key => !key.includes('not')); // 3
let items = await Promise.all(filteredKeys.map(async key => { // 4
let value = await AsyncStorage.getItem(key);
return { key, value }; // 5
}))
let filteredTrueItems = items.filter(item => items.value === 'true'); // 6
let filteredFalseItems = items.filter(item => items.value !== 'true'); // 7
// now you have two arrays one with the items that have the true values
// and one with the items that have the false values
// at this points you can decide what to return as it is not
// that clear from your question
// return the value that your want // 8
} else {
// return your default value if there are no keys // 8
}
}
You would call this function as follows:
_fetchData = async () => {
let channel = await this._getFetchData();
console.log("channel required: " + channel);
}
Although the above will work, it will not currently return a value as you haven't made it clear which value you wish to return. I would suggest you build upon the code that I have written here and update it so that it returns the values that you want.
Further reading
For further reading I would suggest these awesome articles by Michael Chan that discuss state
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0
https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296
https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6
I would also suggest taking some time to read up about async/await and promises
https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
And finally this article and SO question on Promise.all are quite good
https://www.taniarascia.com/promise-all-with-async-await/
Using async/await with a forEach loop
Try this instead. Async functions and Promises can be tricky to get right and can be difficult to debug but you're on the right track.
async _getFetchData() {
let channels = "";
let results = await AsyncStorage.getAllKeys();
results.forEach((result) => {
if (result.includes("not") === false) {
let item = await AsyncStorage.getItem(result);
if (item === 'true') {
console.log(`channel: ${result}`)
channels = `channel_id ${result}`;
}
}
});
return channels;
}
_fetchData() {
this._getFetchData().then((channels) => {
console.log(`channel required: ${channel}`);
});
}
what if you wrap the _getFetchData() in a Promise? This would enable you to use
var channel = this._getFetchData().then(console.log("channel required: " + channel));
Otherwise the console.log won't wait for the execution of the _getFetchData().
This is what the console.log is telling you. it just logs the string. the variable is added after the async operation is done.
UPDATE
I would try this:
//_getFetchData()
AsyncStorage.getAllKeys().then((result) => { //get all stored Keys
valuelength = result.length;
if (valuelength !== 0) {
for (let i = 0; i < valuelength; i++) {
if (result[i].includes("not") == false) { //get Keys without not
AsyncStorage.getItem(result[i]).then((resultvalue) => {
if (resultvalue === 'true') {
if (this.state.firstValue) {
this.state.channels = this.state.channels + "channel_id" + result[i];
console.log("channel: " + this.state.channels);
}
else {
this.state.channels = this.state.channels + "channel" + result[i];
}
}
});
}
return new Promise((resolve, reject) => {
this.state.channels !=== undefined ? resolve(this.state.channels) : reject(Error('error '));
}
_fetchData() {
var channel = this._getFetchData().then(console.log("channel required: " + channel));
}
maybe you must change the this.state.channels !=== undefined to an expression that's matches the default value of this.state.channels.

How to get the text from a matched view using Detox?

I want to test a view that has a list and filtering functionality:
I want to check the text of the first row and save it
Filter using that text
Check again that the same element is rendered
Thing is, when I match and element using element(by.id('some-id')), how can I retrieve info from that element (if it is possible) like the text it contains?
I created the detox-getprops npm package incorporating the hack mentioned by Maxime Helen. It allows retrieving the text and some other (platform-dependent) properties of the element.
const { getText } = require('detox-getprops');
const text = await getText(element(by.id('heading')));
expect(text).toEqual('Step One');
I hope Detox #445 will be resolved soon after which this package can be deprecated.
Update: You can now fetch the text on iOS using the getAttributes method. The detox-getprops library is still needed for Android (tracked using Detox #2083).
Hacky/funny workaround elaborated from this comment:
const readVisibleText = async (testID) => {
try {
await expect(element(by.id(testID))).toHaveText('_unfoundable_text');
throw 'We never should get here unless target element has unfoundable text';
} catch (error) {
if (device.getPlatform() === 'ios') {
const start = `accessibilityLabel was "`;
const end = '" on ';
const errorMessage = error.message.toString();
const [, restMessage] = errorMessage.split(start);
const [label] = restMessage.split(end);
return label;
} else {
// Android to be tested
const start = 'Got:';
const end = '}"';
const errorMessage = error.message.toString();
const [, restMessage] = errorMessage.split(start);
const [label] = restMessage.split(end);
const value = label.split(',');
var combineText = value.find(i => i.includes('text=')).trim();
const [, elementText] = combineText.split('=');
return elementText;
}
}
};
This is currently not supported, the progress is being tracked in this issue.

How to send the index of a for loop into the promise of a function in a Vue Resource call?

I am looping through an object however in the asynchronous part the i variable is always five.
How can I maintain that value, or pass it into the function
getProductData: function() {
var vm = this;
for (var i = 0; i < vm.recommendationResponse['recommendedItems'].length; i++) {
var sku = vm.recommendationResponse['recommendedItems'][i]['items'][0]['id'];
vm.$http.get('http://127.0.0.1:8000/models/api/productimage/' + sku).then(response => {
// get body data
vm.recommendationResponse['recommendedItems'][i]['items'][0]['image_url'] = response.body['product_image_url'];
vm.recommendationResponse['recommendedItems'][i]['items'][0]['price'] = response.body['price'];
}, response => {
vm.recommendationResponse['recommendedItems'][i]['items'][0]['image_url'] = '';
vm.recommendationResponse['recommendedItems'][i]['items'][0]['price'] = '';
});
}
}
I I do something like this:
vm.$http.get('http://127.0.0.1:8000/models/api/productimage/' + sku).then((response, i) => ...
then i is undefined
Who do I keep the index of the loop or should I go about it a different way?
Always use let to initialize variables in for loop when dealing with async operations. Similar things goes to having for loops in intervals. By using let you make sure you always have a unique variable assigned to i.
for (let i = 0, recommendationlength = vm.recommendationResponse['recommendedItems'].length; i < recommendationlength; i++)
Little bonus, if you cache array length in the beginning you get a small performance boost :-)
You could use Array.prototype.forEach instead:
var vm = this;
vm.recommendataionResponse['recommendedItems'].forEach((item, i) => {
var sku = vm.recommendationResponse['recommendedItems'][i]['items'][0]['id'];
vm.$http.get('http://127.0.0.1:8000/models/api/productimage/' + sku).then(response => {
// get body data
vm.recommendationResponse['recommendedItems'][i]['items'][0]['image_url'] = response.body['product_image_url'];
vm.recommendationResponse['recommendedItems'][i]['items'][0]['price'] = response.body['price'];
}, response => {
vm.recommendationResponse['recommendedItems'][i]['items'][0]['image_url'] = '';
vm.recommendationResponse['recommendedItems'][i]['items'][0]['price'] = '';
});
})
This way, since there is a unique scope for each i value, each .then callback will be able to reference the correct value.

results.row[i] is undefined using react-native-db-models

Im new to React Native and Im using react-native-db-models. I have searched stackoverflow for fetching the data and it gave me this code below
DB.users.get_all((result) => {
let data = [];
for (let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
but result.rows[i] returns undefined. Any ideas how and why?
I tried my own solution but this time it gave me another problem. This is my code
DB.expense.get_all(function(result){
var data = [];
for (let i = 1; i <= result.totalrows; i++) {
let j = result.autoinc;
let id = j - i;
DB.expense.get_id(id, function(results){
data.push(result)
})
}
}
when I put console.log(data) after data.push(result) it works fine. But when I put console.log(data) outside DB.expense.get_id function, console.log(data) returns an empty array.
I really need your help guys