Categories
JavaScript Answers

How to Replace All Occurrences of a Javascript String?

Replacing all occurrences of a string is something that we often have to do in a JavaScript app.

In this article, we’ll look at how to replace all occurrences of a string in a JavaScript app.

String.prototype.replaceAll

The replaceAll method is a new method that’s available as part of JavaScript strings since ES2021.

It’s supported by many recent browsers like Chrome, Edge, or Firefox.

To use it, we write:

const result = "1 abc 2 abc 3".replaceAll("abc", "def");

The first argument is the string we want to replace.

And the 2nd argument is the string we want to replace it with.

Therefore, result is '1 def 2 def 3' .

Split and Join

We can also split a string by the string that we want to replace and call join with the string that we want to replace the original string with,

For instance, we can write:

const result = "1 abc 2 abc 3".split("abc").join("def");

to split a string with 'abc' as the separator and call join with 'def' .

And we get the same result returned.

Regex Replace

We can replace a string with the given pattern with a new string.

For instance, we can write:

const result = "1 abc 2 abc 3".replace(/abc/g, 'def');

to replace all instances 'abc' with 'def' .

The g flag means we look for all instances with the given pattern.

We can also use the RegExp constructor to create our regex object:

const result = "1 abc 2 abc 3".replace(new RegExp('abc', 'g'), 'def');

While Loop and Includes

We can use the includes method to check if a string has a given substring.

So if it has a given substring, includes will return true .

Therefore, we can use it with the while loop to replace all instances of a substring with a new one by using includes in the condition.

For instance, we can write:

let str = "1 abc 2 abc 3";  
while (str.includes("abc")) {  
  str = str.replace("abc", "def");  
}

We use let so that we can reassign the value.

The only downside is that we have to mutate the str variable.

Conclusion

There are many ways to replace all instances of a substring with another one in JavaScript.

The newest and easier way to replace all substrings is to use the replaceAll method, which comes with ES2021 and is available with most recent browsers.

Categories
JavaScript Answers

How to Compare Two Dates with JavaScript?

Comparing 2 dates is something we’ve to do often in a JavaScript app.

In this article, we’ll look at how to compare 2 dates with JavaScript.

Comparing Timestamps

One easy way to compare 2 dates is to compare their timestamps.

We can get the timestamp with the getTime method.

For instance, we can write:

const d1 = new Date();  
const d2 = new Date(d1);  
const same = d1.getTime() === d2.getTime();  
const notSame = d1.getTime() !== d2.getTime();

getTime returns the UNIX epoch in seconds.

It’s time number of seconds since January 1, 1970 midnight UTC.

We can also write:

const d1 = new Date();  
const d2 = new Date(d1);  
const same = +d1 === +d2;  
const notSame = +d1 !== +d2;

which replaces getTime with the + before the date objects.

It does the same thing as getTime .

Relational Operators

We can use relational operators directly with date objects.

For instance, we can write:

const d1 = new Date(2021, 0, 1);  
const d2 = new Date(2021, 0, 2);  
d1 < d2;  
d1 <= d2;  
d1 > d2;  
d1 >= d2;

to compare them directly with the relational operators.

d1 and d2 will be converted to timestamps before comparing.

Subtracting Dates

We can also subtract one date from another and compare the result to what we want.

For instance, we can write:

const d1 = new Date(2021, 0, 1);  
const d2 = new Date(2021, 0, 2);  
console.log(d1 - d2 === 0);  
console.log(d1 - d2 < 0);  
console.log(d1 - d2 > 0);

This works because d1 and d2 are converted to timestamps before we subtract them.

Comparing Year, Month, and Date

We can compare the year, month, and day of 2 date objects to check if they’re the same to determine if they’re the same date.

For instance, we can write:

const d1 = new Date(2021, 0, 1);  
const d2 = new Date(2021, 0, 2);  
const isSameDate = d1.getFullYear() === d2.getFullYear() &&  
  d1.getDate() === d2.getDate() &&  
  d1.getMonth() === d2.getMonth();

