Make a Quote Generator using Vue: Part 1

Vue is one of the frameworks that’s often talked about (and compared with) Angular and React. These comparisons are often not very helpful and leave you more confused than before.

To correctly and fully understand what a framework can do for me I prefer trying it out first hand. And that’s what we’re here to do today. We’re here to get understand what Vue can do us. And don’t worry, we will not going to through endless pages of documentation. We’ll use it to make an app. I believe in learning by doing and so to start learning Vue we’ll create a simple quote generator app. This app will be very similar to Behappy.me’s quote generator.

demo image of quote generator

 

Note: If you are already familiar with Vue and would just like to learn about the quote generator, skip to the end of this part, copy the HTML, CSS from Setting up HTML section, and js from Preparing Data section below. You can then proceed to the next part. I’d still suggest you go over this part as well – it’ll hardly take a couple of minutes and you’ll learn a thing or two.

The first step would be to list the main components of Behappy.

Quote Generator’s components

  1. The input field for your quote and its author
  2. A selection mechanism for font and background color (I’m skipping the stamps for now but they shouldn’t be too different from what we do for font and background color)
  3. Live preview

That’s all the components. Now, that we know what we need to include let’s see how to do it. It’s time to launch our editors, get some coffee, and get ready for magic on your screen!

Including Vue JS

First, include Vue JS into your project. You can do this by adding https://cdn.jsdelivr.net/npm/vue’ within script tag in the head of your document. I know it is a better practice to include all scripts before the end of the body. But Vue JS is the hero of our project. I want to ensure that I have it loaded before anything else. Moreover, our project is going to be very small so it hardly makes any difference.

Setup for a Vue project

Include a div with an id of ‘app’.  Inside your javascript, create a Vue object called app. include a property el: ‘#app’.

Notice how the value of el is the id of the div you created. What this does is, it allows the div #app and all it’s children to communicate with the data in the Vue object called app.

Don’t worry, It’s not as complex as it sounds. We’ll discuss it in detail in the next step. For now, make sure that your code looks something like this.

<body>
    <div id = "app"></div>
    
    <script type="text/javascript>
        var app = new Vue({
            e1: '#app',
        });
    </script>
</body>

 

Binding with Vue

For understanding what I meant in the previous step, let’s add a textarea and include attribute v-model = “message”. This is what they call a directive in such frameworks. For angular these directives start with ng-, for Vue, they start with v-. Think of directives are power-ups for your HTML. These are used to make your HTML do smart things.

Now create a div and add {{message}} inside it.

The last thing to do is, inside our app object, create a new item called data. This is a Vue specific object property. Vue refers to this for any data that may be used within your HTML element specified as el. Inside data, let’s add message: ‘test message’

 

<div id = "app">
    <textarea v-model="message"></textarea>
    <div>{{message}}</div>
<div>
<script type="text/javascript>
    var app = new Vue({
        e1: '#app',
        data: {
            message: 'test message',
        }
    });
</script>

 

If you launch your project you should see ‘test message’ inside the text area and as the content of the div. Interesting, right? Vue has taken the value of message from data and passed it on as a form value inside the textarea using v-model and the content of the div.

All you did was use the directive v-model in your textarea, set {{message}} as the content of your div, and added message to your data object. Vue has tied them all together. This is going to be helpful in our app that has ‘live preview’. Changing the quote or background color will update the preview.

If you’re wondering – this binding works both ways. If you were to change the value of the message property the value of the textarea and the div would update too! Go to you Developer’s console, type app.message = “Vue is awesome!” and hit enter. Voila! the text in the textarea and the div changed too. This kind of two way binding is one of the salient features of Vue. When using Vue you no longer have to worry about keeping your variables up-to-date or accepting values from the input. The values are automatically updated.

Now that we know how the binding works let’s get the data ready. Once that’s in place all we’ll need to do is bind it to our HTML using Vue directives.

 

Step 1: Preparing data

We need a default message that will hold the quote, author’s name, background and font colors, and font styles. Apart from these, we’ll also set up properties for currentBackgroundColor, currentFontColor, currentFont. You’ll understand why we need these as we go along.

var app = new Vue({
    el:'#app',
    data:{
        message:'To live is the rarest thing in the world. Most people exist, that is all.',
        author:'Oscar Wilde',
        currentBackgroundColor:'#FFFFAA',
        currentFontColor:'#888888',
        currentFont:'Shadows Into Light',
        themes: [
            { backgroundColor:'#FFFFAA', fontColor:'#888888'},
            { backgroundColor:'#F1A9A0', fontColor:'#FFFFFF'},
            { backgroundColor:'#E4F1FE', fontColor:'#888888'},
            { backgroundColor:'#A2DED0', fontColor:'#FFFFFF'},
            { backgroundColor:'#FDE3A7', fontColor:'#888888'},
        ],
        fonts: [
            'Shadows Into Light',
            'Permanent Marker',
            'Kaushan Script',
            'Great Vibes',
            'Courgette'
       ]
    }
});

