Categories
JavaScript Vue

Vue.js Transition Effects — List Transitions

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to add transitions when rendering lists.

List Transitions

If we want to apply transitions to render multiple items simultaneously with v-for , we can use the transition-group component.

Unlike transition , it renders a span by default. We can change the element that’s rendered with the tag attribute.

Transition modes aren’t available because we aren’t alternating between mutually exclusive elements.

Elements inside are always required to have a unique key attribute.

CSS transition classes will be applied to inner elements and not the group or container itself.

List Entering/Leaving Transitions

For example, we can make add a transition when adding or removing the item to a list as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: [1, 2, 3],  
    nextNum: 4  
  },  
  methods: {  
    add() {  
      this.items.push(this.nextNum++);  
    },  
    remove() {  
      this.items.pop();  
    }  
  }  
});

src/style.css :

.list-enter-active,  
.list-leave-active {  
  transition: all 1s;  
}  
.list-enter,  
.list-leave-to {  
  opacity: 0;  
  transform: translateY(30px);  
}

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <link  
      rel="stylesheet"  
      type="text/css"  
      href="./src/styles.css"  
      media="screen"  
    />  
  </head>  
  <body>  
    <div id="app">  
      <button @click="add">Add</button>  
      <button @click="remove">Remove</button>  
      <transition-group name="list" tag="p">  
        <span v-for="item in items" :key="item">  
          {{ item }}  
        </span>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we click the Add button, we see a number added to the end of the list. When we click Remove, the rightmost number is removed.

Like transition , we defined the classes prefixed with the name we specified.

Also, we specified the tag name so that we have a span element rendered for each item within the p element.

List Move Transitions

transition-group can animate the change in position, in addition, to enter and leave. We can do this with the addition of the v-move class.

Like other classes, we prefix it with the name attribute and we can also manually specify a class with the move-class attribute.

For example, we can add an effect when we shuffle the position of numbers as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  
  },  
  methods: {  
    shuffle() {  
      this.items = _.shuffle(this.items);  
    }  
  }  
});

src/styles.css :

.flip-list-move {  
  transition: transform 1s;  
}

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>  
    <link rel="stylesheet" type="text/css" href="./src/styles.css" />  
  </head>  
  <body>  
    <div id="app">  
      <button @click="shuffle">Shuffle</button>  
      <transition-group name="flip-list" tag="div">  
        <div v-for="item in items" :key="item">  
          {{ item }}  
        </div>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

When we click Shuffle, we see the shuffling is stretched slightly in time.

Vue uses FLIP to smoothly transition between elements from the old position to their new position.

They don’t work with elements set to display: inline , we have to use display: inline-block or place elements in a flexbox container.

Staggering List Transitions

We can stagger list transitions as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    items: ["foo", "bar", "baz"],  
    query: ""  
  },  
  computed: {  
    filteredItems() {  
      if (!this.query) {  
        return this.items;  
      }  
      return this.items.filter(i => i === this.query);  
    }  
  },  
  methods: {  
    beforeEnter(el) {  
      el.style.opacity = 0;  
      el.style.height = 0;  
    },  
    enter(el, done) {  
      var delay = el.dataset.index * 150;  
      setTimeout(() => {  
        Velocity(el, { opacity: 1, height: "1.6em" }, { complete: done });  
      }, delay);  
    },  
    leave(el, done) {  
      var delay = el.dataset.index * 150;  
      setTimeout(() => {  
        Velocity(el, { opacity: 0, height: 0 }, { complete: done });  
      }, delay);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <input v-model="query" />  
      <transition-group  
        name="flip-list"  
        tag="div"  
        v-bind:css="false"  
        v-on:before-enter="beforeEnter"  
        v-on:enter="enter"  
        v-on:leave="leave"  
      >  
        <div v-for="item in filteredItems" :key="item">  
          {{ item }}  
        </div>  
      </transition-group>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

We can see that we now have transitions when the list is being filtered.

Conclusion

We can create transitions when rendering a list with v-for like we do with v-if .

The difference is that we have to specify the tag name of the container if we don’t want to render a span.

Also, we always have to add the key attribute to each element inside.

We can have transitions when changing element position by specifying the CSS style for the v-move class, which can be renamed if we specify the class prefix or name.

Specifying enter and leave transitions or v-for is the same as specifying enter and leave transitions for v-if .

Finally, we can create transitions with JavaScript with Velocity.js just like v-if animations.

Categories
Express JavaScript Nodejs

Serve Favicons in Express Apps with serve-favicon

If we have an Express app that renders templates, we can use the serve-favicon middleware to serve Favicons.

Favicons are icons on the left side of a browser tab.

In this article, we’ll look at how to use it to display our favorite favicon in users’ browsers.

Why do we need this module?

The serve-favicon module lets us exclude requests for the favicon in our logger middleware.

It also caches the icon in memory to improve performance by reducing disk access.

In addition, it provides an ETag based on the contents of the icon, rather than file system properties.

Finally, this module serves with the most compatible Content-Type .

This module is exclusive for serving the favicon with the GET /favicon.ico request.

Installation

We can install it by running:

npm install serve-favicon

Options

The favicon function is provided by this module. It takes 2 arguments, which are path, and options and returns a middleware to serve a favicon from the given path .

The options object takes one property, which is the maxAge property. It sets the cache-control max-age directive in milliseconds. The default is 1 yeat. It also can be a string that’s accepted by the ms module.

Examples

Simple Usage

The serve-favicon middleware should come before other middleware so that it won’t conflict with other requests for favicon.ico .

For instance, we can load a favicon with serve-favicon as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const favicon = require('serve-favicon')  
const path = require('path')  
const app = express();  
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))  
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.listen(3000);

