Show flash message onSubmit form Vue.js

Viewed 1891

I'm trying to create a contact form, which I have done but now I'm trying to create a submit flash message on submit. When submitted the form goes to a PHP file, but I want to show a message and not redirect.

Here is what I have for the message component which is called FlashMessage

<template>
  <div
    class="flex items-center bg-green-500 text-white text-sm font-bold px-4 py-3 mb-6"
    role="alert"
    v-show="show"
  >
    <svg class="fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
      <path
        d="M12.432 0c1.34 0 2.01.912 2.01 1.957 0 1.305-1.164 2.512-2.679 2.512-1.269 0-2.009-.75-1.974-1.99C9.789 1.436 10.67 0 12.432 0zM8.309 20c-1.058 0-1.833-.652-1.093-3.524l1.214-5.092c.211-.814.246-1.141 0-1.141-.317 0-1.689.562-2.502 1.117l-.528-.88c2.572-2.186 5.531-3.467 6.801-3.467 1.057 0 1.233 1.273.705 3.23l-1.391 5.352c-.246.945-.141 1.271.106 1.271.317 0 1.357-.392 2.379-1.207l.6.814C12.098 19.02 9.365 20 8.309 20z"
      />
    </svg>
    <p>{{ body }}</p>
  </div>
</template>

<script>
export default {
  name: "FlashMessage",
  props: {
    message: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      show: false,
      body: ""
    };
  },
  created() {
    if (this.message) {
      this.flash(this.message);
    }
    window.events.$on("flash", message => this.flash(message));
  },
  methods: {
    flash(message) {
      this.show = true;
      this.body = message;

      setTimeout(() => {
        this.hide();
      }, 3000);
    },
    hide() {
      this.show = false;
    }
  }
};
</script>

Here is the form

<FlashMessage message="Message sent!" />

<form @submit.prevent="onSubmit" action="./backend/contact.php" method="POST">
<div class="mb-4">
  <label class="block" for="name">
    <span class="text-gray-900">Full name</span>
    <input
      class="form-input mt-1 block w-full outline-none"
      placeholder="Sherlock Holmes"
      id="name"
      name="name"
      type="text"
    />
  </label>
</div>

<div class="mb-4">
  <label class="block" for="email">
    <span class="text-gray-900">Email address</span>
    <input
      class="form-input mt-1 block w-full outline-none"
      placeholder="sherlock@bakerstreet.com"
      id="email"
      name="email"
      type="email"
    />
  </label>
</div>

<div class="mb-4">
  <label class="block" for="department">
    <span class="text-gray-700">Department</span>
    <select
      class="form-select mt-1 block w-full outline-none"
      id="department"
      name="department"
    >
      <option value="1">General Support</option>
      <option value="2">Hosting Support</option>
      <option value="3">Domain Support</option>
      <option value="4">Game Support</option>
    </select>
  </label>
</div>

<div class="mb-4">
  <label class="block" for="message">
    <span class="text-gray-900">Message</span>
    <textarea
      class="form-input mt-1 block w-full outline-none h-56 resize-none"
      placeholder="Enter your message here"
      id="message"
      name="message"
      type="text"
    />
  </label>
</div>

<div class="flex mt-6">
  <label class="flex items-center">
    <input type="checkbox" class="form-checkbox" />
    <span class="ml-2">
      I agree to the
      <a href="#" class="underline">privacy policy</a>
    </span>
  </label>
</div>

<div class="flex mt-6">
  <label class="flex items-center">
    <button
      type="submit"
      class="flex items-center py-3 px-6 border rounded bg-gray-800 hover:bg-gray-900 font-medium text-white transition duration-300 ease-in-out"
    >
      <i class="fas fa-paper-plane mr-4"></i>
      Send
    </button>
  </label>
</div>
</form>

<script>
import FlashMessage from "../components/FlashMessage";
import FeaturesWGrid from "../components/FeaturesWGrid";
import Grid from "../components/Grid";
import GridItem from "../components/GridItem";