getFullYear returns the 4 digit year number.

getDate returns the date.

And getMonth returns the month from 0 to 11. 0 is January, 1 is February, etc.

Conclusion

We can compare 2 dates easily with JavaScript by converting them to numbers with various operators.

Then we can compare them.

We can also compare their year, month, and day values individually.

Categories
Vue

Add Charts to a Vue App with Highcharts-Vue — Line and Gantt Charts

Highcharts-Vue is an easy to use library that lets us add charts to our Vue apps.

In this article, we’ll look at how to add charts with the highcharts-vue library.

Line Chart

We can add a line chart by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import HighchartsVue from "highcharts-vue";

Vue.use(HighchartsVue);

new Vue({
  el: "#app",
  render: (h) => h(App)
});

App.vue

<template>
  <div>
    <highcharts class="hc" :options="chartOptions" ref="chart"></highcharts>
  </div>
</template>

<script>
export default {
  data() {
    return {
      chartOptions: {
        series: [
          {
            data: [1, 2, 3],
          },
        ],
      },
    };
  },
};
</script>

We register the HighchartsVue plugin and then use the highcharts component within App.vue .

The data for the y-axis is in the series.data property.

Gantt Chart

To create a Gantt chart, we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import Highcharts from "highcharts";
import Gantt from "highcharts/modules/gantt";
import HighchartsVue from "highcharts-vue";

Gantt(Highcharts);
Vue.use(HighchartsVue);

new Vue({
  el: "#app",
  render: (h) => h(App)
});

App.vue

<template>
  <div>
    <highcharts
      :constructorType="'ganttChart'"
      class="hc"
      :options="chartOptions"
      ref="chart"
    ></highcharts>
  </div>
</template>

<script>
export default {
  data() {
    return {
      chartOptions: {
        title: {
          text: "Gantt Chart with Progress Indicators",
        },
        xAxis: {
          min: Date.UTC(2021, 10, 17),
          max: Date.UTC(2021, 10, 30),
        },

        series: [
          {
            name: "Project 1",
            data: [
              {
                name: "Start",
                start: Date.UTC(2021, 10, 18),
                end: Date.UTC(2021, 10, 25),
                completed: 0.25,
              },
              {
                name: "Test",
                start: Date.UTC(2021, 10, 27),
                end: Date.UTC(2021, 10, 29),
              },
              {
                name: "Develop",
                start: Date.UTC(2021, 10, 20),
                end: Date.UTC(2021, 10, 25),
                completed: {
                  amount: 0.12,
                  fill: "#fa0",
                },
              },
              {
                name: "Test Again",
                start: Date.UTC(2021, 10, 23),
                end: Date.UTC(2021, 10, 26),
              },
            ],
          },
        ],
      },
    };
  },
};
</script>

We call the Gantt function in main.js to let us add Gantt charts.

Then we can use the highcharts component to render the chart.

The title has the title.

xAxis has the x-axis value range.

series has the data.

name has the name for the bar.

start and end are the start and end dates.

completed has the progress value.

Conclusion

We can add a line and Gantt chart easily with highcharts-vue.

Categories
Vue

Add Charts to a Vue App with Highcharts-Vue

Highcharts-Vue is an easy to use library that lets us add charts to our Vue apps.

In this article, we’ll look at how to add charts with the highcharts-vue library.

Getting Started

We can install the highcharts-vue library by running:

npm i highcharts-vue highcharts

The highcharts library is required for the highcharts-vue library.

Then we can add a simple chart by writing:

main.js

import Vue from "vue";
import HighchartsVue from "highcharts-vue";
import App from "./App.vue";

Vue.config.productionTip = false;
Vue.use(HighchartsVue);