You may choose different values for colors and fonts. That does not affect the implementation in any way. Notice how the backgroundColor and fontColor are clubbed as a single unit. This allows you to pair a specific background color with a specific font color – avoiding cases where text me be illegible (imagine black text over black background).

Also, don’t forget to include the fonts you wish to use in your quote generator. If you want to go with the ones I have used then just add the following to the head of your document.

<link href="https://fonts.googleapis.com/css?family=Courgette|Great+Vibes|Indie+Flower|Kaushan+Script|Permanent+Marker|Shadows+Into+Light" rel="stylesheet">

With our data ready, the next step is to set up our HTML.

Step 2: Setting up HTML

Nothing fancy here. You can simply copy-paste the code from below. I have not included any directives yet because I’d like to go over each one individually so you understand it better.

<div id="controls">

    <h1>Enter Quote</h1>

    <textarea id="inputQuote" spellcheck="false" maxlength="80"></textarea>

    <input id="inputAuthor" type="text" spellcheck="false" maxlength="20">


    <h1>Select Font</h1>

    <ul class="optionsList" id="fontsList">

        <li> //font options to be displayed here </li>

    </ul>


    <h1>Select Color</h1>

    <ul class="optionsList">

        <li> //background color options will appear here </li>

    </ul>

</div>


<div id="preview">

    <div id="main">

        <div id="quote"> //the message updates here </div>

        <div id="author"> //author's name updates here </div>

    </div>

</div>

 

Step 3: Some CSS

Also, just so the project is easier to work with, here’s the CSS for it. If you’d like to write up your own, that’s great.  But for those of you who want to focus on VueJS, for now, copy-paste the CSS in your stylesheet.

body{
    border: 0;
    font-size: 100%;
    vertical-align: baseline;
    line-height: 1;
    font-family: Arial, Helvetica, sans-serif;
}

#app{
    display: flex;
    justify-content: space-around;
}

#inputQuote{
    width: 300px;
    height: 50px;
    padding: 15px;
    display: block;
    font-family: Arial, Helvetica, sans-serif;
    margin-bottom: 15px;
    resize: none;
}

#inputAuthor{
    width: 300px;
    padding: 15px;
    margin-bottom: 15px;
}

.optionsList{
    display: flex;
    list-style: none;
    padding: 0px;
}

.optionsList li{
    width: 100px;
    height: 40px;
    margin: 10px;
    padding-top: 10px 0 0 10px;
}

#fontsList li{
    border: 1px solid
}

#main{
    width: 400px;
    height: 400px;
    padding: 20px 40px;
}

#quote, #author{
    max-width: 100%;
    font-family: inherit;
    font-size: 4vw;
    margin: auto;
    text-align: left;
    word-wrap: break-word;
    margin-bottom: 15px;
}

#author{
    font-size: 2vw;
}

Conclusion

We’ve see how Vue let’s the data in our Vue object communicate with our HTML. In the next part, we’ll learn about various Vue directives to auto-populate values of background color and font in our HTML, and add inline styles and interaction. See you there!

Make a Quote Generator using Vue: Part 2

In the previous part, we learned about how data defined in a Vue object can be used inside our HTML. We then went on to include values for font family and background color in our Vue object. We set up our basic HTML and CSS.

In this part, our task is to help our HTML interact with our data. We can do this by using Vue directives. Let’s see how it is done.

Step 4: Vue’s v-model directive

Let’s go ahead and get over with the most obvious ones – message and author. In the previous part, we discussed how v-model can be used to bind data for form elements. All you have to do is include v-model=”message” for the textarea and v-model=”author” for the input field. Type {{message}} inside the #quote div and {{author}} inside the #author div within #preview.

 

<div id="controls">

    <h1>Enter Quote</h1>

    <textarea v-model="message" id="inputQuote" spellcheck="false" maxlength="80"></textarea>

    <input v-model="author" id="inputAuthor" type="text" spellcheck="false" maxlength="20">

</div>
.
.
.

<div id="preview">

    <div id="main">

    <div id="quote"> {{ message }} </div>

    <div id="author"> {{ author }} </div>

</div>

