Vue app fetches API data, and objects seem toad into my template, but the text does not appear

Viewed 45

I have created a Vue app that fetches data from my Django REST API and shows it on a page. The data consists of a list of objects that resemble {'name': Whitney Portal, 'parent': Inyo National Forest', 'camp_id': 232123}

I have an input field that users can type text into, and the Vue app will dynamically display all objects that contain the input text.

It appears to be that the app is loading objects into the template, but none of the desired text is showing. I want to show the camp attributes, such as the name for each object.

I have attached a random string 'I'm HERE!' in the html to each object generated, so I can see how many objects are displayed at any one time. However that is the only text showing for each object.

When I type into my input field, the number of objects (and instances of 'I'm HERE!') changes. The objects respond as expected (I know what text to type into the box to make only one object show). For example, if I type in 'Inyo' then only one object remains (because only one of the objects in my database has 'Inyo National Forest' as a parent attribute.

When nothing is typed in, then the number of objects showing matches the number in the database. When I look into the developer tools > Network, I see that a successful API GET request was made and I see all the data in the response.

I receive no errors in the console. Has anyone else encountered this problem before and resolved it?

I am using Django, Django REST Framework, and Vue JS

Vue app

const App = new Vue({
    el: '#show-camps',
    data() {
        return {
            campgrounds: [],
            search: '',
            test: 'test',
        };
    },
    async created() {
        const response = await fetch('http://localhost:8000/api/campgrounds/');
        this.campgrounds = await response.json();
    },
    methods: {
    },
    computed: {
        filteredCamps: function(){
            return this.campgrounds.filter((camp) => {
                return camp.parent.match(this.search);
            });
        }
    }
})

My template

<!DOCTYPE html>
{% extends 'base/base.html' %}
{% load static %}
{% block title %}Campground List{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="row justify-content-center">
        <div class="head col-12 col-sm-10 col-md-7 text-center solid">
            <h1>List of all campgrounds</h1>
            <p>Here is a list of some campground IDs that I've collected.</p>
            <hr>
        </div>
    </div >

    <!--Campground ID Display-->
    <div class="row justify-content-center">
        <div class=" col-12 col-sm-10 col-md-7 text-center solid">
            <div id="show-camps">
                <input type="text" v-model="search" placeholder="search campgrounds"/>
                <div v-for="camp in filteredCamps">
                    <div>
                        {{camp.name}}
                        {{camp.camp_id}}
                        {{camp.parent}}
                        {{ test }}
                    </div>
                    I'm HERE!
                    {{camp.name}}
                    {{camp.camp_id}}
                    {{camp.parent}}
                    {{ test }}
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
    <script type="text/javascript" src="{% static 'js/vue.js' %}"></script>
    <script type="text/javascript" src="{% static 'js/main.js' %}"></script>
{% endblock %}

API Response

[
    {
        "camp_id": "232122",
        "name": "WHITE BRIDGE",
        "parent": "Dixie National Forest"
    },
    {
        "camp_id": "232123",
        "name": "WHITNEY PORTAL",
        "parent": "Inyo National Forest"
    }
]
1 Answers

The problem is that both Vue and Django use the same mustache template syntax for displaying variables so all your {{ camp.name }} bits are trying to display server-side variables.

The way to fix this properly is to tell Django not to process tags using the verbatim tag

{% verbatim %}
<div id="show-camps">
  <!-- all your Vue template code goes here -->
</div>
{% endverbatim %}

Another option is to configure Vue using the delimiters option. For example

const App = new Vue({
  el: '#show-camps',
  delimiters: ["[[", "]]"],
  // etc
})

and then in your HTML template

<div>
  [[ camp.name ]]
  [[ camp.camp_id ]]
  [[ camp.parent ]]
</div>
Related