new Vue({
  render: (h) => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <highcharts :options="chartOptions"></highcharts>
  </div>
</template>

<script>
import { Chart } from "highcharts-vue";

export default {
  name: "App",
  data() {
    return {
      chartOptions: {
        series: [
          {
            data: [1, 2, 3],
          },
        ],
      },
    };
  },
  components: {
    highcharts: Chart,
  },
};
</script>

We call Vue.use(HighchartsVue) to register the chart library.

Then we register the Chart component in App.vue by putting it in the comnponents property.

Then we add the highcharts component into the template with the options prop.

It’s set to the chartOptions reactive property which has the series.data property with the data.

Stock Chart

We can add a stock chart by passing in more props to the highcharts component.

To do this, we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import Highcharts from "highcharts";
import Stock from "highcharts/modules/stock";
import HighchartsVue from "highcharts-vue";

Stock(Highcharts);
Vue.use(HighchartsVue);

new Vue({
  el: "#app",
  render: (h) => h(App)
});

App.vue

<template>
  <div>
    <highcharts
      :constructorType="'stockChart'"
      class="hc"
      :options="chartOptions"
      ref="chart"
    ></highcharts>
  </div>
</template>

<script>
export default {
  data() {
    return {
      chartOptions: {
        series: [
          {
            data: [1, 2, 3],
          },
        ],
      },
    };
  },
};
</script>

In main.js , we call the Stock function with Highcharts to let us add a stock chart.

Then in App.vue , we set the constructorType prop to 'stockChart’ and the options as we did before.

Map Chart

We can add a map chart easily with Highcharts-Vue.

We need to install the @highcharts/map-collection library to add a map chart.

To install it, we run:

npm i @highcharts/map-collection

Then, we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import Highcharts from "highcharts";
import Maps from "highcharts/modules/map";
import HighchartsVue from "highcharts-vue";

Maps(Highcharts);
Vue.use(HighchartsVue);

new Vue({
  el: "#app",
  render: (h) => h(App)
});

App.vue

<template>
  <div>
    <highcharts
      :constructorType="'mapChart'"
      class="hc"
      :options="chartOptions"
      ref="chart"
    ></highcharts>
  </div>
</template>

<script>
import worldMap from "@highcharts/map-collection/custom/world.geo.json";

export default {
  data() {
    return {
      chartOptions: {
        chart: {
          map: worldMap,
        },
        title: {
          text: "Highmaps",
        },
        subtitle: {
          text: "<b>World map</b>",
        },
        mapNavigation: {
          enabled: true,
          buttonOptions: {
            alignTo: "spacingBox",
          },
        },
        colorAxis: {
          min: 0,
        },
        series: [
          {
            name: "Random data",
            states: {
              hover: {
                color: "#BADA55",
              },
            },
            dataLabels: {
              enabled: true,
              format: "{point.name}",
            },
            allAreas: false,
            data: [
              ["fo", 0],
              ["um", 1],
              ["us", 2],
              ["jp", 3],
              ["sc", 4],
              ["in", 5],
              ["fr", 6],
              ["fm", 7],
              ["cn", 8],
              ["pt", 9],
              ["sw", 10],
              ["sh", 11],
              ["br", 12],
              ["ki", 13],
              ["ph", 14],
              ["mx", 15],
              ["es", 16],
              ["bu", 17],
              ["mv", 18],
              ["sp", 19],
              ["gb", 20],
              ["gr", 21],
              ["as", 22],
              ["dk", 23],
              ["gl", 24],
              ["gu", 25],
              ["mp", 26],
              ["pr", 27],
              ["vi", 28],
              ["ca", 29],
              ["st", 30],
              ["cv", 31],
              ["dm", 32],
              ["nl", 33],
              ["jm", 34],
              ["ws", 35],
              ["om", 36],
              ["vc", 37],
              ["tr", 38],
              ["bd", 39],
              ["lc", 40],
              ["nr", 41],
              ["no", 42],
              ["kn", 43],
              ["bh", 44],
              ["to", 45],
              ["fi", 46],
              ["id", 47],
              ["mu", 48],
              ["se", 49],
              ["tt", 50],
              ["my", 51],
              ["pa", 52],
              ["pw", 53],
              ["tv", 54],
              ["mh", 55],
              ["cl", 56],
              ["th", 57],
              ["gd", 58],
              ["ee", 59],
              ["ag", 60],
              ["tw", 61],
              ["bb", 62],
              ["it", 63],
              ["mt", 64],
              ["vu", 65],
              ["sg", 66],
              ["cy", 67],
              ["lk", 68],
              ["km", 69],
              ["fj", 70],
              ["ru", 71],
              ["va", 72],
              ["sm", 73],
              ["kz", 74],
              ["az", 75],
              ["tj", 76],
              ["ls", 77],
              ["uz", 78],
              ["ma", 79],
              ["co", 80],
              ["tl", 81],
              ["tz", 82],
              ["ar", 83],
              ["sa", 84],
              ["pk", 85],
              ["ye", 86],
              ["ae", 87],
              ["ke", 88],
              ["pe", 89],
              ["do", 90],
              ["ht", 91],
              ["pg", 92],
              ["ao", 93],
              ["kh", 94],
              ["vn", 95],
              ["mz", 96],
              ["cr", 97],
              ["bj", 98],
              ["ng", 99],
              ["ir", 100],
              ["sv", 101],
              ["sl", 102],
              ["gw", 103],
              ["hr", 104],
              ["bz", 105],
              ["za", 106],
              ["cf", 107],
              ["sd", 108],
              ["cd", 109],
              ["kw", 110],
              ["de", 111],
              ["be", 112],
              ["ie", 113],
              ["kp", 114],
              ["kr", 115],
              ["gy", 116],
              ["hn", 117],
              ["mm", 118],
              ["ga", 119],
              ["gq", 120],
              ["ni", 121],
              ["lv", 122],
              ["ug", 123],
              ["mw", 124],
              ["am", 125],
              ["sx", 126],
              ["tm", 127],
              ["zm", 128],
              ["nc", 129],
              ["mr", 130],
              ["dz", 131],
              ["lt", 132],
              ["et", 133],
              ["er", 134],
              ["gh", 135],
              ["si", 136],
              ["gt", 137],
              ["ba", 138],
              ["jo", 139],
              ["sy", 140],
              ["mc", 141],
              ["al", 142],
              ["uy", 143],
              ["cnm", 144],
              ["mn", 145],
              ["rw", 146],
              ["so", 147],
              ["bo", 148],
              ["cm", 149],
              ["cg", 150],
              ["eh", 151],
              ["rs", 152],
              ["me", 153],
              ["tg", 154],
              ["la", 155],
              ["af", 156],
              ["ua", 157],
              ["sk", 158],
              ["jk", 159],
              ["bg", 160],
              ["qa", 161],
              ["li", 162],
              ["at", 163],
              ["sz", 164],
              ["hu", 165],
              ["ro", 166],
              ["ne", 167],
              ["lu", 168],
              ["ad", 169],
              ["ci", 170],
              ["lr", 171],
              ["bn", 172],
              ["iq", 173],
              ["ge", 174],
              ["gm", 175],
              ["ch", 176],
              ["td", 177],
              ["kv", 178],
              ["lb", 179],
              ["dj", 180],
              ["bi", 181],
              ["sr", 182],
              ["il", 183],
              ["ml", 184],
              ["sn", 185],
              ["gn", 186],
              ["zw", 187],
              ["pl", 188],
              ["mk", 189],
              ["py", 190],
              ["by", 191],
              ["cz", 192],
              ["bf", 193],
              ["na", 194],
              ["ly", 195],
              ["tn", 196],
              ["bt", 197],
              ["md", 198],
              ["ss", 199],
              ["bw", 200],
              ["bs", 201],
              ["nz", 202],
              ["cu", 203],
              ["ec", 204],
              ["au", 205],
              ["ve", 206],
              ["sb", 207],
              ["mg", 208],
              ["is", 209],
              ["eg", 210],
              ["kg", 211],
              ["np", 212],
            ],
          },
        ],
      },
    };
  },
};
</script>

In main.js , we call the Maps function to create the maps.

We import the worldMap component to let us add a map chart.

And we put all the options in the charrOptions object.

title has the main title.

subtitle has the subtitle.

mapNavihation lets us add navigation to the map.

colorAxis has the color axis options. min is the minimum value for the axis.

series has the data.

dataLabels lets us format the data labels.

Conclusion

We can create various kinds of charts with Highcharts-Vue.

Categories
Vue

How to Make a Calendar App with Vue

For many applications, recording dates is an important feature. Having a calendar is often a handy feature to have. Fortunately, many developers have made calendar components that other developers can easily add to their apps.

Vue.js has many calendar widgets that we can add to our apps. One of them is Vue.js Full Calendar. It has a lot of features. It has a month, week, and day calendar. Also, you can navigate easily to today or any other days with back and next buttons. You can also drag over a date range in the calendar to select the date range. With that, you can do any manipulation you want with the dates.

In this article, we will make a simple calendar app where users can drag over a date range and add a calendar entry. Users can also click on an existing calendar entry and edit the entry. Existing entries can also be deleted. The form for adding and editing the calendar entry will have date and time pickers to select the date and time.

We will save the data on the back end in a JSON file.

We will use Vue.js to build our app. To start, we run:

npx @vue/cli create calendar-app

Next we select ‘Manually select features’ and select Babel, CSS Preprocessor, Vue Router and Vuex.

After the app is created, we have to install some packages that we need. We need Axios for making HTTP requests to our back end, BootstrapVue for styling, jQuery and Moment are dependencies for the Vue-Full-Calendar package which we will use to display a calendar. Vee-Validate for form validation, Vue-Ctk-Date-Time-Picker to let users pick the date and time for the calendar events andVue-Full-Calendar is used for the calendar widget.

We run:

npm i axios bootstrap-vue jquery moment vee-validate vue-ctk-date-time-picker vue-full-calendar

to install all the packages.

With all the packages installed, we can start writing the app. First we start with the form for entering the calendar entries.

Create a file called CalendarForm.vue in the components folder and add:

<template>
  <div>
    <ValidationObserver ref="observer" v-slot="{ invalid }">
      <b-form @submit.prevent="onSubmit" novalidate>
        <b-form-group label="Title" label-for="title">
          <ValidationProvider name="title" rules="required" v-slot="{ errors }">
            <b-form-input
              :state="errors.length == 0"
              v-model="form.title"
              type="text"
              required
              placeholder="Title"
              name="title"
            ></b-form-input>
            <b-form-invalid-feedback :state="errors.length == 0">Title is required</b-form-invalid-feedback>
          </ValidationProvider>
        </b-form-group>

        <b-form-group label="Start" label-for="start">
          <ValidationProvider name="start" rules="required" v-slot="{ errors }">
            <VueCtkDateTimePicker
              input-class="form-control"
              :state="errors.length == 0"
              v-model="form.start"
              name="start"
            ></VueCtkDateTimePicker>
            <b-form-invalid-feedback :state="errors.length == 0">Start is required</b-form-invalid-feedback>
          </ValidationProvider>
        </b-form-group>

        <b-form-group label="End" label-for="end">
          <ValidationProvider name="end" rules="required" v-slot="{ errors }">
            <VueCtkDateTimePicker
              input-class="form-control"
              :state="errors.length == 0"
              v-model="form.end"
              name="end"
            ></VueCtkDateTimePicker>
            <b-form-invalid-feedback :state="errors.length == 0">End is required</b-form-invalid-feedback>
          </ValidationProvider>
        </b-form-group>

        <b-button type="submit" variant="primary">Save</b-button>
        <b-button type="button" variant="primary" @click="deleteEvent(form.id)">Delete</b-button>
      </b-form>
    </ValidationObserver>
  </div>
</template>

<script>
import { requestsMixin } from "../mixins/requestsMixin";
import * as moment from "moment";

export default {
  name: "CalendarForm",
  props: {
    edit: Boolean,
    calendarEvent: Object
  },
  mixins: [requestsMixin],
  data() {
    return {
      form: {}
    };
  },
  watch: {
    calendarEvent: {
      immediate: true,
      deep: true,
      handler(val, oldVal) {
        this.form = val || {};
      }
    }
  },
  methods: {
    async onSubmit() {
      const isValid = await this.$refs.observer.validate();
      if (!isValid) {
        return;
      }
      this.form.start = moment(this.form.start).format("YYYY-MM-DD HH:mm:ss");
      this.form.end = moment(this.form.end).format("YYYY-MM-DD HH:mm:ss");

      if (this.edit) {
        await this.editCalendar(this.form);
      } else {
        await this.addCalendar(this.form);
      }
      const response = await this.getCalendar();
      this.$store.commit("setEvents", response.data);
      this.$emit("eventSaved");
    },

    async deleteEvent(id) {
      await this.deleteCalendar(id);
      const response = await this.getCalendar();
      this.$store.commit("setEvents", response.data);
      this.$emit("eventSaved");
    }
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
button {
  margin-right: 10px;
}
</style>

In this file, we use the BootstrapVue form component to build our form. We use the VueCtkDateTimePicker to add the date and time picker for our form to let users pick the time and date.

We wrap each input with the ValidationProvider component to let us validate each field. Each field is required so we set the rules prop to required .

We set the :state binding to errors.length == 0 to display errors only when the errors array has length bigger than 0. This also applies to b-form-invalid-feedback component.

The form has a Save button to to run onSubmit when the button is clicked. We check the form’s validity by calling this.$refs.observer.validate() . We have this object because we wrapped the form with theValidationObserver component with ref set to observer .

In the function, we format the start and end dates so that we save the correct date and time.

If the edit prop is set to true, then we call the this.editCalendar function in requestsMixin . Otherwise we call this.addCalendar in the same mixin.

Once that succeeds, we call this.$store.commit(“setEvents”, response.data); after calling this.getCalendar to put the latest calendar events into our Vuex store.

After that’s done, we emit the eventSaved event so that we can close the modals in located in the home page.

Next we create the mixins folder and the requestsMixin.js file inside it. In there, we add:

const APIURL = "[http://localhost:3000](http://localhost:3000)";
const axios = require("axios");

export const requestsMixin = {
  methods: {
    getCalendar() {
      return axios.get(`${APIURL}/calendar`);
    },

    addCalendar(data) {
      return axios.post(`${APIURL}/calendar`, data);
    },

    editCalendar(data) {
      return axios.put(`${APIURL}/calendar/${data.id}`, data);
    },

    deleteCalendar(id) {
      return axios.delete(`${APIURL}/calendar/${id}`);
    }
  }
};

These are the functions for making HTTP requests to the back end.

Next we modify Home.vue , by replacing the existing code with:

<template>
  <div class="page">
    <div class="buttons">
      <b-button v-b-modal.add-modal>Add Calendar Event</b-button>
    </div>
    <full-calendar :events="events" @event-selected="openEditModal" defaultView="month" />

    <b-modal id="add-modal" title="Add Calendar Event" hide-footer ref="add-modal">
      <CalendarForm :edit="false" @eventSaved="closeModal()" />
    </b-modal>

    <b-modal id="edit-modal" title="Edit Calendar Event" hide-footer ref="edit-modal">
      <CalendarForm :edit="true" :calendarEvent="calendarEvent" @eventSaved="closeModal()" />
    </b-modal>
  </div>
</template>

<script>
// @ is an alias to /src
import CalendarForm from "@/components/CalendarForm.vue";
import { requestsMixin } from "../mixins/requestsMixin";

export default {
  name: "home",
  components: {
    CalendarForm
  },
  mixins: [requestsMixin],
  computed: {
    events() {
      return this.$store.state.events;
    }
  },
  data() {
    return {
      calendarEvent: {}
    };
  },
  async beforeMount() {
    await this.getEvents();
  },
  methods: {
    async getEvents() {
      const response = await this.getCalendar();
      this.$store.commit("setEvents", response.data);
    },
    closeModal() {
      this.$refs["add-modal"].hide();
      this.$refs["edit-modal"].hide();
      this.calendarEvent = {};
    },
    openEditModal(event) {
      let { id, start, end, title } = event;
      this.calendarEvent = { id, start, end, title };
      this.$refs["edit-modal"].show();
    }
  }
};
</script>

<style lang="scss" scoped>
.buttons {
  margin-bottom: 10px;
}
</style>

In this file, we include the full-calendar component from the Vue Full Calendar package, and an add and edit calendar event modals. We use CalendarForm for both.

Notice that we handle the eventSaved event here, which is emitted by CalendarForm . We call closeModal when the event is emitted, so that the modals will close.

We also pass in the calendarEvent and edit prop set to true when we open the edit modal.

The ref for the modal is set so we can show and hide the modal by their ref .

We get the latest state of the events in the Vuex store by watching this.$store.state.events .

Next we replace the code in App.vue with:

<template>
  <div id="app">
    <b-navbar toggleable="lg" type="dark" variant="info">
      <b-navbar-brand to="/">Calendar App</b-navbar-brand>

      <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>

      <b-collapse id="nav-collapse" is-nav>
        <b-navbar-nav>
          <b-nav-item to="/" :active="path  == '/'">Home</b-nav-item>
        </b-navbar-nav>
      </b-collapse>
    </b-navbar>
    <router-view />
  </div>
</template>

<script>
export default {
  data() {
    return {
      path: this.$route && this.$route.path
    };
  },
  watch: {
    $route(route) {
      this.path = route.path;
    }
  }
};
</script>

<style lang="scss">
.page {
  padding: 20px;
}
</style>

We add the BootstrapVue b-navbar here and watch the route as it changes so that we can set the active prop to the link of the page the user is currently in.

Next we change the code in main.js to:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import FullCalendar from "vue-full-calendar";
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import 'vue-ctk-date-time-picker/dist/vue-ctk-date-time-picker.css';
import { ValidationProvider, extend, ValidationObserver } from "vee-validate";
import { required } from "vee-validate/dist/rules";
import VueCtkDateTimePicker from 'vue-ctk-date-time-picker';

extend("required", required);
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);
Vue.use(FullCalendar);
Vue.use(BootstrapVue);
Vue.component('VueCtkDateTimePicker', VueCtkDateTimePicker);

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

We import all the app-wide packages we use here, like BootstrapVue, Vee-Validate and the calendar and date-time picker widgets.

The styles are also imported here so we can see them throughout the app.

Next in router.js , replace the existing code with:

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import 'fullcalendar/dist/fullcalendar.css'

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "home",
      component: Home
    }
  ]
});

to set the routes for our app, so that when users enter the given URL or click on a link with it, they can see our page.

Next in store.js , we replace the existing code with:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    events: []
  },
  mutations: {
    setEvents(state, payload) {
      state.events = payload;
    }
  },
  actions: {}
});

We added an events state for the calendar events, and a setEvents function that we dispatched with this.$store.commit so that we can set the events in the store and access it in all our components.

Finally, we replace the code in index.html with:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title>Calendar App</title>
  </head>
  <body>
    <noscript>
      <strong
        >We're sorry but vue-calendar-tutorial-app doesn't work properly without
        JavaScript enabled. Please enable it to continue.</strong
      >
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

to change the app’s title.

Now all the hard work is done. All we have to do is use JSON Server NPM package located at https://github.com/typicode/json-server for our back end.

Install it by running:

npm i -g json-server

Then run it by running:

json-server --watch db.json

In db.json , replace the existing content with:

{
  "calendar": []
}

Next we run our app by running npm run serve in our app’s project folder to run our app.