VueJS failing to pass parent data to child component

I'm fairly new to Vue Framework and I'm trying to figure out how to update a child component based on changes in the parent component's attributes. In the code snippet below, I've created a component that displays a greeting message based on the "name" attribute of the node passed from the parent.

Everything works fine if the "name" attribute is present when the node is initialized. However, if the name attribute is added later (as shown in the demonstration with a setTimeout function), the component throws an error and doesn't reflect the changes. I'm struggling to understand how to propagate changes for dynamic attributes generated outside the component.

Essentially, I want the component to dynamically display different widgets based on server responses tied to properties passed to it. I want the component to update itself whenever these properties change. Why isn't two-way binding working as expected in Vuejs?

Vue.component('greeting', {
    template: '#treeContainer',
    props: {'message':Object},
    watch:{
        'message': {
            handler: function(val) {
                console.log('###### changed');
            },
            deep: true
        }
    }
});

var data = {
    note: 'My Tree',
    // name:"Hello World",
    children: [
      { name: 'hello' },
      { name: 'wat' }
    ]
}

function delayedUpdate() {
    data.name='Changed World';
    console.log(JSON.stringify(data));
}

var vm = new Vue({
    el: '#app',
    data:{
        msg:data
    },
    method:{ }
});

setTimeout(function(){ delayedUpdate() ;}, 1000)
<script src="https://vuejs.org/js/vue.js"></script>
<div id="app">
  <greeting :message="msg"></greeting>
</div>
<script  type="text/x-template"  id="treeContainer">
<h1>{{message.name}}</h1>
</script>

Edit 1: @Craig's answer helped me understand how to propagate changes using the "name" attribute and calling set on each attribute. But what if the data is complex and the greeting message relies on multiple attributes of the node? In real-world scenarios, widgets are based on many dynamically sent attributes from the server and each widget varies based on its type. For example, "Welcome, {{message.name}} . Temperature at {{ message.location }} is {{ message.temp}} ." Since the attributes can vary, is there a way to update the entire tree without manually traversing all nodes and calling set on each attribute? Does VUE framework offer a solution for this situation?

Answer №1

Vue has limitations in detecting property addition or deletion without using the set method (refer to: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats). To address this issue, you can use the following code:

Vue.set(data, 'name', 'changed world')

View the JSFiddle link for a demonstration: https://jsfiddle.net/f7ae2364/

UPDATE

If you cannot watch the prop, consider implementing an event bus for communication. Begin by setting up a global bus for your component to listen on:

var bus = new Vue({});

When receiving new data, emit the event onto the bus with the updated data:

bus.$emit('data-updated', data);

To listen for this event within your component and update accordingly (using ES6), follow these steps:

created(){
   bus.$on('data-updated', (message) => {
     this.message = message;
     this.$forceUpdate();
   })
}

Check out the JSFiddle link to see this implementation: https://jsfiddle.net/9trhcjp4/

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring the compatibility between ADFS 2.0 and JSONP

My main website uses passive federation (ADFS 2.0) and includes javascript that communicates with an MVC Web API site using jsonp. I am facing a challenge in getting this WebAPI to support Single Sign On on the same machine but different port. The passive ...

Is there a way to turn off step navigation in bootstrap?

Displayed below is a visual representation of the bootstrap step navigation component. Presently, there is an unseen 'next' button located at the bottom of the page. When this 'next' button is pressed, it transitions from 'step-1 ...

Error: Kinetic.js cannot upload image to canvas

There must be something simple that I'm missing here. I've checked my code line by line, but for some reason, the image just won't load. var displayImage = function(){ var stage = new Kinetic.Stage("imgarea", 250, 256); var layer = new ...

How to ensure unique results when using DFS for Combination Sum?

I am currently tackling the challenge of solving LeetCode #49 Combination Sum. The objective here is to identify all the distinct combinations that add up to the specified target. While it's relatively straightforward to find permutations that result ...