Then we get:

https://thewebdev.info/wp-content/uploads/2020/04/icon.png

Setting Max Age

We can also set the maxAge option as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const favicon = require('serve-favicon')  
const path = require('path')  
const app = express();  
const iconPath = path.join(__dirname, 'public', 'favicon.ico');  
const options = {  
  maxAge: 200 * 60 * 60 * 24 * 1000  
}  
app.use(favicon(iconPath, options));  
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.listen(3000);

Then we set the expiry of the icon to 200 days.

Conclusion

We can use the serve-favicon middleware to cache requests for favicon and serve it instead of loading it every time when users make a request for the favicon.

The expiry can also be set so the favicon request result won’t be cached forever.

It should be included before other middleware so that it won’t conflict with other middleware that makes request for a favicon.

Categories
JavaScript Vue

Introduction to Vue.js Computed Properties and Watchers

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at Vue.js computed properties and watchers.

Computed Properties

To make more template expressions more concise and reusable, we can create computed properties to compute results from existing properties as their value changes.

We can define computed properties in a Vue instance by putting them in the computed property of the options object that we pass into the Vue constructor.

For example, we can write the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});

Then we can use it like any other field in our HTML template. So in index.html, we can write:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{message}}</p>  
      <p>{{spelledMessage}}</p>  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

We should then get:

foof-o-o

on our screen.

The spelledMessage method is a getter that’s used by Vue.js. It takes the returned value of it and then put it in place of {{spelledMessage}} .

Therefore, the name of the placeholder in the template must be the same as the name of the method that returns the value that we want in the computed object.

We can also get the value from the returned Vue instance as follows:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});console.log(vm.spelledMessage);

We should see f-o-o logged from the console.log.

We can bind to computed properties in templates like any other property. Vue knows that vm.spelledMessage depends on vm.message, so the bindings will be updated when vm.message is updated.

The computed getter method doesn’t commit side effects, which makes it easy to test and understand.

Computed Caching vs Methods

One good feature of computed properties is that the result of it is cached.

There’s no caching for results returned from methods.

So instead of using methods, we should use computed properties for cases where we’re computing something from existing properties.

A computed property is only re-evaluated once a reactive property is updated.

For example, if we have:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    now() {  
      return Date.now();  
    }  
  }  
});

It’ll never update after its first computed since it doesn’t depend on any reactive property from the data property.

Without caching computed properties keep getting computed as reactive properties that they depend on change, which means the app gets slow as reactive properties that the computed property depends on are changing.

Computed vs Watched Property

Watch properties are useful for watching for changes in a property as the name suggests.

However, because of the caching feature of computed properties, we should use them as much as we can.

For instance, we can simplify the following:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1,  
    person: undefined  
  },  
  watch: {  
    name: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${newVal} - ${this.age}`;  
      }  
    },  
    age: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${this.name} - ${newVal}`;  
      }  
    }  
  }  
});

to:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person() {  
      return `${this.name} - ${this.age}`;  
    }  
  }  
});

As we can see, the first example was much more complex. We have to set immediate to true in each property so that it’ll watch the initial value change. Then we have to define the value change handler for each reactive property.

Then in each handler, we have to set the person property so that we can combine name and age.

On the other hand, with computed properties, we only have one method which returns the fields combined in the way we want.

It’s much more convenient for us and the app that we create is also faster because of caching.

Computed Setter

We can also create a setter function for computed properties.

