Single Page Apps with Vue.js and Flask: Setting up Vue.js

Setup and Getting to Know Vue.js

Introduction

This is the opening post to a tutorial series on using Vue.js and Flask for full stack web development. In this series I am going to demonstrate how to build a survey web app where the application architecture consists of a front-end comprised of a Vue.js Single Page Application (SPA) and a backend REST API using the Flask web framework.

This first post will cover basic project setup and structure, using the Vue.js v-for directive, and component lifecycle stages.

Series Contents

Frontend setup with vue-cli and webpack

I will be using two very important tools for a Vue.js project, which are the official Vue.js command line interface (CLI) and the very powerful module bundler and build tool webpack. Both of these tools rely on the Node.js runtime and its package manager, npm. If you have not already installed node then please consult the Node.js installation docs for your system, which will also include an installation of npm.

Install the Vue.js CL (vue-cli):

$ npm install vue-cli -g

Now with the CLI installed I will use it to initialize a Vue.js SPA application. The CLI does the following:

Install and configure webpack to bundle my code

Install a development server with hot-reload (server auto-restarts when a file is changed)

Add a dependency for vue-router

Scaffold out a basic Vue.js SPA file structure

I first create a high-level folder which will contain all the code for this tutorial named "survey". Next I make two more directories called "frontend" (for the Vue.js SPA) and "backend" (for developing the REST API) then change my working directory to the frontend directory.

This likely seems a bit overwhelming the first few times you look at it, but fear not we only really need to concern ourselves with the files under the src/ directory, plus the index.html file. Of course the other files are important and perhaps some day I will get into what they are used for, but for now just ignore them.

Files under the src/ directory are where I will be writing the code to drive the functionality of the application. Let us open these files up and get an idea for what is going on.

This is the only HTML file that a Vue SPA utilizes and it rarely contains much more than what is shown above with the exception that sometimes you will link to CSS frameworks and other JavaScript libraries within this file. The lone div element that is produced with a default id of "app" is what the main Vue instance will attach to. That Vue object injects the HTML and CSS that are in the components, to be discussed later, into the div to produce the UI.

The main.js file is the primary entry point for the application and is where you will register the Vue instance and extensions such as vue-router and vuex. As you can see this is where the Vue instance resides. The instance is registered to the app div discussed previously, plus it is fed the router object and the high-level App component.

The App.vue file serves as the top level application components and often contains the general layout of the application. Vue components have a specific structure containing a <template> section for component-specific HTML, a <script> section to define the Vue object and that component's behaviors implemented in JavaScript, and a <styles> section for CSS / SCSS rules. That last bit can be a bit confusing though because by default the style rules you define in a component do not just pertain to that component. They actually affect all the elements in the entire project unless you add a scoped attribute to the <style> element.

The index.js script in the router directory is where the URLs for the application are defined and mapped to components. The first two lines import the Vue and Router objects, which are then linked by the use method on the Vue object.

The default route that is provided from the vue-cli webpack template is simply the root or index route for the application, which servers up the HelloWorld component. To map a route path to a component it first has to be imported, then you need to define a route object in the routes array giving it a path, a name, and the component to be displayed.

The "components" directory is where UI components reside. The HelloWorld component above again contains the three basic sections template, script, and style which all have some example content from the vue-cli initialization template.

Take a look at the contents of the script section. Here you will see that an object is being exported. This object will get injected into the Vue instance that was initialized in the main.js file. Inside this JavaScript object is a data method which returns an object. This object is where you can place component-level state (data) and in this example it's a single property called msg.

You can access and display your component state by its property name within the HTML in the template section. In the example provided you see this as {{ msg }}. The double curly brackets are the default template syntax for doing text interpolation and is inspired by the Mustache template system. Any time you want to display data in the HTML of your component wrap it in double curly brackets.

Bringing in Some Style

To give this app a little better curb appeal I will be using the Bulma CSS framework. The aim of this tutorial will not be on how to use Bulma, but I still want to include it to stave off the drab look of unstyled HTML.

Back in the terminal in the same directory as the package.json file install and save bulma to the project with the following command:

$ npm install --save bulma

In addition, I will need to install some dev tools to properly load the styles for the application so the components know how to work with them. To do this, npm install these additional packages.

Now open up App.vue and replace the style section with what is below, which will import the bulma framework using scss import syntax.

