Home > database >  Cannot make POST request (with data) with event trigger from outside component
Cannot make POST request (with data) with event trigger from outside component

Time:10-02

I am trying to use a click event from one component to trigger a method in another, and so far that works fine... except, the data that should be passed in my POST request doesn't get sent.

However, when I tested it by calling it in the component holding the API call method, it works fine.

Ideas?

Data being passed: Dashboard .vue -

  // Data to be loaded into s3 bucket
  this.s3Data.push(`Longitude: ${this.lng}, Latitude: ${this.lat}, Uncertainty Radius: ${this.uncertainty_radius} meters, Address: ${this.place_name}, Source: TEXT\n`)
  this.s3Data = JSON.parse(JSON.stringify(this.s3Data))

Method to be called: Dashboard.vue -

uploadToS3() {
  axios.post("http://localhost:8080/api/v1/targetLocation/uploadLocationsToS3Bucket", this.s3Data,
      {headers: {'Content-Type': 'application/json'}})
},

Method trigger event: Applayout.vue -

HTML

<v-btn @click="uploadDataToS3" outlined dark data-test="end-tracking-button">End Tracking</v-btn>

JS

uploadDataToS3() {
  Dashboard.methods.uploadToS3()
},

CodePudding user response:

The flow your are trying should work. I suspect there is some error in a part you have not posted. But this is not the usual way this is done.

The easy way

If there is a parent-child relation between the components (Dashboard -> Applayout) the usual way of communication is by emitting events in the child:

this.$emit('custom-event-name', { eventData:  'if needed' })

and handling the event in the parent:

<Dashboard @custom-event-name="uploadDataToS3" />

In this way you don't hard couple the components together, meaning that you can eventually insert other components between the parent and the child and you 'only' need to pass the event higher in the parent-child relation. As an added bonus, events are easier to inspect in the Vue dev tools extension.


The elegant way

But the more elegant way is to use Vuex and if the components are siblings and you need to pass data between them i strongly recommend using Vuex. It is a little bit harder at fist but it is much easier to maintain and you will thank yourself for choosing this path later on for uncoupling external API calls and making them easier to reuse on other components.

You would need a store looking something like this:

import Vuex from 'vuex'
import axios from 'axios'

const store = new Vuex.Store({
  state: {
    neededData: '', 
    resultData: 0
  },
  mutations: {
    setNeededData (state, payload) {
      state.neededData = `Longitude: ${payload.lng}, Latitude: ${payload.lat}, Uncertainty Radius: ${payload.uncertainty_radius} meters, Address: ${payload.place_name}, Source: TEXT\n`
    },
    setresultData (state, payload) {
      state.someData = payload
    }
  },
  actions: {
    async uploadDataToS3 (context, data) {
      const result = await axios.post(
        "http://localhost:8080/api/v1/targetLocation/uploadLocationsToS3Bucket",
        context.state.neededData,
        {headers: {'Content-Type': 'application/json'}}
      )
      context.commit('setResultData ', result.data)
    }
  }
})
export default store

Then update data from Dasboard to the store. You can do this on whatever element you interact with to obtain the data required in the API call.

<template>
  <input type="text" v-model="dashboardData.lat" />
  <input type="text" v-model="dashboardData.lng" />
  <button type="button" @click="setData" />
</template>
<script>
  export default {
    data () {
      return {
        dashboardData: {
          lat: '',
          lng: ''
        }
      }
    },
    methods: {
      setData () {
        this.$store.commit('setNeededData', this.dashboardData)
      }
    }
  }
</script>

Then in the Applayout component you would do this:

  <button @click="$store.dispatch('uploadDataToS3', neededData)" />

To come full circle you would get the result data in the Dashboard component like this:

<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['someData'])
  }
}
</script>

or just

this.$store.state.someData

But i like the previous version better because you can see at a glance what data you pull from a store by looking in the computed property.

CodePudding user response:

In my opinion, the best solution for this is to use mixins.

You will be able to call this and other methods from any component without the trouble of having to communicate between components with props or bus.

Further explanaiton:

If you wants to connect to an api, the function doesn't need to be on a component.

If it is a function called by different components.. the best solution, in my opinion, is to create it in a mixins file and call it from every component who needs it.

  • Related