Sharing data between two components on the same level in Vue.js

I have a situation where I need to transfer data from one component1 to another component2. I am not utilizing vuex or router for this task. The component tree looks like this: -Parent --Component1 --Component2 In the first component1, I am sending an ...

Just starting out with d3, any easy methods to learn?

As a developer with a few years of experience under my belt, I recently discovered d3 and was really impressed by its capabilities. However, it seems like d3 doesn't have the same level of popularity as jquery, making it harder to find comprehensive d ...

Navigating the translation URL in a Node.js Express app

Can someone please guide me on how to handle routing for translated URLs in a Node.js Express application? In my app.js file, I currently have the following routes. How can I improve this setup for handling URLs that change based on language, while still ...

Creating a Rectangular Trapezoid Shape with CSS - Eliminating Unnecessary Spacing

I'm trying to create a trapezoid button using CSS. Here is the intended look: However, my current implementation looks like this: The button appears fine but there seems to be some excess space below it. It's almost like an unwanted margin, ev ...

Setting Up AdminLTE Using Bower

Recently, I decided to incorporate the Admin LTE Template into my Laravel project. I diligently followed the guidelines outlined here As soon as I entered the command: bower install admin-lte The installation process seemed to start, but then the ...

Utilizing dispatch sequentially within ngrx StateManagement

I have been working on a project that utilizes ngrx for state management. Although I am still fairly new to ngrx, I understand the basics such as using this.store.select to subscribe to any state changes. However, I have a question regarding the following ...

What is the best way to apply the addClass method to a list element

I've been searching for a solution to this issue for some time now, and while I believed my code was correct, it doesn't appear to be functioning as expected. HTML <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js ...

Error: The function "this.state.data.map" is not defined in ReactJS

class Home extends Component { constructor(props) { super(props); this.state = { data: [], isLoaded: false, }; } componentDidMount() { fetch("https://reqres.in/api/users?page=2") .then((res) => res.json ...

Using `babel/register` does not seem to be functioning as expected

I am working on an isomorphic app built in ES6 on the client side using the Babel transpiler. I would like my express server to also utilize the same ES6 syntax as the client code. Unfortunately, attempting to use require('babel/register') has n ...

The latest update to the Server Stats code mistakenly changes the channel to "undefined" instead of displaying the total number

I've been working on a private bot for a specific server that displays server statistics and more. However, I've encountered an issue where every time a user joins or leaves the guild, the bot updates a channel with 'undefined' instead ...

What is the best way to interact with the member variables and methods within the VideoJs function in an Angular 2 project

Having an issue with accessing values and methods in the videojs plugin within my Angular project. When the component initializes, the values are showing as undefined. I've tried calling the videojs method in ngAfterViewInit as well, but still not get ...

When encountering an OR operator, Javascript will cease execution of the remaining conditions

This is a basic JavaScript form-validation I created. All the document.form.*.value references are present on my page, except for the document.form.dasdasdas.value ==''. In the code below, the purpose is to display an error if any of the forms a ...

Show the contents of a JSON file using Vue

I have a JSON file containing some data that needs to be fetched and displayed in a component. In the actions of my Vuex store, I've implemented: async getTodos (context) { const todos = [] const response = await fetch('../../data/todos.jso ...

Restoring styles back to the default CSS settings

I am currently working on creating visualizations using D3, and one challenge that I have encountered is the need to define a lot of styles within my code instead of in my CSS where I would prefer them to be. This necessity arises mainly to support transi ...

Top method for keeping track of most recent function outcome

Over time, I have become accustomed to utilizing the bind method to store the previous result of a function and keep track of it for future use. This allows me to easily concatenate or join the previous string with a new string without needing external var ...

Activate a CSS class on click using JavaScript

Having a bit of trouble as a beginner with this. Any help would be much appreciated. This is the code in question: HTML: <div class='zone11'> <div class='book11'> <div class='cover11'></d ...