[{"data":1,"prerenderedAt":89},["ShallowReactive",2],{"article:using-vuejs-app-in-d8-paragraph":3},{"type":4,"id":5,"drupal_internal__nid":6,"status":7,"title":8,"created":9,"changed":10,"metatag":11,"path":26,"body":30,"dashedTitle":35,"heroBackgroundUrl":36,"heroColor":37,"heroLayout":38,"heroOverlay":39,"navColor":40,"node_type":41,"uid":42,"$meta":45,"bio":50},"article","928f0c19-21cc-4267-879d-05e697049391",89,true,"Using a Vue.js app in a D8 Paragraph","2019-10-18T19:16:55+00:00","2020-05-12T22:49:03+00:00",[12,17,21],{"tag":13,"attributes":14},"meta",{"name":15,"content":16},"title","Small Robot Co. | Vancouver Web Design, Technical Consulting, App Development, & Support",{"tag":13,"attributes":18},{"name":19,"content":20},"description","We are a Vancouver, BC based Web Design, Technical Consulting, Web Development, and Support company, specializing in Drupal, Ember.js, websites and web apps.",{"tag":22,"attributes":23},"link",{"rel":24,"href":25},"canonical","https:\u002F\u002Fapi.smallrobot.co\u002Fusing-vuejs-app-d8-paragraph",{"alias":27,"pid":28,"langcode":29},"\u002Fusing-vuejs-app-d8-paragraph",18,"en",{"value":31,"format":32,"processed":33,"summary":34},"\u003Cp>I have had been given the task to pull data from a&nbsp;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.&nbsp;\u003C\u002Fp>\r\n\r\n\u003Cp>I wanted to keep this as simple as possible, and at the same time, make it cool.&nbsp;\u003C\u002Fp>\r\n\r\n\u003Cp>For this task, I decided to use \u003Ca href=\"https:\u002F\u002Fvuejs.org\u002F\" target=\"_blank\">Vue.js\u003C\u002Fa>&nbsp;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.&nbsp;\u003C\u002Fp>\r\n\r\n\u003Cp>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.\u003C\u002Fp>\r\n\r\n\u003Ch3>The Template\u003C\u002Fh3>\r\n\r\n\u003Cp>Using a template I created for that Paragraph, I did some markup tricks to get twig to render correctly. Notice the \u003Ccode>{' '}\u003C\u002Fcode> wrapping the \u003Ccode>{{ profile.firstname }}\u003C\u002Fcode>.\u003C\u002Fp>\r\n\r\n\u003Cpre>\r\n\u003Ccode>{# string wrapper is to prevent Twig processing the Vue vars #}\r\n&lt;div id=\"App\"&gt;\r\n  &lt;div v-for=\"profile in profiles\" class=\"card\"&gt;\r\n    &lt;h2 class=\"name\"&gt;{{ '{{ profile.firstName }} {{ profile.lastName }}' }}&lt;\u002Fh2&gt;\r\n  &lt;\u002Fdiv&gt;\r\n&lt;\u002Fdiv&gt;\u003C\u002Fcode>\u003C\u002Fpre>\r\n\r\n\u003Cp>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.\u003C\u002Fp>\r\n\r\n\u003Cp>You can also write it this way:\u003C\u002Fp>\r\n\r\n\u003Cpre>\r\n\u003Ccode>&lt;div id=\"App\"&gt;\r\n  &lt;div v-for=\"profile in profiles\" class=\"card\"&gt;\r\n    &lt;h2 class=\"name\"&gt;&lt;span v-html=\"profile.firstName\"&gt;&lt;\u002Fspan&gt; &lt;span v-html=\"profile.lastName\"&gt;&lt;\u002Fspan&gt;&lt;\u002Fh2&gt;\r\n  &lt;\u002Fdiv&gt;\r\n&lt;\u002Fdiv&gt;\u003C\u002Fcode>\u003C\u002Fpre>\r\n\r\n\u003Cp>Next&nbsp;I pulled the CDN versions of Vue into the template, as well as Axios, a data management plugin.\u003C\u002Fp>\r\n\r\n\u003Cpre>\r\n\u003Ccode>&lt;script src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fvue@2.6.0\"&gt;&lt;\u002Fscript&gt;\r\n&lt;script src=\"https:\u002F\u002Funpkg.com\u002Faxios\u002Fdist\u002Faxios.min.js\"&gt;&lt;\u002Fscript&gt;\u003C\u002Fcode>\u003C\u002Fpre>\r\n\r\n\u003Cp>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.\u003C\u002Fp>\r\n\r\n\u003Cpre>\r\n\u003Ccode>&lt;script&gt; const myApp = new Vue({\r\n  el: '#App',\r\n  data () {\r\n    return {\r\n      profiles: [],\r\n      loaded: false\r\n      }\r\n    },\r\n  methods: {\r\n    async getProfiles(id) {\r\n      const = 'https:\u002F\u002Fexample.com\u002Fapi\u002F';\r\n      let endpoint = 'profiles' \u003C\u002Fcode>\u003C\u002Fpre>\r\n\r\n\u003Cp>Notice the following API call, which includes the field values to filter the result.\u003C\u002Fp>\r\n\r\n\u003Cpre>\r\n\u003Ccode>  try {\r\n    const resp = await axios.get(url + endpoint + '?args[0]=\r\n      {% if content.field_setting|field_value %}\r\n        {{ content.field_setting|field_value }}  \r\n      {% else %}all{% endif %}\r\n      &amp;limit={{ content.field_limit|field_value }}  \r\n      &amp;offset={{ content.field_offset|field_value }}');\r\n\r\n      this.profiles = resp.data;\r\n      this.loaded = true;\r\n     }\r\n     catch (err) {\r\n        console.log(err)\r\n      }\r\n     },\r\n   },\r\n   mounted() {\r\n    profileParams = 'all';\r\n    this.getProfiles(profileParams);\r\n  }\r\n});\r\n&lt;\u002Fscript&gt;\u003C\u002Fcode>\u003C\u002Fpre>\r\n\r\n\u003Cp>The result is pretty awesome. Now anytime that paragraph is used, the app loads the Vue app, with the REST data.\u003C\u002Fp>\r\n\r\n\u003Cp>&nbsp;\u003C\u002Fp>\r\n","full_html","\u003Cp>I have had been given the task to pull data from a&nbsp;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.&nbsp;\u003C\u002Fp>\n\u003Cp>I wanted to keep this as simple as possible, and at the same time, make it cool.&nbsp;\u003C\u002Fp>\n\u003Cp>For this task, I decided to use \u003Ca href=\"https:\u002F\u002Fvuejs.org\u002F\" target=\"_blank\">Vue.js\u003C\u002Fa>&nbsp;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.&nbsp;\u003C\u002Fp>\n\u003Cp>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.\u003C\u002Fp>\n\u003Ch3>The Template\u003C\u002Fh3>\n\u003Cp>Using a template I created for that Paragraph, I did some markup tricks to get twig to render correctly. Notice the \u003Ccode>{' '}\u003C\u002Fcode> wrapping the \u003Ccode>{{ profile.firstname }}\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cpre>\n\u003Ccode>{# string wrapper is to prevent Twig processing the Vue vars #}\n&lt;div id=\"App\"&gt;\n  &lt;div v-for=\"profile in profiles\" class=\"card\"&gt;\n    &lt;h2 class=\"name\"&gt;{{ '{{ profile.firstName }} {{ profile.lastName }}' }}&lt;\u002Fh2&gt;\n  &lt;\u002Fdiv&gt;\n&lt;\u002Fdiv&gt;\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>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.\u003C\u002Fp>\n\u003Cp>You can also write it this way:\u003C\u002Fp>\n\u003Cpre>\n\u003Ccode>&lt;div id=\"App\"&gt;\n  &lt;div v-for=\"profile in profiles\" class=\"card\"&gt;\n    &lt;h2 class=\"name\"&gt;&lt;span v-html=\"profile.firstName\"&gt;&lt;\u002Fspan&gt; &lt;span v-html=\"profile.lastName\"&gt;&lt;\u002Fspan&gt;&lt;\u002Fh2&gt;\n  &lt;\u002Fdiv&gt;\n&lt;\u002Fdiv&gt;\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Next&nbsp;I pulled the CDN versions of Vue into the template, as well as Axios, a data management plugin.\u003C\u002Fp>\n\u003Cpre>\n\u003Ccode>&lt;script src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fvue@2.6.0\"&gt;&lt;\u002Fscript&gt;\n&lt;script src=\"https:\u002F\u002Funpkg.com\u002Faxios\u002Fdist\u002Faxios.min.js\"&gt;&lt;\u002Fscript&gt;\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>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.\u003C\u002Fp>\n\u003Cpre>\n\u003Ccode>&lt;script&gt; const myApp = new Vue({\n  el: '#App',\n  data () {\n    return {\n      profiles: [],\n      loaded: false\n      }\n    },\n  methods: {\n    async getProfiles(id) {\n      const = 'https:\u002F\u002Fexample.com\u002Fapi\u002F';\n      let endpoint = 'profiles' \u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Notice the following API call, which includes the field values to filter the result.\u003C\u002Fp>\n\u003Cpre>\n\u003Ccode>  try {\n    const resp = await axios.get(url + endpoint + '?args[0]=\n      {% if content.field_setting|field_value %}\n        {{ content.field_setting|field_value }}  \n      {% else %}all{% endif %}\n      &amp;limit={{ content.field_limit|field_value }}  \n      &amp;offset={{ content.field_offset|field_value }}');\n\n      this.profiles = resp.data;\n      this.loaded = true;\n     }\n     catch (err) {\n        console.log(err)\n      }\n     },\n   },\n   mounted() {\n    profileParams = 'all';\n    this.getProfiles(profileParams);\n  }\n});\n&lt;\u002Fscript&gt;\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>The result is pretty awesome. Now anytime that paragraph is used, the app loads the Vue app, with the REST data.\u003C\u002Fp>\n\u003Cp>&nbsp;\u003C\u002Fp>\n","","using-vuejs-app-in-d8-paragraph","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1446729444801-31245ddba81a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80","background-black","hero-center","overlay-graydark","nav-light",null,{"type":43,"id":44,"__unresolved":7},"user","f2161fdf-d42e-4a25-ab4a-1f31ec931d33",{"uid":46,"bio":48},{"drupal_internal__target_id":47},1,{"drupal_internal__target_id":49},50,{"type":51,"id":52,"drupal_internal__nid":49,"drupal_internal__vid":53,"langcode":29,"revision_timestamp":54,"status":7,"title":55,"created":56,"changed":54,"promote":7,"sticky":57,"default_langcode":7,"revision_translation_affected":7,"metatag":58,"path":66,"body":41,"linkedin":67,"professionalTitle":68,"twitter":69,"node_type":41,"revision_uid":42,"$meta":70,"uid":42,"photo":78},"bio","40ae49e0-5103-44fe-9768-456fdb3a0dd3",792,"2019-01-20T20:33:28+00:00","Trent Stromkins","2019-01-20T06:12:57+00:00",false,[59,61,63],{"tag":13,"attributes":60},{"name":15,"content":16},{"tag":13,"attributes":62},{"name":19,"content":20},{"tag":22,"attributes":64},{"rel":24,"href":65},"https:\u002F\u002Fapi.smallrobot.co\u002Fnode\u002F50",{"alias":41,"pid":41,"langcode":29},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Ftrentstromkins","Founder & CEO, Software Engineer","bmx269",{"revision_uid":71,"uid":72,"photo":73},{"drupal_internal__target_id":47},{"drupal_internal__target_id":47},{"alt":74,"title":34,"width":75,"height":76,"drupal_internal__target_id":77},"portrait of Trent Stromkins",360,415,91,{"type":79,"id":80,"drupal_internal__fid":77,"filename":81,"uri":82,"filemime":83,"filesize":84,"status":7,"created":85,"changed":86,"uid":42,"$meta":87},"file","b949d713-0184-4a63-b63e-e4c5805d8391","Trent.jpg","\u002Fsites\u002Fdefault\u002Ffiles\u002F2019-01\u002FTrent.jpg","image\u002Fjpeg",39025,"2019-01-20T06:13:43+00:00","2019-01-20T06:14:09+00:00",{"uid":88},{"drupal_internal__target_id":47},1785963526835]