Amanda Harvey
Amanda Harvey

Reputation: 549

Adding a new component instance in Vue via a button click returning error

Just to preface this whole thing-- I'm not even sure that the way I'm going about this is the most correct way to do it. Basically, I need to add an instance of a Vue component when the user clicks a button, expanding. I used this discussion in the vue.js forum to help. Unfortunately, triggering this insert function via a button click is not working. Console is showing an "addNewStop is not defined at HTMLButtonElement.onclick" error.

The HTML in my template:

<div id="newCont"></div>
            <button type="button" class="btn-primary" id="addStop" onclick="addNewStop()">Add Stop</button>

The script I'm calling:

  import Stops from '@/components/Stops'

  const ComponentCtor = Vue.extend(Stops)
  const componentInstance = new ComponentCtor({})
  function addNewStop() {
    componentInstance.$mount('#newCont')
  }

I will freely admit that I wasn't sure how to go about doing this in the first place, and have found surprisingly little information about how to insert new component instances. If there are other, better options I should be exploring beyond this, please let me know!

Edit:

Stops is actually a template containing form inputs, allowing the user to specify a delivery stop along a truck route. Here is its template:

<template>
  <div class="stops">
    <h4>Delivery</h4>
            <div class="form-group">
                  <label for="shipName">Shipper Name</label>
                <vue-simple-suggest
                    :list="simpleSuggestionList"
                    :filter-by-query="true" id="shipName" placeholder="Start typing a name" autocomplete="autofill-myself"></vue-simple-suggest>
                </div>
            <div class="form-group">
                  <label for="locationPickup">Location</label>
                <vue-simple-suggest
                    :list="simpleSuggestionList"
                    :filter-by-query="true" id="locationPickup" placeholder="Start typing an address" autocomplete="custom-addresses"></vue-simple-suggest>
                </div>
                <div class="form-group row">
              <label>Date</label>
              <flat-pickr
              :config="dateConfig"
                class="form-control" 
                placeholder="Select date"               
                name="date" id="date1"></flat-pickr>
            </div>

            <div class="row">
              <div class="form-group col left">
              <label>Time</label>
              <flat-pickr
                :config="timeConfig"
                class="form-control" 
                placeholder="Select time"               
                name="time1" id="time1"></flat-pickr>
              </div>

              <div class="form-group col right">
              <label v-show="pickupChecked">Time 2</label>
              <flat-pickr
                :config="timeConfig"
                class="form-control" 
                placeholder="Select time"               
                name="time2" v-show="pickupChecked" id="time2"></flat-pickr>
              </div>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="checkbox" v-model="pickupChecked" id="apptCheck1" >
                <label class="form-check-label" for="apptCheck1">
                  Time range?
                </label>
            </div>
             <div class="form-group row">
              <label for="userAboutMe">Location notes:</label>
              <textarea class="form-control" id="userAboutMe" rows="3" placeholder="Is there any information about the location that the driver should know?"></textarea>
              <div class="form-check">
                <input class="form-check-input" type="checkbox" value="" id="defaultCheck1">
                <label class="form-check-label" for="defaultCheck1">
                  Save location notes for this place?
                </label>
              </div>
            </div>
  </div>

</template>

Upvotes: 2

Views: 7456

Answers (1)

Stephen Thomas
Stephen Thomas

Reputation: 14053

In most cases, trying to manipulate the DOM directly (e.g. by adding a component) is a sign that you're not using Vue.js as it was intended. Vue is data-driven, which means that your code should simply update the data, leaving the DOM manipulation to Vue itself. Your question doesn't provide enough details for a specific solution, but there are a couple of general approaches that might work.

If you have a number of Stop components in the DOM, and clicking on the button simply adds another, then use v-for to render the stops from data, and have the button click handler simply add another entry in the data array.

<template>
    <form>
        <fieldset v-for="(stop, index) in stops" :key="index">
            <stop v-bind="whatever"/>
        </fieldset>
        <button @click="onClick">Add one</button>
    </form>
</template>

<script>
export default {
    data() {
        return {
            stops: []
        };
    },
    methods: {
        onClick() {
            this.stops.push(/* whatever */)'
        }
    },
    components {
        Stop
    }
};
</script>

Upvotes: 5

Related Questions