Cloudinary Blog

Getting Started with Vue JS: The Progressive JavaScript Framework

Getting Started with Vue JS: The Progressive JavaScript Framework

Vue.js is a progressive frontend framework which is the latest workflow and productivity trend. Its simplicity and approachability is what makes Vue.js outstanding among the pool of frontend frameworks. You may not be using Vue.js right now because you already know other JS frameworks and don’t want to learn another. But it’s important to keep in mind that a good framework is built to improve on the weaknesses of the existing ones. This is exactly what Vue.js has done.

The most challenging aspect of building a product with a front-end framework is focusing on the complexity of the tool rather than the complexity of the actual problem being solved. It’s perhaps more frustrating when the tool is complex but the problem is a simple one (e.g. complex webpack config for a todo app). The term progressive, is used by Vue.js to describe how this challenge can be mitigated. Building a basic demo or small app? Vue.js is simple enough to handle that. How about a complex enterprise app? Vue.js is capable of produce cutting-edge solutions, as well.

Vue.js is approachable, easy to learn and fast. In this article, we're going to get started with Vue.js by building a gallery app. A gallery app is simple, yet vast enough, to show you all the basic concepts in Vue.js that are applicable to any other framework you might have used

Webinar
How to Optimize for Page Load Speed

To get up and running quickly with image uploads and delivery to/from the cloud, we will utilize Cloudinary which is a natural choice. Cloudinary is a tool we have put together to assure you peace of mind when it comes to internet media. Ranging from upload to delivery, and most importantly, transformations that suit your needs, Cloudinary employs cutting edge engineering solutions to make this a painless reality.

Final Example

Preparing for Vue.js

To showcase how simple Vue.js is, we are going to build our demo using Codepen Project by importing a Vue.js script tag. No tooling for bundles or transpiling. Let's just write JavaScript.

Create a new Codepen project using the Vue.js template shown on the sidebar:

Codepen sidebar

This generates a new project with very few components and an entry point. We will clear most of the boilerplate code to make room for our gallery app logics:

Copy to clipboard
<!-- index.html -->
<html lang="en">
<head>

  <!-- Meta -->
  <meta charset="UTF-8" />
  <title>Vue.JS Grid</title>

  <!-- Styles -->
  <link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />
  <link rel="stylesheet" href="styles/index.processed.css">

  <!-- Scripts -->
  <script src="https://unpkg.com/vue@2.1.10/dist/vue.js"></script>
</head>
<body>

  <div id="demo">

  </div>

  <!-- Scripts -->
  <script src="/scripts/components.js"></script>
  <script src="/scripts/index.js"></script>
</body>
</html>
Copy to clipboard
// index.js

// Init Vue!
var app = new Vue({
  el: '#demo',
  methods: {

  },
  data: function() {
    return {
     thumbs: []
    }
  }
})

The Vue Instance

Vue is initialized using the Vue instance and passing all information about the app as object. The properties of this object is what defines how your app behaves and what data is bound to your app. Now, let's look at the three most popular properties:

  • The el property tells Vue where to mount the app instance in your HTML. That's why we have the div tag with a demo id.
  • data is a function that returns an object of data, which can be bound to the view as well as available in all the Vue methods via this. Two-way binding in Vue is achieved via the data object properties.
  • methods object is used to define methods that can be invoked from the view, as well as the Vue instance. This is the best place to put your event logic.

We will dig into details and see how these properties can be applied together to build a rich app.

Data Binding

To see how data can be bound to the view, let's return an object in the data function with a property of the object bound to the view:

Copy to clipboard
  <div id="demo">
    <input type="text" v-model="greeting" class="form-control" />
    {{greeting}}
  </div>
Copy to clipboard
var app = new Vue({
  el: '#demo',
  methods: {

  },
  data: function() {
    return {
     greeting: '',
    }
  }
})

This is a typical two-way data binding example. A data property, greeting, is bound to an input box (using v-model) and to a paragraph (using interpolation). When the value in the input box changes, the content of the paragraph will be updated with respect to the box.

Let's try something a bit more advanced:

Copy to clipboard
<div id="demo" class="container">
    <header>Awesome Gallery</header>
    <input type="text" v-model="greeting" class="form-control" />
    {{greeting}}
    <div class="row">
      <div class="col-md-4" v-for="thumb in thumbs">
        <div class="thumb">
          <img v-bind:src="thumb.url" />
        </div>
      </div>
    </div>
  </div>
Copy to clipboard
// Init Vue!
var app = new Vue({
  ...
  data: function() {
    return {
     greeting: '',
     thumbs: [
       {
         publidId: 'views',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493072225/views.jpg'
       },
       {
         publidId: 'dream-bikes',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493072159/dream-bikes.jpg'
       },
       {
         publidId: 'workstation',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493072107/workstation.jpg'
       },
       {
         publidId: 'reflection',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493072042/reflection.jpg'
       },
       {
         publidId: 'electricity',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493072006/electricity.jpg'
       },
       {
         publidId: 'cute-cat',
         url: 'https://res.cloudinary.com/christekh/image/upload/v1493071918/cute-cat.jpg'
       }
     ]
    }
  }
})