export default {
  name: "Contact",
  components: {
    FlashMessage,
    FeaturesWGrid,
    Grid,
    GridItem
  },
  methods: {
    onSubmit() {
      show: true;
    }
  }
};
</script>

contact.php

<?php
include("/home/hostedca/redacted/includes/api.php");

$api_identifier = "";
$api_secret = "";

$postfields = array(
    "identifier" => $api_identifier,
    "secret" => $api_secret,
    "action" => "OpenTicket",
    "responsetype" => "json",
);

$name = $_POST["name"];
$email = $_POST["email"];
$department = $_POST["department"];
$message = $_POST["message"];

$command = "OpenTicket";
$postData = array(
    "deptid" => "$department",
    "name" => "$name",
    "email" => "$email",
    "subject" => "Contact form Inquiry from $name for $department",
    "message" => "$message",
    "priority" => "Medium",
    "markdown" => false,
);

$adminUsername = "admin";

// Call the localAPI function
$results = localAPI($command, $postData, $adminUsername);
if ($results['result'] == 'success') {
    echo 'Message sent successfully!';
} else {
    echo "An Error Occurred: " . $results['result'];
}
?>

Not sure where I'm going wrong.

3 Answers

show data property should be a prop like :

export default {
  name: "FlashMessage",
  props: {
    message: {
      type: String,
      required: true
    },
   show:{
   type:Boolean,
   default:false
   }
  },
  data() {
    return {

      body: ""
    };
  },

in the Contact component :

<FlashMessage message="Message sent!" :show="showMsg"/>

....
export default {
  name: "Contact",
  components: {
    FlashMessage,
    FeaturesWGrid,
    Grid,
    GridItem
  },
 data(){
 return{
  showMsg:false,
}
},
  methods: {
    onSubmit() {
      this.showMsg= true;
    }
  }
};

You can remove the 'v-show' condition from the child component FlashMessage.vue. Directly use the value in the parent,

Set show with false as default value in the data section. Change the onSubmit() method like follows

export default {
  name: "Contact",
  data:()=>{
    return {
      show:false
    }
  },
  methods: {
    onSubmit() {
      this.show = true;
      setTimeout(()=>{
        this.show = false;
      },3000);
      // rest of your logic
    }
  }
};

While calling the child component add v-if or v-show condition like follow

<FlashMessage message="Message sent!" v-if = "show"/>

You are not passing show as a prop and it is not declared in the parent, so, instead of declaring it in the data of the child, you should let the parent be in control and pass the variable as a prop as follows:

  • In the parent:
    <FlashMessage message="Message sent!" show="show"/>
    data(){
         return{
              show:false
         }
    },
    methods:{
         onSubmit(){
             this.show = true;
             setTimeout(() => {
                 this.show = false;
             }, 3000);
         }
    }
  • And in the child:
    <template>
          <div
               class="flex items-center bg-green-500 text-white text-sm font-bold px-4 py-3 mb-6"
               role="alert"
               v-show="show"
           >
                <svg class="fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
                <path
                 d="M12.432 0c1.34 0 2.01.912 2.01 1.957 0 1.305-1.164 2.512-2.679 2.512-1.269 0-2.009-.75-1.974-1.99C9.789 1.436 10.67 0 12.432 0zM8.309 20c-1.058 0-1.833-.652-1.093-3.524l1.214-5.092c.211-.814.246-1.141 0-1.141-.317 0-1.689.562-2.502 1.117l-.528-.88c2.572-2.186 5.531-3.467 6.801-3.467 1.057 0 1.233 1.273.705 3.23l-1.391 5.352c-.246.945-.141 1.271.106 1.271.317 0 1.357-.392 2.379-1.207l.6.814C12.098 19.02 9.365 20 8.309 20z"
               />
            </svg>
            <p>{{ message }}</p>
         </div>
    </template>

    <script>
    export default {
         name: "FlashMessage",
         props: {
             message: {
                  type: String,
                  required: true
             },
             show: {
                  type: Boolean,
                  required: true
             }
         },
    };
    </script>
    ```
Related