Pass Django Data into Vue component

Viewed 3219

I am using Django as a backend and I am trying to pass some data into a Vue table component that I made. I set it up using this tutorial The component is showing up fine while using a webpack. I am trying to set the data to a javascript constant and then pass it into the component. The data does not appear to be passing through. Here is how my scripts are laid out.

index.html

{% block content %}
<script>
  const gridData = {{json_data|safe}};
  console.log(gridData)
</script>

    <div id="app">
        <table_component
        v-bind:tableData=this.gridData
        >
        </table_component>

    </div>  
{% end block %}

myComponent.vue script seciton

export default {
  name: 'table_component',
    props: {
    tableData: Array
  },
  data() {
      return {

      }
  },
  components: {
    Grid,
    ButtonModal
  },
  created(){
    console.log(this.tableData)
  },
}

When I look at the console, it is not showing any data. It just says undefined.

view.py

class CurrentClassroomView(LoginRequiredMixin, CreateView):
    template_name = 'home/index.html'

    def get(self, request, *args, **kwargs):
        db_data = list(myData.objects.all().values())
        my_json_data = json.dumps(db_data)
        return render(request, self.template_name, {'json_data':my_json_data})  

I am getting this in the console that I am not sure what that means and why it is making everything lowercase even though I'm passing it with upper case letters.

[Vue tip]: Prop "griddata" is passed to component <Anonymous>, but the declared prop name is "gridData". Note that HTML attributes are case-insensitive and camelCased props need to use their kebab-case equivalents when using in-DOM templates. You should probably use "grid-data" instead of "GridData".
tip @ vue.js:639
extractPropsFromVNodeData @ vue.js:2294
createComponent @ vue.js:3233
_createElement @ vue.js:3427
createElement @ vue.js:3359
vm._c @ vue.js:3496
eval @ VM1553:3
Vue._render @ vue.js:3550
updateComponent @ vue.js:4066
get @ vue.js:4477
Watcher @ vue.js:4466
mountComponent @ vue.js:4073
Vue.$mount @ vue.js:9043
Vue.$mount @ vue.js:11943
Vue._init @ vue.js:5011
Vue @ vue.js:5077
eval @ index.js:14
./assets/js/index.js @ app.js:409
__webpack_require__ @ app.js:20
(anonymous) @ app.js:84
(anonymous) @ app.js:87

Any help on this would be greatly appreciated. I am not sure where I am going wrong

1 Answers

When you set gridData and try to bind it to a Vue component it is not working because they have different contexts. When you dealing with Vue components you can only access data defined inside the Vue instance. Additionally, {{json_data|safe}} is vulnerable to XSS-type attacks.

However, it is very easy to safely pass data from Django to a Vue component, we just have to use the json_script filter and load the data in Vue's mounted hook.

In views.py just pass the list to the template, no need to use json.dumps():

class CurrentClassroomView(LoginRequiredMixin, CreateView):
    template_name = 'home/index.html'

    def get(self, request, *args, **kwargs):
        db_data = list(myData.objects.all().values())
        return render(request, self.template_name, {'json_data':db_data}) 

In index.html, we will use the json_script template tag to create a JSON formatted representation of json_data variable:

{% block content %}
{{ json_data|json_script:"json_data" }}

<div id="app">
    <table_component></table_component>
</div>  
{% end block %}

This will create a <script> block, e.g.:

<script id="json_data" type="application/json">{"hello": "world"}</script>

And finally, in myComponent.vue, we load, JSON-decode and set the data in the mounted hook:

export default {
  data() {
      return {
          tableData
      }
  },
  components: {
    Grid,
    ButtonModal
  },
  mounted() {
    this.tableData = JSON.parse(document.getElementById('json_data').textContent)
  },
}
Related