Categories
JavaScript Vue

Defining Nested Routes with Vue Router

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 define nested routes with Vue Router.

Why do we Need Nested Routes?

We need nested routes to organize routes where components are nested multiple levels deep.

For example, we have to find a way to organize routes like:

/user/bar/profile                       
/user/bar/posts

into one coherent place.

Defining Nested Routes

We can define nested routes by adding a children array in the route entry, and then in the parent route’s template we have to add router-view to display the children routes.

For example, we can write the following:

src/index.js :

const Profile = { template: "<p>{{$route.params.user}}'s profile</p>" };  
const Posts = { template: "<p>{{$route.params.user}}'s posts</p>" };  
const User = {  
  template: `  
    <div>  
      <p>user - {{$route.params.user}}</p>  
      <router-view></router-view>  
    </div>  
`  
};  
const routes = [  
  {  
    path: "/user/:user",  
    component: User,  
    children: [  
      { path: "posts", component: Posts },  
      { path: "profile", component: Profile }  
    ]  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="[https://unpkg.com/vue/dist/vue.js](https://unpkg.com/vue/dist/vue.js)"></script>  
    <script src="[https://unpkg.com/vue-router/dist/vue-router.js](https://unpkg.com/vue-router/dist/vue-router.js)"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="/user/foo">Foo User</router-link>  
        <router-link to="/user/foo/posts">Foo Post</router-link>  
        <router-link to="/user/foo/profile">Foo Profile</router-link>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have:

const routes = [  
  {  
    path: "/user/:user",  
    component: User,  
    children: [  
      { path: "posts", component: Posts },  
      { path: "profile", component: Profile }  
    ]  
  }  
];

to define the child routes.

The Posts and Profile components are like any component we defined as usual.

However, the User component has the router-view to display them content of the Posts and Profile components.

In the template, we have 3 router links to go to the root and child routes:

<router-link to="/user/foo">Foo User</router-link>  
<router-link to="/user/foo/posts">Foo Post</router-link>  
<router-link to="/user/foo/profile">Foo Profile</router-link>

Then we should see:

Foo User Foo Post Foo Profile  
user - foofoo's posts

when we go to /#/user/foo/posts or click on Foo Post .

And we should see:

Foo User Foo Post Foo Profileuser - foofoo's profile

when we go to /#/user/foo/profile or click on Foo Profile.

When we go to /#/user/foo or click on Foo User , we see:

Foo User Foo Post Foo Profileuser - foo

Any nested path that starts with / will be treated as the root path. This lets us use component nesting without having to use a nested URL.

Also, the parent and child routes all have access to the same route parameters.

For example, we can add a UserHome component and a route for it to the example above as follows:

src/index.js :

const Profile = { template: "<p>{{$route.params.user}}'s profile</p>" };  
const Posts = { template: "<p>{{$route.params.user}}'s posts</p>" };  
const UserHome = { template: "<p>{{$route.params.user}} home</p>" };  
const User = {  
  template: `  
    <div>  
      <p>user - {{$route.params.user}}</p>  
      <router-view></router-view>  
    </div>`  
};  
const routes = [  
  {  
    path: "/user/:user",  
    component: User,  
    children: [  
      { path: "", component: UserHome },  
      { path: "posts", component: Posts },  
      { path: "profile", component: Profile }  
    ]  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="/user/foo">Foo User</router-link>  
        <router-link to="/user/foo/posts">Foo Post</router-link>  
        <router-link to="/user/foo/profile">Foo Profile</router-link>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Now when we go to /user/foo or click on Foo User , we see:

Foo User Foo Post Foo Profileuser - foofoo home

Everything else remains the same.

Conclusion

We can add nested routes to our routes by adding a children property with an array of routes.

Then we have to add router-view to the parent route so that we can see the content of the child routes.

The parent and child routes all have access to the same route parameters.

Categories
JavaScript Vue

Programmatic Navigation of Vue Router Routes

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 navigate through Vue Router routes dynamically.

Programmatic Navigation

We can navigate through routes programmatically in addition to using router-link to create a link to let users navigate through routes.

router.push(location, onComplete?, onAbort?)

To do this, we can use the $router instance available to a component to navigating routes programmatically.

router.push(…) is called when a router-link link is clicked. We can call it ourselves to programmatically navigate to routes.

For example, we can define routes and navigate through them programmatically as follows:

src/index.js :

const Foo = { template: "<p>foo</p>" };  
const Bar = { template: "<p>bar</p>" };

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router,  
  methods: {  
    goTo(route) {  
      this.$router.push(route);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <a href="#" @click='goTo("foo")'>Foo</a>  
        <a href="#" @click='goTo("bar")'>Bar</a>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we have the goTo method that takes a string for the route that we want to go to.

In the method, we call this.$router.push(route); to go to the route we want to reach.

So when we click on Foo we see foo , and when we click on Bar we see bar .

We can also pass in an object as follows:

this.$router.push({ path: route });

Also, we can go to named routes when $router.push . To do this, we write:

src/index.js :

const Foo = { template: "<p>foo</p>" };  
const Bar = { template: "<p>bar</p>" };

const routes = [  
  {  
    name: "foo",  
    path: "/foo",  
    component: Foo  
  },  
  {  
    name: "bar",  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router,  
  methods: {  
    goTo(name) {  
      this.$router.push({ name });  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <a href="#" @click='goTo("foo")'>Foo</a>  
        <a href="#" @click='goTo("bar")'>Bar</a>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we defined named routes by adding the name property to our routes by writing:

const routes = [  
  {  
    name: "foo",  
    path: "/foo",  
    component: Foo  
  },  
  {  
    name: "bar",  
    path: "/bar",  
    component: Bar  
  }  
];

Then we can go to a route by name as follows in the goTo method:

this.$router.push({ name });

We can pass in route parameters as follows:

router.push({ name: 'user', params: { userId: '123' } })

The following won’t work:

router.push({ path: 'user', params: { userId: '123' } })

We can go to routes with query strings as follows:

router.push({ path: 'user', query: { userId: '123' } })

or:

router.push({ name: 'user', query: { userId: '123' } })

We can also go on a path with a route parameter as follows:

router.push({ path: `/user/123` });

For example, we can use them as follows:

const Foo = { template: "<p>foo {{$route.query.id}}</p>" };  
const Bar = { template: "<p>bar</p>" };

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router,  
  methods: {  
    goTo(path, query) {  
      this.$router.push({ path, query });  
    }  
  }  
});

Then we see foo 1 when we click on Foo since we take a query string with id as the key.

It’s the same as going to /#/foo?id=1 in the browser.

The same rules apply for the to property of the router-link component.

In Vue Router 2.2.0 or later, we can optionally provide a onComplete and onAbort callbacks to router.push or router.replace as the 2nd and 3rd arguments.

In Vue Router 3.1.0+. router.push and router.replace will return promises and we don’t need to pass in the 2nd and 3rd arguments to handle those cases.

If our destination is the same as the current route and only the parameters are changing, like /users/1 to /users/2 , then we have to use beforeRouteUpdate hook to react to changes.

router.replace(location, onComplete?, onAbort?)

router.replace acts like router.push except that no new history entry is added.

router.replace(…) is the same as <router-link :to=”…” replace> .

router.go(n)

We can use router.go to go forward or backward by passing in an integer for the number of steps to go forward or back. Negative is backward and positive is forward.

For example, we can use it as follows:

src/index.js :

const Foo = { template: "<p>foo</p>" };  
const Bar = { template: "<p>bar</p>" };

const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  routes  
});

new Vue({  
  el: "#app",  
  router,  
  methods: {  
    forward() {  
      this.$router.go(-1);  
    },  
    back() {  
      this.$router.go(1);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <router-link to="foo">Foo</router-link>  
        <router-link to="bar">Bar</router-link>  
        <a href="#" @click="forward">Forward</a>  
        <a href="#" @click="back">Back</a>  
      </div>  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

We have to forward and back methods to go forward and backward respectively.

router.go will fail silently if no such history record exists.

Conclusion

We have the router.push method to go to a path with different names, paths, query string or parameters.

Likewise, we can do the same with router.replace but without adding a new history entry.

They both take a string or object for the route and an onComplete and onAbort handlers.

router.go lets us go back and forward in the browser history. It takes a number of steps to go forward or back.

Categories
JavaScript Vue

Using Vue Router’s History Mode.

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

Vue Router is a URL router that maps URLs to components.

In this article, we’ll look at how to use Vue Router’s history mode.

HTML5 History Mode

The default mode for Vue Router is hash mode. It uses a URL hash to simulate a full URL so that the page won’t be reloaded when the URL changes.

We can set Vue Router to history mode to get rid of the hash. It uses history.pushState API to let us navigate URLs without a page reload.

For example, we can enable history mode as follows:

src/index.js :

const Foo = { template: "<div>foo</div>" };  
const Bar = { template: "<div>bar</div>" };  
const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  }  
];

const router = new VueRouter({  
  mode: "history",  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then when we go to /foo and /bar , we’ll see foo and bar displayed respectively. Now we don’t need to add a hash sign in front of the URL anymore.

Server Configuration

The issue with history mode is that we have to configure our server to display our app whenever the user navigates to the folder in our server.

This is because if we didn’t configure our server, we’ll get a 404 error if we go directly to the URL from the browser.

To fix this, we need to redirect to index.html if it doesn’t match any assets uploaded to the server that we want to load.

We can use the following configure in Apache:

<IfModule mod_rewrite.c>  
  RewriteEngine On  
  RewriteBase /  
  RewriteRule ^index.html$ - [L]  
  RewriteCond %{REQUEST_FILENAME} !-f  
  RewriteCond %{REQUEST_FILENAME} !-d  
  RewriteRule . /index.html [L]  
</IfModule>

This configuration assumes that the code is in the root folder. If it’s in a subfolder, we can change RewriteBase / with RewriteBase /subfolder-name/ .

For Nginx, it’s simpler:

location / {  
  try_files $uri $uri/ /index.html;  
}

Again, we can replace / with the subfolder if the code is in a subfolder.

We should add a 404 route to our app since how 404 errors won’t be displayed.

We can add one as follows:

src/index.js :

const Foo = { template: "<div>foo</div>" };  
const Bar = { template: "<div>bar</div>" };  
const NotFound = { template: "<div>not found</div>" };  
const routes = [  
  {  
    path: "/foo",  
    component: Foo  
  },  
  {  
    path: "/bar",  
    component: Bar  
  },  
  { path: "*", component: NotFound }  
];

const router = new VueRouter({  
  mode: "history",  
  routes  
});

new Vue({  
  el: "#app",  
  router  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>  
  </head>  
  <body>  
    <div id="app">  
      <router-view></router-view>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

With Node.js, the easiest way to serve a Vue app with history mode set by using Express and the connect-history-api-fallback middleware as follows:

server.js :

const express = require('express');  
const history = require('connect-history-api-fallback');

const app = express();  
app.use(history());  
app.use(express.static('src'));

app.get('/', (req, res) => {  
  res.sendFile('src/index.html');  
});

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

Then the Vue app files can be stored in the src folder.

In the code above, the code:

{ path: "*", component: NotFound }

is the catch-all route for anything other than foo and bar and maps to the NotFound component.

Conclusion

We can enable the Vue Router’s history mode to eliminate the hash from our app’s URLs.

However, we have to redirect our app to index.html since we don’t want users to see errors when they go the URLs by entering it or refreshing the page.

We can do this with any web server. Then we have to add a catch-all route to display something when it doesn’t match any routes.

Categories
JavaScript JavaScript Basics

JavaScript Events Handlers — onblur and onerror

In JavaScript, events are actions that happen in an app. They are triggered by various things like inputs being entered, forms being submitted, changes in an element like resizing, or errors that happen when an app is running, etc.

We can assign event handlers to respond to these events. Events that happen to DOM elements can be handled by assigning an event handler to properties of the DOM object for the corresponding events.

In this article, we will look the onblur and the onerror property.

window.document.onblur

The onblur property let’s set an event handler function to it to handle the blur event, where the object that represents the element that can lose focus has lost focus. For example, we can attach a onblur event listener function by writing the following code:

document.onblur = () => {  
  console.log('Document lost focus.');  
};

After adding the code above, when we click outside the page then ‘ Document lost focus.’ should be logged.

window.document.onerror

The onerror property lets us attach an event handler to handle situations when the error event is triggered.

The error event is triggered when a JavaScript run time error occurs, such as when syntax errors or exceptions are being thrown within handlers occurs. The error event handler can take a parameter that has the ErrorEvent object in this case.

These errors get bubbled up to the window object by default. It’s also fired when a resource, like an image or script element, fails to load. An error event using the Event interface will be passed into the error event handler in this case. These errors do not get bubbled up to the window object, but it can be handled in window.addEventListener with useCapture is set to true which is the third argument of the addEventListener method.

For historical reasons, the arguments that are passed into window.onerror are different from the ones that are passed into element.onerror as well as on error-type window.addEventListener handlers. window.onerror’s error handler function has the following function signature:

window.onerror = function(message, source, lineno, colno, error) { ... }

Where message is the error message, the source is the string of the URL of the script that threw the error. The lineno parameter is a number that has the line number where the error was raised. The colno parameter is a number that has the column number for the line where the error occurred. The error parameter has the Error object. The Error object has the following standard properties:

  • constructor — the function that created the instance’s prototype
  • message — the error message
  • name — the error name

It also has vendor-specific properties. For Microsoft browsers, the Error object has the following additional properties:

  • description — the error description, which is similar to message
  • number — the error number

For Mozilla browsers, the following additional properties are added to the error object:

  • fileName — the path to the file that raised the error
  • lineNumber — the line number that raised the error
  • columnNumber — the column number of the line that raise the error
  • stack — the stack trace of the error

If an error event handler is passed into the second argument of the window.addEventListener method, then the function signature of the event handler is significantly different. It should have one event parameter which is the ErrorEvent, so the function signature should be the one below:

window.addEventListener('error', function(event) { ... })

The ErrorEvent inherits all the properties from the Event object plus the following properties are included:

  • message — a read-only property that as the string of the human-readable error message which describes the error
  • filename — a read-only string property that has the name of the script of the file in which the error occurred
  • lineno — a read-only integer that has the line number of the script of the file on which the error occurred
  • colno — a read-only integer that has the column number of the script where the error occurred
  • error — a read-only JavaScript object that has the data about the event

If the onerror is a property of anything other than window, then the event handler that we assign to it should have the same signature as we have above, which is only the event parameter which will have the ErrorEvent passed in when an event occurs.

So with the onerror event handler we can handle any error that occurs when loading the page and running the scripts that are loaded on the page. For example, we can use it to handle the situation when an image fails to load by providing an alternative image which we can load.

For example, if we want to load an image that might exist, then we can add an onerror attribute to the img element to load the fallback image like in the following code:

<img src="invalid.gif" onerror="this.src='[https://images.unsplash.com/photo-1556742521-9713bf272865?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1534&q=80'](https://images.unsplash.com/photo-1556742521-9713bf272865?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1534&q=80');" />

To handle errors during script loading, we can write the following code:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Error</title>  
  </head>  
  <body>  
    <script src="main.js"></script>  
    <script src="error.js"></script>  
  </body>  
</html>

Then in main.js we add our onerror event handler:

window.onerror = (message, source, lineno, colno, error) => {  
  console.log(message);  
  console.log(source);  
  console.log(lineno);  
  console.log(colno);  
  console.log(error.toString());  
};

Then we put some expressions or statements that throws an error in error.js like the following code:

xyz

Then we should get the error logged in our console.log statements inside the onerror event handler in main.js . We should get something like the following output from the console.log statements:

Uncaught ReferenceError: xyz is not defined  
[http://localhost:3000/error.js](http://localhost:3000/error.js)  
1  
1  
ReferenceError: xyz is not defined

The first console.log output has the error message. The second line in the output has the path to the script that caused the error message. Line 3 has the line number of the script where the error occurred. The fourth line has the column number of the line that caused the error, and the last line has the Error object converted to a string, which returns the error message.

If we instead write use the window.addEventListener method to add the event handler, then we can write the following code to log the ErrorEvent object:

window.addEventListener("error", event => {  
  console.log(event);  
});

Then we should get something like the following output from the console.log statement in the event handler above:

bubbles: false  
cancelBubble: false  
cancelable: true  
colno: 1  
composed: false  
currentTarget: Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}  
defaultPrevented: false  
error: ReferenceError: xyz is not defined at [http://localhost:3000/error.js:1:1](http://localhost:3000/error.js:1:1)  
eventPhase: 0  
filename: "[http://localhost:3000/error.js](http://localhost:3000/error.js)"  
isTrusted: true  
lineno: 1  
message: "Uncaught ReferenceError: xyz is not defined"  
path: [Window]  
returnValue: true  
srcElement: Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}  
target: Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}  
timeStamp: 68.510000128299  
type: "error"

In the output above, we get everything from the Event object plus the additional properties from the ErrorEvent object that we listed above like the error property, message property and the filename property.

Conclusion

With the onblur property, we can set an event handler that can handle the blur event. The onerror property lets us set the event handler for when the error event occurs, which happens when something fails to load like an image or a script that fails to run because of some error.

These are handy event handlers that let us handle user interaction and unexpected errors when resource load respectively.

Categories
JavaScript

JavaScript Events Handlers — onanimationstart

In JavaScript, events are actions that happen in an app. They’re triggered by various things like inputs being entered, forms being submitted, and changes in an element like resizing, or errors that happen when an app is running, etc. We can assign an event handler to handle these events. Events that happen to DOM elements can be handled by assigning an event handler to properties of the DOM object for the corresponding events. In this part, we take a close look at the onanimationstart event handler and the animationstart event.

onanimationstart

We can assign our own event handler function to the onanimation property if we want to handle the situation when a CSS animation starts to play, which is when animationstart event is triggered. We can create an animation with CSS that animates a box by first creating the HTML elements that will be animated like in the following code:

<div id='container'>  
  <div id='box'> </div>  
</div>

Then we add some styling to the elements and create the animation with CSS like in the following code:

#box {  
  width: 100px;  
  height: 100px;  
  left: 0;  
  top: 0;  
  border: 1px solid red;  
  margin: 0;  
  position: relative;  
  background-color: red;  
  display: block;  
  justify-content: center;  
  animation: 5s resizeBox;  
}#container {  
  height: 500px;  
}[@keyframes](http://twitter.com/keyframes) resizeBox {  
  from {  
    transform: translateX(100%) scaleX(3);  
  } to {  
    transform: translateX(0) scaleX(1);  
  }  
}

In the code above, we change the box size to 100 pixels by 100 pixels., change the fill color to red, and then put the box in the top left corner of our page. Then we create the resizeBox animation by horizontally scaling the box by 3 times and then shrink back to the original size. We repeat this for 5 seconds. After we create the animation in the CSS code, we can set the event handler to the onanimationstart property with the following code:

document.onanimationstart = (event) => {  
  console.log(event);  
  console.log('Animation starts');  
};

When the event handler function above is run, then we get the AnimationEvent object in the parameter of the event handler function. It inherits the properties from the Event object which have the following properties:

  • bubbles — is a read-only boolean property that indicates whether the event bubbles up through the DOM tree or not.
  • cancelBubble — is a historical alias to the stopPropagation method. Setting its value to true before returning from an event handler prevents the propagation of the event.
  • cancelable — is a read-only boolean property indicating whether the event can be cancelled.
  • composed — is a read-only boolean property that indicates whether or not the event can bubble across the boundary between the shadow DOM and the regular DOM.
  • currentTarget — is a read-only property that references currently registered target for the event. This is the object to which the event is currently slated to be sent to, but it’s possible that this has been changed along the way through retargeting.
  • deepPath — is an array of DOM Nodes through which the event has bubbled.
  • defaultPrevented — is a read-only boolean property that indicates whether or not event.preventDefault() has been called on the event.
  • eventPhase — is a read-only property that indicates which phase of the event flow is being processed.
  • explicitOriginalTarget — is a read-only property that has an explicit original target of the event. This property is only available in Mozilla browsers.
  • originalTarget — is a read-only property that has the original target of the event, before any retargeting. This property is only available in Mozilla browsers.
  • returnValue — is a historical property introduced by Internet Explorer and eventually adopted into the DOM specification in order to ensure existing sites continue to work. Ideally, you should try to use preventDefault() and defaultPrevented instead for cancelling events and checking if events are cancelled, but you can use returnValue if you choose to do so.
  • srcElement — is anon-standard alias from old versions of Microsoft Internet Explorer for target, which is starting to be supported in some other browsers for web compatibility purposes.
  • target — is a read-only property that is a reference to the target to which the event was originally dispatched.
  • timeStamp — is a read-only that has the time at which the event was created (in milliseconds). By specification, this value is the time since January 1, 1970, but in reality browsers’ definitions vary.
  • type — is a read-only property that has the name of the event (case-insensitive).
  • isTrusted — is a read-only property that indicates whether or not the event was initiated by the browser after user interaction or by a script using an event creation method like initEvent.

The list above is a partial of properties. It only contains the value properties of the Event object. The AnimationEvent inherit the properties and add its own properties, which are the following:

  • animationName — is a read-only property that returns a string that contains the value of the animation-name of the CSS animation.
  • elapsedTime — a read-only float property that has the amount of time that the animation has been running in seconds as of the time the event is being triggered. For the animationstart event the elapsedTime is 0.0 unless there was a negative value for the animation-delay CSS attribute, which in that case the event will be fired with elapsedTime of minus one multiplied by the delay.
  • pseudoElement — a string read-only property that starts with :: containing the name of the pseudo-element that the animation runs on. If the animation isn’t running in a pseudo-element then the value of this property will be an empty string.

If we run the code above, we should get the following AnimationEvent object logged:

animationName: "resizeBox"  
bubbles: true  
​cancelBubble: false  
​cancelable: false  
​composed: false  
​currentTarget: null  
​defaultPrevented: false  
​elapsedTime: 0  
​eventPhase: 0  
​explicitOriginalTarget: <div id="box">  
​isTrusted: true  
​originalTarget: <div id="box">  
​pseudoElement: ""  
​returnValue: true  
​srcElement: <div id="box">​target: <div id="box">  
​timeStamp: 297  
​type: "animationstart"

As we can see the animationName is “resizeBox” which is the name of our CSS animation. The elapsedTime is 0 since we’re logging this Event object in an onanimationstart event handler and our animation don’t have a negative delay.pseudoElement is an empty string since we aren’t running our animation in any pseudo-element.

This property and the animationstart is a work in progress. The event handler is run only in Firefox. It doesn’t run in Chrome or other popular modern browsers. This means that this shouldn’t be relied upon in production environments if we want it to work on anything other than Firefox.

The animationstart event is triggered when the CSS animation starts. It’s only triggered in Firefox so far and the work to standardize this event is ongoing. It’s handy for getting the start event and the elapsed time of when the animation starts running and the name of the animation that’s running.