Skip to content
Advertisement

Vue js – Update index value doesn’t update the second component’s view

I have this pretty simple Vue js page as below:

<html>
    <head>
        <script src="https://unpkg.com/vue/dist/vue.js"></script>
    </head>
    <body>
        <div id="main-container">
            <div id="contact-table">
                <table>
                    <thead>
                        <tr>
                            <th>Contact Name</th>
                            <th>Email</th>
                        </tr>
                    </thead>
                    <tbody v-for="contact in contacts">
                        <tr v-on:click="selectContact(contact.index)">
                            <td>
                                {{contact.name}}
                            </td>
                            <td>
                                {{contact.email}}
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div id="contact-form">
                <input type="text" v-model="contactName"/>
                <input type="text" v-model="contactEmail"/>
                <button type="button" v-on:click="updateContact">Update Contact</button>
            </div>
        </div>
    </body>
    <script>
        var hub = {
            contacts: [
                {
                    name: "James",
                    email: "Jame@bond.com",
                    index: 0
                },
                {
                    name: "Mary",
                    email: "Mary@lamb.com",
                    index: 1
                }
            ],
            index: 0
        };

        var contactTable = new Vue({
            el: "#contact-table",
            data: {
                contacts: hub.contacts
            },
            methods: {
                selectContact: function(index) {
                    hub.index = index;
                    console.log(hub.index);
                }
            }
        });

        var contactForm = new Vue({
            el: "#contact-form",
            data: {
                contactName: hub.contacts[hub.index].name,
                contactEmail: hub.contacts[hub.index].email
            },
            methods: {
                updateContact: function() {
                    hub.contacts[hub.index].name = this.contactName;
                    hub.contacts[hub.index].email = this.contactEmail;
                }
            }
        });
    </script>
</html>

Basically it contains two Vue parts – the table and the input form. By clicking the row in the table it should change the value in the input form and but clicking the Update contact button it should update the form details.

The second part is working well – however, when I clicked the table’s row, although console.log tells me the hub.index is well updated, but the view in the input form is not.

I believe this should be a two-way binding here so I am just wondering where did I do wrong here.

Advertisement

Answer

Your hub variable is outside vue instance, so this varible is not reactive, meaning that if this variable change vue will not update the DOM. You can also define hub in the data part of vue and make it reactive.

You also need to have an event bus, as you want to communicate between your two components, You can send an event using $emit and listen to the component in other component using $on.

Here is the working fiddle for your code: https://jsfiddle.net/mimani/50ajs58L/1/

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<body>
  <div id="main-container">
    <div id="contact-table">
      <table>
        <thead>
          <tr>
            <th>Contact Name</th>
            <th>Email</th>
          </tr>
        </thead>
        <tbody v-for="(contact, index) in contacts">
          <tr v-on:click="selectContact(index)">
            <td>
              {{contact.name}}
            </td>
            <td>
              {{contact.email}}
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <div id="contact-form">
      <input type="text" v-model="contactName" />
      <input type="text" v-model="contactEmail" />
      <button type="button" v-on:click="updateContact">Update Contact</button>
    </div>
  </div>
</body>
<script>
  var hub = {
    contacts: [{
      name: "James",
      email: "Jame@bond.com",
      index: 0
    }, {
      name: "Mary",
      email: "Mary@lamb.com",
      index: 1
    }],
    index: 0
  };
  var bus = new Vue()
  var contactTable = new Vue({
    el: "#contact-table",
    data: {
      contacts: hub.contacts
    },
    methods: {
      selectContact: function(index) {
        hub.index = index;
        console.log(hub.index);
        bus.$emit('updateIndex', index)
      }
    }
  });

  var contactForm = new Vue({
    el: "#contact-form",
    data: {
      contactName: hub.contacts[hub.index].name,
      contactEmail: hub.contacts[hub.index].email,
      index: hub.index
    },
    methods: {
      updateContact: function() {
        hub.contacts[this.index].name = this.contactName;
        hub.contacts[this.index].email = this.contactEmail;
      }
    },
    created() {
      var that = this
      bus.$on('updateIndex', function(index) {
        that.index = index
        that.contactName = hub.contacts[that.index].name
        that.contactEmail = hub.contacts[that.index].email
      })
    }
  });

</script>

Here I have used event bus, but as your application grows, you can think of using a state management technique which will give you variables accessible to all the components, or you can use vuex which is popular among community. You can have a look at this and this answer for more details.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement