Using ASP.NET Core and Vue.js to dynamically switch content of site
I debated a long time with myself on whether or not I really need some kind of javascript library for TeamScreen. In the end, I decided, that in fact, I do need it – just because the code will be simpler. Keep in mind that TeamScreen it’s still a pretty much static website, that’s why I won’t be using stuff like Webpack or more and more popular React. TeamScreen is not an application that needs those kinds of sophisticated JavaScript libraries. Instead, I’ll use Vue.js. I’ll like to call it a simpler Angular – it is powerful and lets you create advanced applications, but code produced is much lighter than this you can find in Angular and you don’t have to complicate compilation process like it is with React and its JSX files.
I planned to use also Typescript, but a quick glance at setup instruction proven me, that I’ll spend more time configuring it, than writing in it, so again, for TeamScreen it is just not worth it.
My plan for TeamScreen was to have one plugin per page and change active page after given interval. I also wanted to have some degree of control over this mechanism, so the user can go to next/previous plugin or pause on the current for a while. I’ve added a ContainerController with just empty Index method and corresponding view:
1 2 3 4 5 6 7 8 9 10 |
<div id="app"> <div id="contentContainer"></div> <div class="controls"> <i class="fa fa-chevron-left" aria-hidden="true" v-on:click="loadPreviousPlugin"></i> <i class="fa fa-pause" aria-hidden="true" v-if="!paused" v-on:click="pause"></i> <i class="fa fa-play" aria-hidden="true" v-if="paused" v-on:click="resume"></i> <i class="fa fa-chevron-right" aria-hidden="true" v-on:click="loadNextPlugin"></i> </div> </div> |
As you can see it’s really simple. div with id ‘app’ is a hook element for Vue, ‘contentContainer’ is a placeholder for plugin content and I also have some controls using font awesome library for icons and v-on:click directive from Vue to hook up event handlers for left click on given element.
Another part of Container’s Index view is Vue view model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
var vm = new Vue({ el: "#app", data: { index: 0, availablePlugins: ['@Url.Action("Content", "Jira")', '@Url.Action("Content", "TeamCity")'], interval: 60, paused: false, timer: 0, }, methods: { loadPreviousPlugin: function () { if (this.index > 0) this.index--; else this.index = this.availablePlugins.length - 1; $("#contentContainer").load(this.availablePlugins[this.index]); }, loadNextPlugin: function () { if (this.index < this.availablePlugins.length - 1) this.index++; else this.index = 0; $("#contentContainer").load(this.availablePlugins[this.index]); }, pause: function() { this.paused = true; }, resume: function() { this.paused = false; }, tick: function () { if (this.paused) return; this.timer++; if (this.timer == this.interval) { this.loadNextPlugin(); this.timer = 0; } }, handleKeyboard: function (event) { if (event.keyCode === 32) //space this.paused = !this.paused; else if (event.keyCode === 37) //left arrow this.loadPreviousPlugin(); else if (event.keyCode === 39) //right arrow this.loadNextPlugin(); event.preventDefault(); }, }, mounted: function() { this.loadNextPlugin(); $(document).keydown(this.handleKeyboard); setInterval(this.tick, 1000); } }); |
I really like Vue’s separations of concerns in the code. Going from the top I have el directive which tells us to what element in DOM, hook up the code. After that, we have data element which contains all data properties of view model and their initial values. Next is the methods element containing all the functions of the view model. At the end we have mounted function – it’s a function that will be called after view model is created and hooked up to the corresponding element in DOM tree.
The logic here is – after view model is created load first plugin, enable keyboard support using handleKeyboard function and using standard Javascript’s setInterval method call tick every second. In tick, if the execution isn’t paused we increase timer variable and if it matches interval we load next plugin. I handle time by second especially for the ability to pause it in any given moment. loadNextPlugin method uses jquery load function to replace HTML content at given DOM node. It loads plugin from the list of availablePlugins containing information about URL address to specific plugins view. Right now all plugin’s controller’s return PartialView so they can be easily loaded into another web page.
Thanks to Vue I now have a simple system to dynamically load plugins and control their display. Hope you liked today’s post and see you next time!