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.
{# 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 }}</h3> </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.
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/vue@2.6.0"></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.