How can I update a nested array with ionic4 storage - ionic4

Using
openSavedForm() {
this.storage.get('test').then((val) => {
this.auditResults = JSON.parse(val);
this.audit = this.auditResults
this.auditOne = this.auditResults.siteVehicle;
console.log('pull all', this.audit);
});
}
I can view my key value pair stored items in sqlite. Here is a photo of the of the console.log
Is it possible to only update only the siteVehicle Array with
async saveFormUpdates() {
this.newAudit =this.auditOne;
await this.storage.set( 'test', JSON.stringify(this.newAudit));
console.log ("storage", this.newAudit);
}
with out deleting all the other arrays?

My async saveFormUpdates() was wrong. Turns out just saving this.audit instead of this.auditOne did everything with no further input from me.
async saveFormUpdates() {
this.newAudit = this.audit;
await this.storage.set( 'test', JSON.stringify(this.newAudit));
console.log ("storage", this.newAudit);
}

Related

How exactly do I update FlatList's data using Apollo Client's fetchMore method?

My GraphQL backend returns data in the form:
{
data: {
feed: {
A: [...],
B: [...]
}
}
}
Where my frontend merges A and B using a sort on some field present within the data, and then uses React Native's FlatList to display them as a single array. I'm using Apollo client to query my backend like so:
const { fetchMore, loading, data, error } = useQuery(fetchQuery, {variables: fetchArgs});
if (loading) {...}
if (error) {...}
let A = [];
let B = [];
if (data!.feed.A) A = data!.feed.A
if (data!.feed.B) B = data!.feed.B
let feedData = sortedMerge(A,B);
return (
<FlatList
data={feedData}
...
onEndReached{
//update fetchArgs
fetchMore({
variables: fetchArgs,
updateQuery: // Not sure if I need to do anything here?
}).then(result => {
// Maybe this is where I update?
})
}
)
However, I can't seem to figure out how or where to get the new data, say A' and B' merged and concatenated with feedData so that my FlatList can update as efficiently as possible?
I guess I'm having trouble because I can't just directly update the list and need to do a little bit of preprocessing, but no matter where I update feedData, either in the then block after fetchMore or outside of it, the FlatList never seems to update.
Try putting your merge logic in a useMemo:
const { fetchMore, loading, data, error } = useQuery(fetchQuery, {variables: fetchArgs});
const feedData = useMemo(() => {
if (data) {
const { A, B } = data.feed;
return sortedMerge(A,B);
} else return [];
},[data]);
if (loading) {...}
if (error) {...}
return (
<FlatList
data={feedData}
...
onEndReached = {() => fetchMore({ variables: fetchArgs })}
/>
)
Executing fetchMore should cause data to be updated which will trigger the useMemo and update your feedData variable.
However you'll still need to merge the paginated results into the client-side cache.

AsyncStorage saving multiple items

I want to store multiple phone numbers with name. I am using AsyncStorage.
storeData = async (value) => {
try {
var number = [['name', this.state.name], ['number', this.state.number]];
await AsyncStorage.setItem('#following', JSON.stringify(number));
} catch (e) {
}
};
Everything works fine, it is saving the data. But how about if i want to add one more number to my existing data? When i try it now, it overwrites the existing data.
/* In Order to update followers List need to perform these steps
1. Get the followers array from AsyncStorage.
2. Push the new followers to the array.
3. Update the followers array in AsyncStorage.
*/
async addNewFollower(name, number) {
let existingFollowers = await this.getExistingFollowers();
const updatedFollowers= [...existingFollowers, [name, number]]
console.log("Updated followers", updatedFollowers);
await AsyncStorage.setItem(
"#following",
JSON.stringify(updatedFollowers)
);
}
async getExistingFollowers() {
let followers = await AsyncStorage.getItem("#following");
console.log("followers", followers);
return followers ? JSON.parse(followers) : [];
}

How to render text only after a Promise has been resolved in React Native?

