[Vuejs]-VueJS component display other component content

0đź‘Ť

âś…

There’re some errors in your code:

  • @click="!(displayAddressBook)" should be @click="displayAddressBook = !displayAddressBook" – the first really does nothing (interesting), the second (suggested) sets the value of displayAddressBook to the opposite it has currently.
  • the input-address component does not really do anything with the input field (missing v-model)
  • the changes in the child component (input-address) are not sent back to the parent (added a watcher to do that in the child component)
  • the parent component (mail-composer) has to handle the values emitted from the child (added the @address-change action handler)
  • the v-for in your input-address component does not have a key set. Added key by using the index for it (not the best solution, but easy to do).
  • just put createmail.to: {{ createmail.to }} at the end of MailComposer, so you can see how it changes

Suggestions

  • always use CamelCase for component names – if you get used to it, then you get less “why is it not working?!” moments
  • watch for typos: createmail doesn’t look good – createEmail or just simply createemail would be better (ok, it doesn’t look so nice – maybe you should choose a totally different name for that)
Vue.component('InputAddress', {
  props: ["addresses"],
  data() {
    return {
      displayAddressBook: false,
      address: null
    }
  },
  template: `
          <div>
          <label><b>To: </b>
            <input
              type="text"
              v-model="address"
            />
            <button
              @click="displayAddressBook = !displayAddressBook"
            >
              Address Book
            </button>
          </label>
          <ul v-if="displayAddressBook">
            <li
              v-for="(address, i) in addresses"
              :key="i"
              @click="clickAddressHandler(address)"
             >
              {{address}}
            </li>
          </ul>
          </div>
        `,
  watch: {
    address(newVal) {
      // emitting value to parent on change of the address
      // data attribute
      this.$emit('address-change', newVal)
    }
  },
  methods: {
    clickAddressHandler(address) {
      // handling click on an address in the address book
      this.address = address
      this.displayAddressBook = false
    }
  }
})

Vue.component('MailComposer', {
  props: ['addressesbook'],
  data() {
    return {
      createmail: {
        to: '',
        subject: '',
        body: ''
      }
    }
  },
  methods: {
    send: function(createmail) {
      this.$emit('send', createmail);
    },
    addressChangeHandler(value) {
      this.createmail.to = value
    }
  },
  template: `
            <div>
              <input-address
                :addresses="addressesbook"
                v-model="createmail.to"
                @address-change="addressChangeHandler"
              />
              <p>
                <b>Subject: </b>
                <input
                  type="text"
                  v-model="createmail.subject"
                />
              </p>
              <p>
                <b>Body: </b>
                <textarea v-model="createmail.body"></textarea>
              </p>
              <button @click="send(createmail)">Send</button><br />
              createmail.to: {{ createmail.to }}
            </div>
            `
});

new Vue({
  el: "#app",
  data: {
    addressesbook: [
      'abcd@abcd.com',
      'fghi@fghi.com'
    ]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <mail-composer :addressesbook="addressesbook" />
</div>

Leave a comment