<style lang="scss">
@import '~bulma/bulma'
</style>

Give it a Home (page)

Ok, now that we have a basic understanding of the structure and main parts of a Vue.js SPA application I can start writing code.

Start by renaming the HelloWorld.vue file to Home.vue and then clear out the contents of the template, script, and style sections. Also, in App.vue remove the line for the Vue image logo <img src="./assets/logo.png"> and clear out the contents of the <style> element while your in there. Lastly, open up router/index.js and import the component Home.vue instead of HelloWorld.vue and update the route object to use the Home component.

This gives us some dummy data to work with. As you can probably tell it represents two surveys, one about dogs and another about cars. The data will provide the drive behind the HTML we are about to write by providing content to display.

Now in the template section I will add a div which will wrap all my other elements. Every Vue component must have a single parent element, there cannot be top-level sibling elements or the component will not compile. Inside this div I will add a section for a Bulma hero header.

Below the header will be another section for displaying the name of each survey and the date it was created. It is in this block of HTML where we will start to see some of the awesomeness that is provided by Vue.js.

Save any unsaved files in the project and refresh your browser, which should now appear as shown below:

As you can see in the screenshot there are two survey Bulma cards being displayed. These two surveys map to the array of survey objects that were in my data function of my Home component, which I fed into my HTML using the v-for directive.

Take a look again at the below subsection of the original template code, which represents a survey. This whole element and its children are being repeated once for each survey in the surveys array. Basically, the data is driving the generation of HTML.

The v-bind:key part is adding an attribute called key equal to the survey's id to each div with class "card". Vue uses these keys to keep explicit track of each node being created in the DOM which aids in bookkeeping and performance. It is recommended to always set a unique key to the outermost element being used in conjunction with a v-for directive.

The v-for directive uses a syntax of item in items where items is an iterable such as an array or an object's properties and item is an alias for each element in the iterable. However, there are variations of this syntax, which allows for greater flexibility and control.

For example, say I had an array of letters var letters = ['a', 'd', 'a', 'm'] that I wanted to use to drive the creation of a regular ole HTML unordered list that displays each letter and its corresponding index. Well that could be done with this variation of v-for:

• Index position 0 has letter a
• Index position 1 has letter d
• Index position 2 has letter a
• Index position 3 has letter m

To iterate over the properties of an object the syntax is quite similar. Given an object such as var person = { name: 'adam', occupation: 'software developer', residence: 'lincoln, nebraska' }, iterating with a v-for directive would look like this:

Mocking an AJAX Request for Surveys

I have my first functional UI component displaying a collection of surveys, but in the end the actual application will need to fetch survey data from our REST API. To make this a bit more realistic I would like to mock out the functions for an AJAX request to feed the Home component surveys.

In the src directory create a new folder called "api" then add a script called index.js within it. This is where I will mock out my AJAX functions. In this new file cut and paste the surveys array from the Home.vue component as a global constant.

Below this array of surveys create a function called fetchSurveys which returns a promise with the array of surveys after waiting 300 milliseconds (to simulate the API delay). The function will need to be exported so that it can be accessed from the Home component.

Vue components have a series of defined lifecycle stages that are meaningful to the developer when doing various things such as pulling in data using an AJAX request. In order to feed survey data into the Home component I will need to hook into one of the Vue lifecycle stages, specifically the beforeMount stage. There are several other stages that are useful for many more things than just AJAX requests, but I defer to the official Vue.js docs for a details explanation.

The beforeMount lifecycle stage works well for the API call because it is executed right before the mounting of our component begins, and right before render is called on our component. This gives it time to fetch data before being displayed to the user.

To take advantage of the beforeMount stage of the Home component all I need to do is add it as a new method to the component's Vue object. Inside this function I will make a call to my fetchSurveys function and assign the returned surveys to the surveys data property.

Conclusion

This post has covered the basics of setting up a Vue.js SPA application with vue-cli using the webpack template. In addition to project setup I covered how to use data in the form of an iterable to dynamically generate UI content using the powerful v-for Vue.js directive. For the last major topic I hit on component lifecycle stages and how the beforeMount stage can be useful in loading data into a component with a mock AJAX request.

Next post I will be covering how to use the vue-router extension to flow from one page to another giving our application a workflow concept. The code for this tutorial can be found at my GitHub account which contains a branch for each post. Thanks for reading and please feel free to comment or critique below.