I am trying to dynamically translate some text to be displayed when a user clicks on the translate button, but I can't get it to save my values outside of the Promise. I haven't worked much with Promises and every example only shows console.log, rather than saving values outside of the Promise. I don't really understand how they work. Here is (most of) the code I am trying to fix:
constructor(props) {
super(props);
this.state = {
dynamicTranslate: this.props.dynamicTranslate,
};
}
// I've tried this method as both sync and async (with await) but neither work
googleTranslate = (key) => {
const translator = TranslatorFactory.createTranslator();
// translate returns a Promise
return translator.translate(key, i18n.locale)
.then((response) => {return response});
}
renderText() {
// getting some values....
// this loops through all the feedback information
for (var i = 0; i < components_feedback.length; i++) {
let label = (some string);
let value = (some string);
// to do: call google translate call here if Boolean(this.state.dynamicTranslate)
if (Boolean(this.state.dynamicTranslate)) {
// I am ultimately trying to save the translation string from googleTranslate()
// in label/value so I can push it into feedbacks
label = this.googleTranslate(label);
value = this.googleTranslate(value);
}
feedbacks.push({label: label, value: value, type: comp.type})
}
return (
// some stuff
feedbacks.map((feedback, index)) => {
// some stuff
<Text>{feedback.label}</Text>
<Text>{feedback.value}</Text>
// some other stuff
});
);
}
render() {
return (
<View>{this.renderText()}</View>
);
}
One of the issues I'm running into is that label/value is a Promise if translation is on. If I try to make renderText() an async method, it is also turned into a Promise which render() can't handle. No idea where to go from here.
Solved this issue. Solution is to put the loop in an async function that (ideally) gets called on construction. This loop was edited to await the returns and push to local arrays of labels and values then saves those in state. You can compare the length of those arrays to the expected length (compare length of last array being used to be positive that it has finished) and that is how you can know if the Promises have returned. Paraphrased code:
constructor(props) {
this.state = {
translatedLabels = []
translatedValues = []
}
this.asyncFunction()
}
asyncFunction = () => {
labels = []
for loop
label = await promise
labels.push(label)
//same for values
end for
this.setState({translatedLabels: labels})
}
//later
renderText() {
if (this.state.translatedLabels.length === whatever) {
// do your stuff as you know the async function has finished
}
}
render() {
return (
{this.renderText()}
);
}

Update entire item in array - redux

I am trying to update a single object in an array of objects with a redux dispatch, I have tried answers to similar questions however I cannot seem to get it working. What I want to do, is when the action comes in, it should look for an item in the array with the same date as the action.options.date it should then replace that item in the array with the new item actions.options.data[0] which is the whole item object.
const initialState = {
isFetching: false,
monthArray: [],
searchOptions: {
currentMonth: moment().format('YYYY-MM'),
leeway: 1
},
availabilityOptions: {
Early: -1,
Late: -1,
Day: -1,
Twilight: -1,
Night: -1
}
};
case UPDATE_DAY_IN_MONTH_ARRAY:
return Object.assign({}, state, {
monthArray: state.monthArray.map(item => {
if (formatDate(item.date) === formatDate(action.options.date)) {
return action.options.data[0];
}
return item;
})
});
Action code: (Reason for data: data[0] is because an array of objects from mysql is returned)
export const updateDayInMonthArray = (date, data) => {
return {
type: UPDATE_DAY_IN_MONTH_ARRAY,
options: {
date,
data: data[0]
}
}
}
Dispatching the action
const updateDayInMonthArrayHandler = (date, data) => {
dispatch(updateDayInMonthArray(date, data));
}
Figured it out, and thank you guys for help. Wasn't React or Redux issue, was actually an issue with the node server returning data before checking what was updated.

Vue.js Vuex - Delete in Database not reflected in view

I have a number of companies in the Vuex Store. Each company object has several objects within it ... to simplify for my question, imagine
company{ id: 1, approval_notes: [{id: 1}, {id: 2}, {id: 3}], fins:
{total_rev: 10000} }
I want to remove the approval_note with id of 2 from the company with the id of 1.
In the view, I have
deleteNote(obj) {
if(confirm('Are you sure you want to delete this note?')) {
let path = '/api/approval_notes/' + obj.id;
axios.delete(path)
.then(function(rsp) {
this.$store.dispatch('delete_approval_note', obj);
}.bind(this))
.catch(function (err) {
console.log('AXIOS ERR', err);
}.bind(this));
}
}
The action is
export const delete_approval_note = ({commit}, payload) => {
commit('DELETE_APPROVAL_NOTE', payload);
};
And the mutation is
export const DELETE_APPROVAL_NOTE = (state, payload) => {
_.each(state.companies, function(co) {
if(co.id = payload.company_id) {
let notes = co.approval_notes;
notes.splice(notes.indexOf(payload), 1);
}
});
};
The note is deleted from the database but the view does not update without a page refresh.
This type of thing I will be doing a bunch so it's important to me to understand this process since I obviously don't get it right now.
Any help is appreciated.
Instead of IndexOf, using
notes.findIndex(obj => obj.id == payload.id)
It can get tricky when using IndexOf with complex object, I mostly rely on indexOf if dealing with simple values (integers, strings, booleans)