In an attempt to replicate a real life app, we have extended the previous example to include an array of images stored in my Cloudinary server. This time we can't just bind the array to the view. Rather, we iterate over each of the array items and bind them to the view. This iteration is achievable with the help of Vue’s built in template v-for directive.

Another new and important addition is the v-bind directive. Vue won't allow you to interpolate in attributes, therefore, the v-bind directive is made responsible for attribute bindings.

Methods and Event Handling

Static information makes apps less interesting; we can do better. Rather than having the input box greet us, let's make it more useful (I am not saying greetings are useless :D). We can use the input to add more image URLs to our array by using a clickable button to initiate the process:

Copy to clipboard
<div class="row">
  <divclass="col-md-9">
    <input type="text" v-model="thumb.url" class="form-control" />
  </div>
  <div class="col-md-3">
    <button class="btn btn-primary" v-on:click="addThumb">Add thumb</button>
  </div>
</div>

We updated the model from greeting string to thumb object with a url property to match the url property in the thumbs array's objects.

v-on is used to bind events in Vue. Therefore, we use that to bind a click event (v-on:click) to the button. This event should be handled by addThumb method.

Let's see the thumb property and the addThumb method:

Copy to clipboard
// Init Vue!
var app = new Vue({
  el: '#demo',
  methods: {
    addThumb: function() {
      this.thumbs.unshift(this.thumb)
    }
  },
  data: function() {
    return {
     thumb: {
       url: ''
     },
     thumbs: [
       ... 
      ]
    }
  }
})

Just as data properties live in the data function, methods live in the method object and are accessible from the template as we just saw.

Component Composition

Vue is a component-based and architected framework, which means that you can build reusable self-contained UI widgets and share them across your apps or even in external projects. For example, let's add a global component to display each of the thumbs:

Copy to clipboard
// components.js
Vue.component('thumb-item', {
  template: `
        <div class="thumb">
        <img v-bind:src="thumb.url" />
    </div>
    `,
  props: ['thumb']
})

Vue enables you to register the component using the component property in the Vue instance object argument. It also enables you to create a global component available everywhere in your app. We went with the latter option.

The component static method takes the name of the component and an object that describes the component. template, as you might have guessed, is the HTML we want rendered. props, on the other hand, is an array of properties we are expecting from whatever parent in which component is contained.

Let's use this component in our existing app. Change:

Copy to clipboard
<div class="row">
  <divclass="col-md-4" v-for="thumb in thumbs">
    <div class="thumb">
      <img v-bind:src="thumb.url" />
    </div>
  </div>
</div>

to:

Copy to clipboard
<div class="row">
  <divclass="col-md-4" v-for="thumb in thumbs">
    <thumb-item v-bind:thumb="thumb"></thumb-item>
  </div>
</div>

The component is identified in the template using the component's name.

Lifecycle Hooks

Another important topic to discuss in a Vue introduction is Vue's lifecycle hook. Vue maintains a state for its components -- from mounting your component to un-mounting. A lot of other phases are encountered in between. Lifecycle hooks help you tap in and perform operations at a given stage of your component life.

A good example is making a HTTP request when the component is created so we can render data from the request to the view or whatever suites your context:

Copy to clipboard
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>
Copy to clipboard
var app = new Vue({
  el: '#demo',
  methods: {
    addThumb: function() {
      this.thumbs.unshift(this.thumb)
    }
  },
  created: function() {
    axios.get('https://res.cloudinary.com/christekh/image/list/gs-vue.json').then((res) => {
      this.thumbs = res.data.resources.map(t => {
        return {
          publicId: t.public_id,
          url: `https://res.cloudinary.com/christekh/image/upload/v${t.version}/${t.public_id}.jpg`
        }
      })
    })
  },
  data: function() {
    return {
     thumb: {
       url: ''
     },
     thumbs: []
    }
  }
})

The created lifecycle hook method is called when a component is created. This makes it a good place to fetch data. Therefore, we use axios to make a request to a list of images tagged gs-vue on my Cloudinary server.

NOTE For security reasons, Cloudinary will not allow you to make requests like this from the client. The best method is to use the admin API via a backend SDK and then send the resource list to the client.

However, to enable access to list resources from client, you need to enable client resource listing. This is not recommended in a production environment, but is fine for demo purposes.

Aside: Image Upload with Cloudinary

Cloudinary is a cloud-based media management tool. You can now worry less about image uploads, quality delivery, transformation and manipulation. Instead, you are able to focus on building your app while Cloudinary takes care of your media files.

The example in this article has been delivering images from a Cloudinary server. Let's try to make the app more flexible by allowing users to upload more images to the existing ones:

Copy to clipboard
<div class="row">
   <divclass="col-md-12">
     <input type="file" v-model="thumb.url" class="form-control" v-on:change="upload($event.target.files)" accept="image/*" />
   </div>
 </div>