For example, we can write:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person: {  
      get() {  
        return `${this.name} - ${this.age}`;  
      },  
      set(newValue) {  
        const [name, age] = newValue.split("-");  
        this.name = name.trim();  
        this.age = age.trim();  
      }  
    }  
  }  
});

The getter function returns the same thing as before, but now we also have a setter function.

The setter function splits the newValue, which has the computed value from the getter function, we split the result and set the result back to the corresponding reactive properties.

We can use a setter as follows. We can put the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    firstName: "Joe",  
    lastName: "Smith"  
  },  
  computed: {  
    name: {  
      get() {  
        return `${this.firstName} ${this.lastName}`;  
      },  
      set(newValue) {  
        const [firstName, lastName] = newValue.split(" ");  
        this.firstName = (firstName || "").trim();  
        this.lastName = (lastName || "").trim();  
      }  
    }  
  }  
});

And in index.html, we put:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{name}}</p>  
      <input type="text" v-model="name" />  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

Then when we change the value in the input, we get the new values assigned back to the firstName and lastName fields with the setter.

Conclusion

We can use computed properties to compute values from existing properties.

Returned values from computed properties are cached to reduce the amount of computation required.

Computed properties can also have setters, where we can do things with the new values returned from the computed property getter.

Categories
JavaScript Vue

Vue.js Basics — The Vue Instance

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look more closely at the Vue instance, including how to define it and some properties of it.

Characteristics of the Vue Instance

Each Vue.js app begins by defining a new Vue instance. The Vue constructor takes an options object that takes various properties.

We often use vm to refer to a Vue instance, where vm stands for ViewModel.

A Vue app roughly follows the Model-View-ViewModel pattern, where the ViewModel has the business logic of the app, View has the markup that users see, and Model has the data.

For example, we can define a Vue instance as follows:

const vm = new Vue({ });

Each Vue app consists of a root Vue instance and it’s created with new Vue . We can organize it in a tree for easier maintenance.

Data and Methods

The options object that pass into the Vue constructor can have data and methods.

For example, if we define a Vue instance as follows:

const vm = new Vue({  
  el: "#app",  
  data: { foo: "bar" }  
});

Then when we add:

console.log(vm.foo);

below our vm definition, we get 'bar' since data.foo has the value 'bar' .

In other words, if we have:

const data = { foo: "bar" };  
const vm = new Vue({  
  el: "#app",  
  data  
});  
console.log(vm.foo === data.foo);

Then the console.log will log true .

When the data changes, the app will re-render with the new data.

If we create a new property in vm and set it as follows:

let data = { foo: "bar" };  
const vm = new Vue({  
  el: "#app",  
  data  
});  
vm.a = 1;

The app won’t re-render. On the other hand, if we write:

let data = { foo: "bar", a: 1 };  
const vm = new Vue({  
  el: "#app",  
  data  
});

Then the app will re-render. This means that we have to put our data that we want to render in the data field.

If we freeze the object that we pass to data with Object.freeze() , then the Vue app won’t re-render since properties can’t be changed, so new changes can’t propagate since they aren’t set in the object.

So if we have:

let data = { foo: "bar", a: 1 };  
Object.freeze(data);  
const vm = new Vue({  
  el: "#app",  
  data  
});

No changes can be made after the initial render since we froze data with Object.freeze .

The Vue instance also exposes a number of instance properties and methods.

They’re prefixed with the $ so that we know they’re part of the Vue instance.

$el

We have the $el property to get the DOM element that the Vue instance resides in.

For example, if we have:

let data = { foo: "bar" };  
const vm = new Vue({  
  el: "#app",  
  data  
});

console.log(vm.$el === document.getElementById("app"));

Then the console.log will log true since our Vue instance resides in an element with ID app .

$data

The $data property will get us the value of the data property that we set in the options object that we passed into the Vue constructor.

So if we have:

let data = { foo: "bar" };  
const vm = new Vue({  
  el: "#app",  
  data  
});

console.log(vm.$data === data);

Then we get true from the console.log since data references the same object as vm.$data since we set it as the value of the data property of the options object that we passed into the Vue constructor.

$watch

$watch is an instance method that lets us watch for changes in the data object that we set as the value of the options object.

For example, if we have:

let data = { foo: "bar" };  
const vm = new Vue({  
  el: "#app",  
  data  
});

vm.$watch("foo", (newValue, oldValue) => {  
  console.log(newValue, oldValue);  
});

in src/index.js and:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input type="text" v-model="foo" />  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

in index.html . Then when we type in something to the input box, we should get some console.log output from:

vm.$watch("foo", (newValue, oldValue) => {  
  console.log(newValue, oldValue);  
});

This is because changes are constantly being watched in the data.foo property. v-model automatically updates the value for foo as we type into the box.

