I have had been given the task to pull data from a REST API into a Drupal 8 Paragraph, to be rendered on any specific page. The API would provide the data for a profile, showing in a listing, and a full bio.
I wanted to keep this as simple as possible, and at the same time, make it cool.
For this task, I decided to use Vue.js inside a template. I felt that this would give me a way to work with Vue in a way that is not as common - inside a Drupal 8 template.
I created a Paragraph type called a Profile Listing. In that Paragraph, I added some fields that I would be using to control the API call. In this case, a related taxonomy, limit, and offset, and a few other fields.
Using a template I created for that Paragraph, I did some markup tricks to get twig to render correctly. Notice the {' '}
wrapping the {{ profile.firstname }}
.
{# string wrapper is to prevent Twig processing the Vue vars #}
<div id="App">
<div v-for="profile in profiles" class="card">
<h2 class="name">{{ '{{ profile.firstName }} {{ profile.lastName }}' }}</h2>
</div>
</div>
This allows the HTML to not be filtered in the template. This does make it so that ticks ` have to be used instead of single quotes inside that template.
You can also write it this way:
<div id="App">
<div v-for="profile in profiles" class="card">
<h2 class="name"><span v-html="profile.firstName"></span> <span v-html="profile.lastName"></span></h2>
</div>
</div>
Next I pulled the CDN versions of Vue into the template, as well as Axios, a data management plugin.
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Then inside a following script tag, I write the app. Since the app is inside the Paragraph, all field values can be used in the markup, allowing you to filter based on the values. This is a very shortened and modified version, but you get the picture.
<script> const myApp = new Vue({
el: '#App',
data () {
return {
profiles: [],
loaded: false
}
},
methods: {
async getProfiles(id) {
const = 'https://example.com/api/';
let endpoint = 'profiles'
Notice the following API call, which includes the field values to filter the result.
try {
const resp = await axios.get(url + endpoint + '?args[0]=
{% if content.field_setting|field_value %}
{{ content.field_setting|field_value }}
{% else %}all{% endif %}
&limit={{ content.field_limit|field_value }}
&offset={{ content.field_offset|field_value }}');
this.profiles = resp.data;
this.loaded = true;
}
catch (err) {
console.log(err)
}
},
},
mounted() {
profileParams = 'all';
this.getProfiles(profileParams);
}
});
</script>
The result is pretty awesome. Now anytime that paragraph is used, the app loads the Vue app, with the REST data.