Vue

by the94air

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/bootstrap-vue.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bootstrap-vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<div id="app">
  <b-container v-cloak>
    <b-form @submit="handleSubmit" v-if="!success">
      <b-form-row class="mb-4">
        <b-col xl="4" lg="4" md="4" sm="12">
          <b-form-select :options="options.years" v-model="form.year" size="lg" @change="handleYearChange" :disabled="disableAll"></b-form-select>
        </b-col>
        <b-col xl="4" lg="4" md="4" sm="12">
          <b-form-select :options="options.makes" v-model="form.make" size="lg" :disabled="disableAll"></b-form-select>
        </b-col>
        <b-col xl="4" lg="4" md="4" sm="12">
          <b-form-select :options="options.models" v-model="form.model" size="lg" :disabled="disableAll"></b-form-select>
        </b-col>
        <b-col xl="4" lg="4" md="4" sm="12">
          <b-button type="submit" size="lg" variant="primary" block :disabled="disableAll"><span v-if="loading" class="loading">Please wait <span>.</span><span>.</span><span>.</span></span><span v-else>Submit</span></b-button>
        </b-col>
        <b-col xl="4" lg="4" md="4" sm="12">
          <pre>{{ json }}</pre>
        </b-col>
      </b-form-row>
    </b-form>
    <b-row v-else>
      <b-col>
        <div style="text-align: center"><h1>Thank you!</h1></div>
      </b-col>
    </b-row>
  </b-container>
</div>

CSS

body {
  margin-top: 200px;
}
select, button, .loading {
  margin-bottom: 15px;
}
.loading {
  text-align: center;
}
.loading span {
  animation-name: blink;
  animation-duration: 1.4s;
  animation-iteration-count: infinite;
  animation-fill-mode: both;
}
.loading span:nth-child(2) {
  animation-delay: .2s;
}
.loading span:nth-child(3) {
  animation-delay: .4s;
}
@keyframes blink {
  0% {
    opacity: .2;
  }
  20% {
    opacity: 1;
  }
  100% {
    opacity: .2;
  }
}
[v-cloak] {
  display: none;
}

Vue

new Vue({
  el: "#app",
  watch: {
    "form.year": function () {
      this.prepareParams();
    },
    "form.make": function () {
      this.prepareParams();
    }
  },
  computed: {
  	json() {
    	return JSON.stringify(this.form, null, 2);
    }
  },
  methods: {
    handleSubmit(e) {
      e.preventDefault();
      // validate all fields
      // send data to backend
      if(this.form.year !== "" && this.form.make !== "" && this.form.model !== "") {
      	this.success = true;
      }
    },
    handleYearChange() {
      this.form.make = "";
      this.form.model = "";
    },
    prepareParams() {
      var self = this;
      if(this.form.year !== "" && this.form.make !== "") {
        self.loading = true;
        self.disableAll = true;
        var url = `https://vpic.nhtsa.dot.gov/api/vehicles/getmodelsformakeyear/make/${self.form.make}/modelyear/${self.form.year}?format=json`;

        axios.get(url)
          .then(function (response) {
          var results = response.data.Results;
          var models = [{ text: "Model...", value: "" }];

          var modelsResults = results.map((result) => ({
            text: result.Model_Name,
            value: result.Model_Name
          }));

          models.push(...modelsResults);
          self.options.models = models;
          self.form.model = "";
          self.disableAll = false;
        })
          .catch(function (error) {
          // handle error
          console.log(error);
        })
          .then(function () {
          self.loading = false;
        });
      }
    },
  },
  data: {
    loading: false,
    disableAll: false,
    success: false,
    form: {
      year: "",
      make: "",
      model: "",
    },
    options: {
      years: [
        { text: "Year...", value: "" },
        { text: "2018", value: "2018" },
        { text: "2017", value: "2017" },
        { text: "2016", value: "2016" },
        { text: "2015", value: "2015" },
        { text: "2014", value: "2014" },
        {...