Almost EVERYONE who tried headless systems said they saw benefits. Download the state of CMS now!

Storyblok now on AWS Marketplace: Read more

O’Reilly Report: Decoupled Applications and Composable Web Architectures - Download Now

Empower your teams & get a 582% ROI: See Storyblok's CMS in action

Skip to main content

Render dynamic component depending on dates in Vue.js

Try Storyblok

Storyblok is the first headless CMS that works for developers & marketers alike.

  • Home
  • Tutorials
  • Render dynamic component depending on dates in Vue.js

With Vue.js it is unbelievably easy to render dynamic components, which we can utilize to render content with specific components and layouts by only using their name.

We've already covered the topic on how to render component dynamically from a JSON, now we will focus on how to only render components if in the correct time frame.

Section titled The JSON structure The JSON structure

The content JSON has been enhanced by a start and end field for one of our two components. The start and end property in our example are not required and can result in an empty string. Each DateTime string is in GMT+0 just so we get the question about timezones out of our mind for this.

        
      ...
  data() {
    return {
      content: {
        body: [
          {
            _uid: "BUY6Drn9e1",
            component: "foo",
            headline: "Foo"
+            start: "2019-09-02 01:59",
+            end: "2019-09-14 20:56"
          },
          {
            _uid: "gJZoSLkfZV",
            component: "bar",
            title: "Bar"
          },
          {
            _uid: "X1JAfdsZxy",
            component: "foo",
            headline: "Another headline",
+            start: "2019-12-25 19:55",
+            end: ""
          }
        ]
      }
    }
  },
...
    

Section titled Filtering before or during looping through components? Filtering before or during looping through components?

We now have two possibilities on how to receive the components we want to actually how. In this small example filtering the components beforehand will be much easier by using a computed property, however with a nested and more complex content structure that might already be way harder as you no longer loop through one array of objects but a tree content structure instead.

Section titled The filter function using a computed property The filter function using a computed property

Filtering dates in JavaScript is always a bit tricky, packages like momentjs make things easier. If you're performing more complex date operations it's good to know they exist, for this example we'll use the default Date of JavaScript and add the timezone +0000 before using the date strings.

        
      computed: {
  componentsToShow() {
    return this.content.body.filter(comp => {
      if (comp.start && comp.end) {
        let start = new Date(`${comp.start}+0000`);
        let end = new Date(`${comp.end}+0000`);
        return start <= new Date() && new Date() <= end;
      }

      if (comp.start) {
        let start = new Date(`${comp.start}+0000`);
        return start <= new Date();
      }

      if (comp.end) {
        let end = new Date(`${comp.end}+0000`);
        return new Date() <= end;
      }
      return true;
    });
  }
}
    

Instead of using the content.body property directly we will use our computed property componentsToShow.

        
      - <template v-for="block in content.body">
+ <template v-for="block in componentsToShow"> 
  <component :is="block.component" :block="block" :key="block._uid"></component>
</template>
    

Section titled Using a method to determine if a component should be included Using a method to determine if a component should be included

To use a method and the Vue.js template instead of using a computed property we extract the above filter method into a helper method, let us call it isComponentVisible.

        
      methods: {
  isComponentVisible: comp => {
    if (comp.start && comp.end) {
      let start = new Date(`${comp.start}+0000`);
      let end = new Date(`${comp.end}+0000`);
      return start <= new Date() && new Date() <= end;
    }

    if (comp.start) {
      let start = new Date(`${comp.start}+0000`);
      return start <= new Date();
    }

    if (comp.end) {
      let end = new Date(`${comp.end}+0000`);
      return new Date() <= end;
    }
    return true;
  }
},
    

Since we're not going to use the computed property we can return to our direct content structure using content.body.

        
      -<template v-for="block in componentsToShow"> 
+<template v-for="block in content.body">
  <component :is="block.component" :block="block" :key="block._uid"></component>
</template>
    

The last step to filter our components is to use the isComponentVisible method with the current block object.

        
      <template v-for="block in content.body">
-  <component :is="block.component" :block="block" :key="block._uid"></component>
+  <component v-if="isComponentVisible(block)" :is="block.component" :block="block" :key="block._uid"></component>
</template>
    

Section titled When should I use which approach? When should I use which approach?

We would recommend opting for the method approach as you can outsource that one method from your component and re-use it everywhere (where component might be used) in your Vue.js app. This way you no longer have the complexity of filtering out the components of the structure before rendering, but decide during rendering what to show.

Keep in mind that even tho the components are not displayed we would recommend to only use this approach with non-sensitive information. Your data is filtered on the client and the original information is still available through the browsers dev tools.

If you want to filter information before rendering on the client you would be able to use a server-side rendered website or a static site generator. Another option would be to go for a cloud function / custom API (Netlify Function / Zeit) to filter your component on a server.

Section titled Editing the JSON Editing the JSON

Start End Schema in components of Storyblok

Adding a start and end field to your components can be done by pressing Define Schema in that component and adding two new fields. Select the type Date/Time and you're ready to go. Try it out by exchanging the static content with our demo API Call right here.

Section titled Codesandbox example Codesandbox example

Here you can find the Codesandbox example.

Author

Dominik Angerer

Dominik Angerer

A web performance specialist and perfectionist. After working for big agencies as a full stack developer he founded Storyblok. He is also an active contributor to the open source community and one of the organizers of Scriptconf and Stahlstadt.js.