Search code examples
javascriptreactjstypescriptionic-frameworkcapacitor

Update value inside Capacitor Storage


Following situation:

I have an Ionic React app, which I use to take photos and then save the photos with its belonging info. I take all the existing data (at the point of taking the photo) and save it with the Capacitor Storage API Storage.set(). If I console.log() the storage with 2 photos, it looks like this:

[{"filepath":"file:///storage/emulated/0/Documents/1631810178839.jpeg","latitude":52.09244,"longitude":15.099145,"time":"9/16/2021, 4:35:49 PM","park":""},{"filepath":"file:///storage/emulated/0/Documents/1631796536758.jpeg","latitude":52.09244,"longitude":15.099145,"time":"9/16/2021, 2:48:24 PM","park":""}]

The photos are displayed in some kind of list. Where every object hast 2 columns. The left column shows the photo and the right column contains the additional info, like date, location and dropdown for park.

Where I am stuck:

I want to update value of park. park needs to be added/changed after saving the photo because its value should be choosen by the user via a select form and is therfore not defined at the point of saving the first time. But the photo needs to be saved after taking it, ohterwise it is not displayed in the app.

What I tried so far:

My Idea was to add an empty park to be able to update it later on. So I wanted to read the objects inside storage by Storage.get() and then comparing the the filepath of the object I am selecting a park with the filepaths of every object in the storage. After a match the empty park should be exchanged with the selected value. And afterwards Storage.set() with the array of the updated park value.

The code block:
class Park extends React.Component {
    constructor(props) {
      super(props);
      this.state = {park: ""};
  
      this.handleChange = this.handleChange.bind(this);
    }
  
    async handleChange(e) {
      this.setState({
        park: e.target.value
      });
      
      const {value} = await Storage.get({key: 'test' });
      var item = value.find(x => x.filepath == this.props.photoPath);

      if (item) {
        item.park = this.state.park;
      }

      Storage.set({key: 'test', value: value})
    }
  
    render() {
      return (
          <IonItem>
              <IonLabel position="stacked">Parks</IonLabel>
              <IonSelect name="park" value={this.state.park} placeholder="Choose park" onIonChange={this.handleChange}>
                  <IonSelectOption value="park1">Park1</IonSelectOption>
                  <IonSelectOption value="park2">Park2</IonSelectOption>
                  <IonSelectOption value="park3">Park3</IonSelectOption>
              </IonSelect>
          </IonItem>
      );
    }
  }

export default Park

FYI this.props.photoPat is passed from the parent and gives the filepath of the photo belonging to the select form.
But this is not properly running beacuse of the way I try to fetch data from storage. The find function is not working:

Property 'find' does not exist on type 'string'.ts(2339)


Solution

  • In the end it was pretty simple... find() is only working on arrays and Storage.get() gives back a string. So you have to parse() the string to get an array and afterwards you can successfuly use the find()-function

      class Park extends React.Component {
        
        async handleChange(target) {
    
          const {value} = await Storage.get({key: 'park' });
          let array = JSON.parse(value)
          let index = array.findIndex((array) => array.filepath === this.props.photoPath)
          if(index !== -1) {
            array[index] = {
                filepath: array[index].filepath,
                park: target
              }
          } else {
              console.log("error")
          }
          Storage.set({key: 'park', value: JSON.stringify(array)})
    
        }
      
        render() {
          return (
            <IonItem>
              <IonLabel position="stacked">Parks</IonLabel>
              <IonSelect name="park" value={this.props.park} placeholder="Bitte wählen" onIonChange={e => this.handleChange(e.detail.value)}>
                  <IonSelectOption value="park1">Park1</IonSelectOption>
                  <IonSelectOption value="park2">Park2</IonSelectOption>
                  <IonSelectOption value="park3">Park3</IonSelectOption>
              </IonSelect>
          </IonItem>
          );
        }
      }