To test it out, type in a message or author’s name. The text should update in the Preview section on the right. Once you’ve made sure that it works well, move on to the next part.

Step 5: Vue’s v-for directive

Let’s populate our list of fonts. Vue has a directive v-for that can help us out here. Think of v-for as a for loop for HTML. To use it include v-for=”font in fonts” in the li tag of #fontsList as shown below

<ul class="optionsList" id="fontsList">
    
    <li v-for="font in fonts">{{ font }}</li>

</ul>

Here, font is the iterator and fonts is the name of the data array. {{font}} displays the current iterator’s value i.e. the font’s name inside the li tag. Just like {{message}} displayed the message text inside the #quote div.

An improvement over this would be to display these font labels in their respective font styles. We can do that by setting styles for each li tag inline. v-bind:style let’s us to specify inline styles for an HTML element.

 

<ul class="optionsList" id="fontsList">
 
    <li v-for="font in fonts" v-bind:style="{fontFamily: font}">{{ font }}</li>

</ul>

 

v-bind:style takes the value of an iterator and assigns it to the fontFamily for each li tag. I’d like to take a minute and appreciate how simple and elegant this is. Trying to achieve this in a traditional way would mean applying styles separately to each li or using JS to apply styles to each li. In contrast, Vue let us apply styles to an element while rendering it – all in a single line.

We can use v-bind:style to list our background colors as well. You can update the li for background colors like so

<ul class="optionsList">

    <li v-for="theme in themes" v-bind:style="{backgroundColor: theme.backgroundColor}></li>

</ul>

theme contains two properties – backgroundColor and fontColor. We use theme’s backgroundColor property and assign it to the style backgroundColor. This should list all of you background colors.

Our next step will be to set the font family, background color, and font color for our preview. This is where currentBackgroundColor, currentFontColor, and currentFont we defined in our data, will be used. We’ll use the v-bind:style, again, to do this.

<div id="main" v-bind:style="{backgroundColor: currentBackgroundColor,

color: currentFontColor,

fontFamily: currentFont}">

    <div id="quote">{{ message }}</div>

    <div id="author">- {{ author }}</div>

</div>

Launch your app again and check if everything is working fine. Let’s go ahead and add a way for this app to update to user’s selection.

Step 5: Adding interaction

In the previous step, we defined the styles for preview using the currentBackgroundColor, currentFontColor, and currentFont properties. These properties are defined in our data and so Vue will react to and re-render and relevant HTML, if these properties are changed.

So, we’ll need to somehow update the values of currentBackgroundColor, currentFontColor, and currentFont properties based on user’s selection. We don’t need to do this for message and author because the v-model directive handles it for us. It’s designed specifically with the intention of keeping the app aware of the freshest form data.

For non-form elements, we can use v-on:click. In your li tag for fonts add v-on:click=”currentFont = font”.

<ul class="optionsList" id="fontsList">
    <li v-for="font in fonts" v-bind:style="{fontFamily: font}" v-on:click="currentFont=font">
        {{ font }}
    </li>
</ul>

This tells the app to set the currentFont to the font value for that li tag when the user clicks on it. Try it out, when you click a font option the font in the #preview should update instantly. Similarly, we can update the code for background color.

<ul class="optionsList">
    <li v-for="theme in themes" 
        v-bind:style="{backgroundColor: theme.backgroundColor}
        v-on:click="currentBackgroundColor=theme.backgroundColor, currentFontColor=theme.fontColor"></li>
</ul>

Notice that we set the currentBackgroundColor and the currentFontColor here. Again, test it out. Works brilliantly, doesn’t it? You quote generator with a live preview is now ready.

Next Steps

You’ll agree that this still is a very basic quote generator. Even though we’ve mostly achieved what Behappy does, I’m sure you can think of ways to improve it. How about adding those stamps we left out at the beginning. Small hint: try using Font Awesome (or your favorite icon font) for this (instead of images). Icon fonts will render better and it’ll essentially be like loading text instead of trying to manage image icons. If you want to allow your users to download their quote as an image, check out html2Canvas created by Niklas von Hertzen. It’s an amazing library that takes your HTML elements and adds them to an HTML canvas. You can use this canvas to download its contents as an image.

Conclusion

We’ve created a very simple project and it does not even begin to measure Vue’s full capabilities. Vue has a lot more to offer. From conditional rendering, to state transitions, to custom directives – the list just goes on. And their documentation is full of detailed explanations and examples. Don’t forget to check it out.

I will not compare Vue with Angular or React because I don’t think it would be fair. They all have features that set them apart and they may have limitations that might undesirable for your project. The best way to asses this is to test it yourself.