Building a Horizontal Calendar with VueJS and Vis.js Part 2/3

Casper Bottelet
5 min readJun 23, 2020

Hello again, welcome to part 2 of creating a horizontal calendar with Vit.js and Vue.js.

Let’s dig into the Vue part.

I’ll first create a new Vue component called Calendar.vue and register it in app.js

import calendar from ‘./components/Calendar.vue’;var app = new Vue({el: ‘#wrapper’,components: {calendar}});

and add then I’ll use it in my calendar view which we created in the previous part by simply referencing the new component

calendar.blade.php<div id=”wrapper”><calendar></calendar></div>

I then wanted to get rid of the CDN we were using and install it as a package so I deleted the JS and CSS CDN scripts we added before

<link href=”//unpkg.com/vis-timeline@latest/dist/vis-timeline-graph2d.min.css” rel=”stylesheet” type=”text/css” /><script type=”text/javascript” src=”//unpkg.com/vis-timeline@latest/dist/vis-timeline-graph2d.min.js”></script>

and did

npm install vis-timeline

Let’s put everything over into the Vue component I simply copy-pasted all of the scripts into the mounted method of Vuejs, but this is messy so let’s create a component that works with the mock data we have created

Calendar.vue<template><div class=”wrapper”><p>Timeline test 2</p><div id=”visualization”></div></div></template>

Start by importing the Timeline we downloaded as a package. and changed the reference from vis.timeline to Timeline in your `mounted()` method.

<script>import { Timeline } from ‘vis-timeline/standalone’;mounted() {….. All the options etc// Create a Timelinelet timeline = new Timeline(document.getElementById(‘visualization’));}</script>

secondly, let’s add all the mock data we have as `data()`

data() {return {items: [{id: 1, content: “Item 1”, start: ‘2020–04–01 10:00:00’, end: ‘2020–04–01 11:00:00’, group: 1},{id: 2, content: ‘item 2’, start: ‘2020–04–01 09:00:00’, end: ‘2020–04–01 10:00:00’, group: 0},{id: 3, content: ‘item 3’, start: ‘2020–04–03 08:00:00’, end: ‘2020–04–03 10:00:00’, group: 1},{id: 4, content: ‘item 4’, start: ‘2020–04–02 08:00:00’, end: ‘2020–04–02 10:00:00’, group: 1},{id: 5, content: ‘item 5’, start: ‘2020–04–02 08:00:00’, end: ‘2020–04–02 10:00:00’, group: 0}],groups: [{id:0,content: ‘Group 1’},{id:1,content: ‘Group 2’},],options: {orientation: “top”,itemsAlwaysDraggable:true,timeAxis: {scale: ‘hour’, step: 1, },zoomMax: 150000000,//for days 7 instead of 6?minHeight:’500px’,start: ‘2020–04–01’,hiddenDates: {start: ‘2020–03–04 18:00:00’,end: ‘2020–03–05 06:00:00’,repeat: ‘daily’},editable: {add: true, // add new items by double tappingupdateTime: true, // drag items horizontallyupdateGroup: true, // drag items from one group to anotherremove: true, // delete an item by tapping the delete button top rightoverrideItems: false // allow these options to override item.editable},onUpdate: function (item, callback) {item.content = prompt(‘Edit items text:’, item.content);if (item.content != null) {callback(item); // send back adjusted item}else {callback(null); // cancel updating the item}},onMove: function (item, callback) {console.log(item, callback)if (item.content != null) {callback(item); // send back adjusted item}else {callback(null); // cancel updating the item}},}}},

And then in your mounted method you should have something like this instead to reference the new variables:

let timeline = new Timeline(document.getElementById(‘visualization’));timeline.setOptions(this.options);timeline.setGroups(this.groups);timeline.setItems(this.items);

Looking at the documentation I see I can enter HTML as content on items and groups I would like for those to be nicer so I’ll edit the content on items and groups to be:

items:From:{id: 1, content: “Item 1”, start: ‘2020–04–01 10:00:00’, end: ‘2020–04–01 11:00:00’, group: 1},To:{id: 1, content: “<span style=’font-size:9px; margin:0; padding: 0 0 0 0'>Apr 4, 2020 10:00</span> <p style=’margin:0; padding: 0; line-height: 0.8;’>item 1</p>”, start: ‘2020–04–01 10:00:00’, end: ‘2020–04–01 11:00:00’, group: 1},Groups:From:{id:0,content: ‘Group 1’},To:{id:0,content: “<div style=’float:left; margin-right: 10px;’><img src=’https://picsum.photos/400' style=’border-radius:50%;’ width=’60em’></div>” +“<div style=’float:right;’><p style=’margin: 0'>Casper Bottelet</p>” +“<span style=’font-size:11px; font-weight: 300; font-color:#eee;’>Management<span></div>”,style: ‘width:200px’},

So this is what we got so far entirely:

<template><div class=”wrapper”><p>Timeline test 2</p><div id=”visualization”></div></div></template><script>import { Timeline } from ‘vis-timeline/standalone’;export default {data() {return {items: [{id: 1, content: “<span style=’font-size:9px; margin:0; padding: 0 0 0 0'>Apr 4, 2020 10:00</span> <p style=’margin:0; padding: 0; line-height: 0.8;’>item 1</p>”, start: ‘2020–04–01 10:00:00’, end: ‘2020–04–01 11:00:00’, group: 1},{id: 2, content: ‘item 2’, start: ‘2020–04–01 09:00:00’, end: ‘2020–04–01 10:00:00’, group: 0},{id: 3, content: ‘item 3’, start: ‘2020–04–03 08:00:00’, end: ‘2020–04–03 10:00:00’, group: 1},{id: 4, content: ‘item 4’, start: ‘2020–04–02 08:00:00’, end: ‘2020–04–02 10:00:00’, group: 1},{id: 5, content: ‘item 5’, start: ‘2020–04–02 08:00:00’, end: ‘2020–04–02 10:00:00’, group: 0}],groups: [{id:0,content: “<div style=’float:left; margin-right: 10px;’><img src=’https://picsum.photos/400' style=’border-radius:50%;’ width=’60em’></div>” +“<div style=’float:right;’><p style=’margin: 0'>Casper Bottelet</p>” +“<span style=’font-size:11px; font-weight: 300; font-color:#eee;’>Management<span></div>”,style: ‘width:200px’},{id:1,content: “<div style=’float:left; margin-right: 10px;’><img src=’https://picsum.photos/400' style=’border-radius:50%;’ width=’60em’></div>” +“<div style=’float:right;’><p style=’margin: 0'>Hans Eriksen</p>” +“<span style=’font-size:11px; font-weight: 300; font-color:#eee;’>Product Owner<span></div>”,// Optional: a field ‘className’, ‘style’, ‘order’, [properties]},{id:2,content: “<div style=’float:left; margin-right: 10px;’><img src=’https://picsum.photos/400' style=’border-radius:50%;’ width=’60em’></div>” +“<div style=’float:right;’><p style=’margin: 0'>Marc Anksen</p>” +“<span style=’font-size:11px; font-weight: 300; font-color:#eee;’>Programmer<span></div>”// Optional: a field ‘className’, ‘style’, ‘order’, [properties]}// more groups…],options: {orientation: “top”,itemsAlwaysDraggable:true,timeAxis: {scale: ‘hour’, step: 1, },zoomMax: 150000000,//for days 7 instead of 6?minHeight:’500px’,start: ‘2020–04–01’,hiddenDates: {start: ‘2020–03–04 18:00:00’,end: ‘2020–03–05 06:00:00’,repeat: ‘daily’},editable: {add: true, // add new items by double tappingupdateTime: true, // drag items horizontallyupdateGroup: true, // drag items from one group to anotherremove: true, // delete an item by tapping the delete button top rightoverrideItems: false // allow these options to override item.editable},onUpdate: function (item, callback) {item.content = prompt(‘Edit items text:’, item.content);if (item.content != null) {callback(item); // send back adjusted item}else {callback(null); // cancel updating the item}},onMove: function (item, callback) {console.log(item, callback)if (item.content != null) {callback(item); // send back adjusted item}else {callback(null); // cancel updating the item}},}}},mounted() {// Create a Timelinelet timeline = new Timeline(document.getElementById(‘visualization’));timeline.setOptions(this.options);timeline.setGroups(this.groups);timeline.setItems(this.items);}}</script><style>/* alternating column backgrounds */.vis-time-axis .vis-grid.vis-odd {background: #f5f5f5;}/* gray background in weekends, white text color */.vis-time-axis .vis-grid.vis-saturday,.vis-time-axis .vis-grid.vis-sunday {background: gray;}.vis-time-axis .vis-text.vis-saturday,.vis-time-axis .vis-text.vis-sunday {color: white;}.vis-item {background-color: #d6e6ff;border-color: #1371fe;color: #0155d3;border-left-width: 3px;border-left-style: solid;font-weight: 500;opacity: .8;font-size: 13px;height: 55px;}</style>

Part 3 Getting and updating data from and to the

--

--