First, we update the input text box to file input. Rather than using a button, we just attach a change event to the file input. Then whenever we add a file, it's automatically handled by the upload method. We only want users to upload images, so we add a client validation by setting the accept attribute to image/*.

The upload handler is added to the methods object:

Copy to clipboard
data: function() {
    return {
     cloudinary: {
       uploadPreset: '<UPLOAD-PRESET>',
       apiKey: '<API-KEY>',
       cloudName: '<CLOUD-NAME>'
     }, 
     thumb: {
       url: ''
     },
     thumbs: []
    }
  },
  computed: {
    clUrl: function() {
    return `https://api.cloudinary.com/v1_1/${this.cloudinary.cloudName}/image/upload`  
    },                
  },
methods: {
    upload: function(file) {
      const formData = new FormData()
      formData.append('file', file[0]);
      formData.append('upload_preset', this.cloudinary.uploadPreset);
      formData.append('tags', 'gs-vue,gs-vue-uploaded');
      // For debug purpose only
      // Inspects the content of formData
      for(var pair of formData.entries()) {
        console.log(pair[0]+', '+pair[1]);
      }
      axios.post(this.clUrl, formData).then(res => {
        this.thumbs.unshift({
          url: res.data.secure_url
        })
      })
    }
  },
 }

The cloudinary property holds an object with some Cloudinary credential:

  • The API key and cloud name are available on the Cloudinary dashboard.
  • Client uploads require upload preset to be set. Setting up an upload preset gives you a preset ID, which you need to provide during every upload.

One other Vue instance property that we haven't discussed is computed property. This is basically a getter and is handy when a using a method as a getter is an overkill. We just have one computed property -- clUrl.

The upload function creates a FormData instance, appends all the attributes of this upload and sends to Cloudinary API using axios. These attributes include the file, tags and the upload preset.

Conclusion

What’s most interesting about Vue.js is how simple it is to go from nothing to uploading an image to a server. The need for another supporting JavaScript library was minimal, not even a file upload library; just Vue.js library. We are just using axios to simplify what native fetch could have done.

We also saw how simple it is to upload images to Cloudinary for free. But Cloudinary enables even more. You can manipulate and transform these images just by tweaking URL parameters. You can learn about the awesome features of Cloudinary and sign up for a free account that enables you to do uploads/transformations and so much more.

Christian Nwamba Christian Nwamba (CodeBeast), is a JavaScript Preacher, Community Builder and Developer Evangelist. In his next life, Chris hopes to remain a computer programmer.

Recent Blog Posts

Automate the Staging Process of Videos for Social Media

Rich and engaging media helps build customer engagement and trust but can be time consuming to stage. Developers save a tremendous amount of time by preparing videos for social media with Cloudinary. That’s because Cloudinary’s interface, widgets, and application programming interface (API) transform raw media into polished content, optimizing footage and enabling effortless customization and publishing.

Read more

Top Five Web-Video Formats of 2021

By William Imoh
The Five Most Popular Web-Video Formats and Streaming Protocols

Over the past 15 years, the video industry has undergone a significant change in video formats on the web. In particular, in the early 2010s, the 3GP format, which the 3rd Generation Partnership Project (3GPP) created for 3G-enabled mobile devices, went nearly extinct. The advancement of mobile devices and cellular networks has brought about the need for pioneers to build better formats for a faster user experience.

Read more
Cloudinary Introduces Integration With SAP Commerce Cloud

We’re excited to announce Cloudinary’s integration with SAP Commerce Cloud, through which the latter’s customers can significantly boost the visual media experience on their website or app.

SAP Commerce Cloud powers some of the largest e-commerce sites (B2C, B2B, and B2B2C businesses), complete with building blocks like storefront design and order management. Reinforced with Cloudinary’s laser-sharp focus on optimizing, managing, and delivering images and videos, the new extension will enable SAP Commerce Cloud customers to create unique and engaging visual experiences effortlessly.

Read more
Personalizing Video Email for Marketing Campaigns With Cloudinary

As critical as it is to engage with shoppers in order to succeed in e-commerce, old-style, boring emails are far from being effective. In fact, they tend to be annoying because no one likes to read formulaic, generic messages that are sent en masse. For better results, rethink your email marketing campaigns and try out creative strategies.

Read more
Muted Videos and Subtitles

The bane of our existence is the lack of efficient ways for tackling the plethora of recurring tasks in our lives. One of those tasks is surfing the internet. We consume a lot of web content daily, of which a large percentage are images and videos. We’re constantly quickly scrolling through 30-second videos or checking out pictures of cute items we’d like to buy in our free time.

Read more

Building a Roommate-Matching App With Cloudinary and Jamstack

By Marcelo Ricardo de Oliveira
Building a Roommate-Matching App With Cloudinary and Jamstack

Roommate matching can be a pain—especially during the COVID pandemic when people don't want to meet in person. Matching apps like Flatmates, Roomster, and roommates.com are helpful, and if you're in the roommate-matching space, you know that great video is essential for those seeking roommates. Fortunately, Cloudinary can help.

Read more