Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Vue.js Tutorial: Build a Tesla Battery Range Calculator

DZone 's Guide to

Vue.js Tutorial: Build a Tesla Battery Range Calculator

Get started building robust UIs with Vue.js.

· Web Dev Zone ·
Free Resource

close-up-of-front-of-red-tesla-in-parking-gara


This tutorial focuses entirely on the new driving experience. It is now clear that electric driving is the future. But how far can you actually ride on a full battery? And what influence does the speed, outside temperature, and size of the rims have on the range, for example? In this tutorial, we get started with Vue.js, an easy-to-understand JavaScript framework. We are going to make a dashboard with which we can calculate how much range the Tesla has under different circumstances.

Figure 1

As a starting point for the tutorial, clone this Github repository.

You may also like: Hello Vue: A Quick Tutorial on Getting Started With Vue.

Then, move to the vuejs-app directory.  

cd workshop-reactjs-vuejs/vuejs-app


Read the README.md for the tasks to be executed. The figure above is an example of the application that we are going to build. We initially start from a buggy application, which we must fix and further develop. Before we get started, I first explain how this application is structured.

Requirements

To start with this tutorial you must install the following:

  • Stable node version 8.9 or higher (https: // nodejs.org/en/download/).

  • Yarn (https://yarnpkg.com).

Project Structure

The project we are working on has the same structure as the aforementioned figure and shows the components that make up this application. The main.js is the entry point of the application. App.vue is the entry component of the application. The outer edge of the figure above shows the App.vue component.       

Project Entry Point

A Vue application is started in  main.js. In main.jsyou first create a new "root Vue instance." This goes as follows:

1. Import Vue: import Vue from "vue."Importing vue from Vue module

2. Import an entry component App.vue, through: import App  from "./App. vue ".

3. Create a "root Vue instance":  new Vue ({....}).

4. From this "root Vue instance," render the imported App.vue component (entry component).
render: h => h (App).

5. Finally, this root Vue instance is mounted. This is the point where the application is started. This refers to an HTML element with the identification #app, which is defined in the template in the  App.vue component. (See the code snippet in the section below.)

App.vue Component 

This App.vue is the entry component of the application and consists of the following parts.

Script: this is the JavaScript part of this component. In this example, the name property indicates the name of the component (the name is “app”). The child components that this component uses are defined in the components-property. In this case, TeslaBattery is a child component of the App.vue component. To use the TeslaBattery component, it must first be imported ( import Tesla-Battery from  "..." ).

In the data()-function, you can define and initialize state variables, such as the imported logo and the greeting property. To render the logo and the greeting, they must be defined in the template. You must eventually export this entire component (via  export default { }  ), so that it can be imported again into other components and into main.js.

Template: is responsible for defining the output that the component generates. Vue.js uses an HTML-based template syntax. Data from the data ()-function can be easily rendered through data binding. The simplest form of data binding is text interpolation using the Mustache syntax (double braces): {{greeting}}  

In the example above,{{greeting}}  is replaced by the value Hello Tesla !!! from the relevant  data()-function. Above this greeting, the logo is also rendered thanks to the img-tag. To assign the logo to the img src-attribute, use attribute binding. For this, you can use v-bind,   <img :src="logo", or   <img v-bind:src="logo">. Attribute binding is often used in this application.

And finally, the TeslaBattery component is instantiated and rendered using the <tesla battery>-tag. For this tag (also called "custom element"), you must use the Kebab case. How this component functions will be discussed later.

Style: in Vue, we use a SCSS file for styling the entire application.

Breaking Down the UI 

Almost all Vue applications consist of a composition of components. This application consists of an entry App component with the TeslaBattery as a child component. And the TeslaBattery component contains the following child components:

  • TeslaCar: for rendering the TeslaCar image with wheel animation.

  • TeslaStats: for rendering the maximum battery range per Tesla model. This concerns the models: 60, 60D, 75, 75D, 90D and P100D.

  • TeslaCounter: for manually controlling the speed and the outside temperature.

  • TeslaClimate: this changes the heating to air conditioning when the outside temperature is more than 20 degrees.

  • TeslaWheels: for manually adjusting the wheel size from 19 inches to 20 inches and vice versa.

The user interface is represented by a component tree as follows.

The following code block shows that the "Tesla Battery component" is a Container component. The underlying child components are Presentation components. This is a useful pattern that can be used when developing a Vue application. Dividing components into two categories makes them more reusable.

Container components are characterized by the following: 

  • They can contain both presentation and container components.

  • They take care of the creation and transfer of data to child components through "props."

  • They execute logic based on incoming events.

  • They are responsible for managing the state and know when a component must be rendered again.

  • They are often stateful because they tend to serve as data sources.

Presentation components are characterized by the following:

  • They are also called "dumb components." The focus is on the user interface. Almost all basic UI components must be regarded as dumb components. Examples of this are buttons, inputs, modals, etc. 

  • The TeslaCar is also a dumb component, which ensures the rendering of the TeslaCar image.

  • They receive data via "props" and return data to parent components through an event.

  • They are often stateless and have no dependence on the rest of the application.


This approach has the following advantages:

  • Reusability.

  • Dumb components are easier to test because they only receive "props," emit events, and return a piece of UI.

  • Higher readability: the less code you have and the better it is organized, the easier it is to understand and adjust.

  • It offers consistency and prevents code duplication.

TeslaBattery service 

The data we use is hard-coded and stored in tesla-battery.service.js. This service has a  getModel-Data() method for retrieving the model data. View the structure of this model data in code block below. 

The maximum battery range per Tesla model is determined based on the following parameters:

  • Tesla model (60, 60D ...).

  • Wheel size (19/20 inch).

  • Climate (on / off).

  • Speed.

  • Temperature ( -10.0 ...).

TeslaBattery component 

This component is responsible for defining, creating and passing data to child components through "props." It is also responsible for managing the state of the application.

When fully collapsed, we see that this component consists of the properties below.

The components property contains all child components that this component uses.

The computed property contains the functions that are cached. That is, such a function is only executed if it depends on a specific data property and when the state of this property changes. In the full version of the TeslaBattery component below, the stats()-function is an example of a computed function.

This function filters the maximum battery range per Tesla model from the model data. The code block below is an example of the output of the stats()-function. This maximum battery range is based on user input, such as the selected wheel size, climate, speed, and temperature. And this stats()-function is only executed if this user input changes. The user input is recorded in the tesla object (state object), which is defined in the data()-function.

Maximum battery range per model: 

[

  {"model":"60","miles":267},

  {"model":"60D","miles":271},

  {"model":"75","miles":323},

  {"model":"75D","miles":332},

  {"model":"90D","miles":365},

  {"model":"P100D","miles":409}

]


The methods property contains all of the functions that are not cached. The changeClimate() function is defined here because this function is triggered by an onClick-event (and is not based on a data/state property).

The template of this TeslaBattery component has the same structure as the fourth code block. 

Passing Data to Child Components Through Props

In the following figure, stats-data (originating from the stats()-function) is passed from the TeslaBattery component to the TeslaStats component.

To pass data to a child component, you must use v-bind or  : in the template of the TeslaBattery component.

<template>    
    <form>       
        ...       
            <tesla-stats :stats="stats" />       
        ...    
    </form> 
</template>


Receive Data in the TeslaStats Component

This component contains a props-property in the scripts section for receiving the stats-data. These stats are of type Array. In the template we use a v-for directive from Vue.js, to iterate through the stats. The :key (in the v-for directive) indicates that this list must be rendered in a specific order.

You can define a custom filter in the filters-property. For example, the filter, "lowercase," with a pipe for rendering the model names in lowercase. There is also a custom filter defined for converting miles to kilometers.

Conclusion 

With this introduction, you can start solving bugs and carrying out assignments described in the README.md of this project. In this Github project a powerpoint has also been added, which elaborates on issues such as two-way data binding through the v-model directive, assigning an onClick event to a button with @click and creating other components.


Related Articles

Topics:
javascript ,web dev ,vue.js ,tesla ,ui component ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}