So as we’re typing, the changes to foo are being watched and it’s logged by the handler function that we passed into the $watch method.

Conclusion

The Vue instance is created by passing in an options object with the data , el , and methods properties to the Vue constructor. It returns an instance of our Vue app.

The instance has the $el property to get the DOM element that our app resides in.

Also, there’s the $data property to get the value of the data property to get the data that we set when we pass it in as the value of the data property of the options object.

Finally, we have the $watch method to watch for changes in our data.

Categories
Express JavaScript

Guide to the Express Response Object — Redirection and Templates

The Express response object lets us send a response to the client.

Various kinds of responses like strings, JSON, and files can be sent. Also, we can send various headers and status code to the client in addition to the body.

In this article, we’ll look at various properties of the response object, including sending the Links response header, redirect to different paths and URLs, and rendering HTML.

Methods

res.links(links)

The links method joins an object with links together and sends the Link response header with the links joined together.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
  res  
    .links({  
      next: 'http://foo.com?page=1',  
      last: 'http://foo.com?page=2'
    })  
    .send();  
});
app.listen(3000, () => console.log('server started'));

Then we get that the Link response header has the value:

<http://foo.com?page=1>; rel="next", <http://foo.com?page=2>; rel="last"

when we make a request to the / path.

res.location(path)

The location method sends the Location response header with the specified path parameter as the value.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
  res  
    .location('http://medium.com')  
    .send();  
});
app.listen(3000, () => console.log('server started'));

Then we get:

http://medium.com

as the value of the Location response header when we make a request to the / route.

res.redirect([status,] path)

The redirect method redirects to the URL or path specified with the specified status . If no status is specified, the default is 302.

For example, we can use it as follows to redirect to another route:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
  res.redirect('/bar');  
});

app.get('/bar', (req, res) => {  
  res.send('bar');  
});

app.listen(3000, () => console.log('server started'));

Then we should see bar since we redirected to the bar route.

We can specify a status code as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
  res.redirect(301, '/bar');  
});

app.get('/bar', (req, res) => {  
  res.send('bar');  
});

app.listen(3000, () => console.log('server started'));

We can also redirect to a full URL:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
    res.redirect('http://google.com');  
});

app.listen(3000, () => console.log('server started'));

Then when we go to / in our browser, we get Google displayed in our browser.

We can redirect back to the referrer with:

res.redirect('back')

and we can also redirect to a higher level URL, which defaults to / .

We can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const post = express.Router();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));

post.get('/', (req, res) => {  
    res.redirect('..');  
});

app.get('/', (req, res) => {  
    res.send('hi');  
});

app.use('/post', post);app.listen(3000, () => console.log('server started'));

Then we get hi if we go to /post since we see redirect to '..' .

res.render(view [, locals] [, callback])

res.render lets us render HTML using a template. Once we set the HTML template engine, we can use template files to display the results.

The locals object has the properties that we can access in the templates.

And the callback can get the error and the rendered HTML string.

The view argument has the string with the template’s file name. The view’s folder is set before we can call res.render so we don’t need the full folder name.

For example, we can use the Pug template to render templates as follows:

const express = require('express')  
const app = express()  
app.use(express.json())  
app.use(express.urlencoded({ extended: true }))  
app.set('views', './views');  
app.set('view engine', 'pug');
app.get('/', (req, res, next) => {  
  res.render('index', { pageTitle: 'Hello', pageMessage: 'Hello there!' });  
})  
app.listen(3000, () => console.log('server started'));

Then we can add a template file called index.pug to the views folder as follows:

html  
  head  
    title= pageTitle  
  body  
    h1= pageMessage

Then we get:

https://thewebdev.info/wp-content/uploads/2020/04/hello-there.png

We can also pass in a callback to the render method as follows:

const express = require('express')  
const app = express()  
app.use(express.json())  
app.use(express.urlencoded({ extended: true }))  
app.set('views', './views');  
app.set('view engine', 'pug');app.get('/', (req, res, next) => {  
  res.render(  
    'index',  
    { pageTitle: 'Hello', pageMessage: 'Hello there!' },  
    (err, html) => {  
      if (err) {  
        next(err);  
      }  
      else {  
        console.log(html);  
      }  
    }  
  );  
})  
app.listen(3000);

Then we get the rendered HTML from the console.log :

<html><head><title>Hello</title></head><body><h1>Hello there!</h1></body></html>

Any error will be sent to the Express error handler with the next function.

Conclusion

We can render HTML results with render method.

With the redirect method, we can redirect to different paths and URLs with the different response code.

We can use the links and locations methods to send the Links and Locations response headers respectively.