13

I am creating an alert component for a CRUD app using Vue.js. I want a message to be passed to another component once data has been saved. Currently I am trying to pass this data in $router.push like this this.$router.push({path: '/', query: {alert: 'Customer Added'}}) Then access this data in another component. However this is not working as expected, instead the data is passed into the url.

This is the component which saves the data, Add.vue

<template>
<div class="add container">
<Alert v-if="alert" v-bind:message="alert" />
<h1 class="page-header">Add Customer</h1>
<form v-on:submit="addCustomer">
    <div class="well">
        <h4>Customer Info</h4>
        <div class="form-group">
            <label>First Name</label>
            <input type="text" class="form-control" placeholder="First Name" 
            v-model="customer.first_name">
        </div>
        <div class="form-group">
            <label>Last Name</label>
            <input type="text" class="form-control" placeholder="Last Name" 
            v-model="customer.last_name">
        </div>
    </div>
    <div class="well">
        <h4>Customer Contact</h4>
        <div class="form-group">
            <label>Email</label>
            <input type="text" class="form-control" placeholder="Email" v-model="customer.email">
        </div>
        <div class="form-group">
            <label>Phone</label>
            <input type="text" class="form-control" placeholder="Phone" v-model="customer.phone">
        </div>
    </div>

    <div class="well">
        <h4>Customer Location</h4>
        <div class="form-group">
            <label>Address</label>
            <input type="text" class="form-control" placeholder="Address" v-model="customer.address">
        </div>
        <div class="form-group">
            <label>City</label>
            <input type="text" class="form-control" placeholder="City" v-model="customer.city">
        </div>
        <div class="form-group">
            <label>State</label>
            <input type="text" class="form-control" placeholder="State" v-model="customer.state">
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</template>

<script>
import Alert from './Alert'
export default {
name: 'add',
data () {
    return {
    customer: {},
    alert:''
    }
},
methods: {
    addCustomer(e){
        if(!this.customer.first_name || !this.customer.last_name || 
!this.customer.email){
            this.alert = 'Please fill in all required fields';
        } else {
            let newCustomer = {
                first_name: this.customer.first_name,
                last_name: this.customer.last_name,
                phone: this.customer.phone,
                email: this.customer.email,
                address: this.customer.address,
                city: this.customer.city,
                state: this.customer.state
            }
            this.$http.post('http://slimapp.dev/api/customer/add', 
            newCustomer)
                .then(function(response){
                    this.$router.push({path: '/', query: {alert: 'Customer 
            Added'}})

                });
            e.preventDefault();
            }
            e.preventDefault();
            }
            },
            components: {
             Alert
            }
            }
            </script>

            <!-- Add "scoped" attribute to limit CSS to this component only 
            -->
            <style scoped>
            </style>

This the alert component, Alert.vue

<template>
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span></button>
{{message}}
</div>
</template>

<script>
export default {
name: 'alert',
props: ['message'],
data () {
return {

}
}
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

And this is the component where the alert is to be viewed, Customers.vue

<template>
<div class="customers container">
<Alert v-if="alert" v-bind:message="alert" />
<h1 class="page-header">Manage Customers</h1>
<table class="table table-striped">
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="customer in customers">
      <td>{{customer.first_name}}</td>
      <td>{{customer.last_name}}</td>
      <td>{{customer.email}}</td>
      <td></td></tr>
  </tbody>
</table>

</div>
</template>

<script>
import Alert from './Alert';

export default {
name: 'customers',
data () {
return {

  customers: [],
  alert: ''

 }
},

methods: {
fetchCustomers(){
  this.$http.get('http://slimapp.dev/api/customers')
    .then(function(response){

      this.customers = (response.body); 
    });
  }
 },
created: function(){
 if (this.$route.params.alert) {
   this.alert = $route.params.alert
 }
 this.fetchCustomers();
},
updated: function(){
this.fetchCustomers();
},
components: {
  Alert
  }
}

How do I solve this?

Caleb Oki
  • 667
  • 2
  • 11
  • 29

2 Answers2

19

It is not possible to pass data through vue-router the way you want to. You only can pass parameters like this:

Route definition:

{ path: '/products/:id/edit', name: 'products.edit', component: ProductForm },

And then you can get the parameter with this.$route.params.id

Or you can do:

this.$router.push({name: 'products.index', params: { id: 1 }})

I suggest you to add a GET parameter like ?success=true or show an alert with sweetalert for example before pushing the new route.

Marcello B.
  • 4,177
  • 11
  • 45
  • 65
Eduardo Aguad
  • 811
  • 7
  • 15
  • I think you meant: this.$router.push({name: products.index, params: {id: 1 }) – Alessandro Dentella Dec 17 '18 at 12:17
  • 2
    @AlessandroDentella I actually meant ```this.$router.push({name: 'products.index', params: { id: 1 }})``` – Eduardo Aguad Dec 18 '18 at 19:13
  • @EduardoAguad is correct, `this.$router.push({name: 'foo', params: { foo: bar }})` – twknab May 12 '19 at 06:21
  • I see a lot of people suggest this `params` way to pass "invisible" (not in the url) data with `push`. But isn't it intended for urls like `users/:id`? I believe this is why [the docs](https://router.vuejs.org/api/#params) say the values in `params` have to be strings; because they're ultimately supposed to be tied to a url. Thus, the example `{ id: 1 }` above technically isn't valid. If you try to pass more advanced structures, it probably wont work. – V. Rubinetti Mar 23 '22 at 20:11
  • @V.Rubinetti the idea is to call whatever endpoint you need using the ID to get the info or use store to get the data. Obviously, it depends on the scenario. – Eduardo Aguad Mar 23 '22 at 21:14
  • This is not possible in the same way in Vue 3 without 'hacks'. See this SO post: https://stackoverflow.com/a/67181837/339803 – redfox05 Jul 27 '22 at 10:27
  • I miss the part of reading the params. Where would I read them and how...? – Dirk Schumacher Jan 03 '23 at 08:35
  • 1
    @DirkSchumacher please have a look to the documentation that explains it: https://router.vuejs.org/guide/essentials/dynamic-matching.html – Eduardo Aguad Jan 03 '23 at 20:13
0

A weird solution is to set the value to store/local_storage and retrieve and destroy it from the store/local_storage when the destination page loads.