Categories
JavaScript APIs

Use the JavaScript Notification API to Display Native Popups

The Notifications API lets us display popups that show up as a native desktop or mobile notification. The functionality varies across platforms but they generally provide a way to asynchronously provide information to the user.

Create a New Notification

We can create a new notification with the Notification constructor. It takes 2 arguments. The first is the title, and the second is an object with a variety of properties and is optional:

  • dir: the direction of the displayed notification. Default value is auto, but it can also be rtl for right to left or ltr for left to right.
  • lang: string value for the language. Possible values are BCP 47 language tags.
  • badge: string which contains the URL for an image used to represent the notification when there isn’t enough space to display it.
  • body: a string with the text of the notification.
  • tag: a string with the identifying tag of the notification
  • icon: URL string with the icon’s URL
  • image: URL string for the image to be displayed.
  • data: data we want to be associated with the notification.
  • vibrate: vibration pattern for devices that vibrate.
  • renotify: boolean value specifying whether the user should be notified after a new notification replaces the old one. Default value is false.
  • requireInteraction: indicates whether the notification should remain active until the user clicks or dismisses it. Default value is false.
  • actions: an array of NotificationAction which have actions that are available to the user when the notification is displayed. It’s an object with a name, title, and icon properties.

We can define a simple notification as follows:

const options = {
  body: "body",
  icon:
    "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"
};

const n = new Notification("title", options);

To see the notification, we have to set Notification to always display in our browser.

We should see the text we set and the icon we specified in the icon property.

Methods of the Notification Object

Requesting Permission

We can request permission with the requestPermission static method. It returns a promise which resolves when the permission for showing the notification is allowed or denied.

It resolves with an object which has the permission data.

The browser will ask for permission to display notifications for the domain when we run this method.

For example, we can use it as follows:

(async () => {
  try {
    const permission = await Notification.requestPermission();
    console.log(permission);
    const options = {
      body: "body",
      icon:
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"
    };
    const n = new Notification("title", options);
  } catch (error) {
    console.log(error);
  }
})();

If permission is granted, the console.log in the try block will log granted. Otherwise, it will log denied from the console.log in the catch block.

Closing the Notification Programmatically

We can close a notification programmatically with the close method, which is an instance method of a Notification object.

For example, we can use it as follows:

(async () => {
  try {
    const permission = await Notification.requestPermission();
    console.log(permission);
    const options = {
      body: "body",
      icon:
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"
    };
    const n = new Notification("title", options);
    await new Promise(resolve => {
      setTimeout(() => {
        n.close();
        resolve();
      }, 5000);
    });
  } catch (error) {
    console.log(error);
  }
})();

In the example above, we called close inside the callback of the setTimeout method. This makes it close automatically after 5 seconds.

Photo by Priscilla Du Preez on Unsplash

Event Handlers

Notification objects also have their own event handlers. They events are onclick, onclose, onerror, and onshow. We can assign our own event handler functions to them.

onclick

We can assign an event handler to the onclick property when we want to do something when the notification is clicked. For example, we can write:

(async () => {
  try {
    const permission = await Notification.requestPermission();
    console.log(permission);
    const options = {
      body: "body",
      icon:
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"
    };
    const n = new Notification("title", options);
    n.onclick = () => {
      alert("Notification clicked");
    };
  } catch (error) {
    console.log(error);
  }
})();

This shows an alert in the browser tab when our notification is clicked. The event handler function can take one parameter, which is the event object.

The default behavior is to move focus to the viewport of the notification’s related browsing context. We can call preventDefault() on the event parameter that we pass in to prevent that as follows:

(async () => {
  try {
    const permission = await Notification.requestPermission();
    console.log(permission);
    const options = {
      body: "body",
      icon:
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"
    };
    const n = new Notification("title", options);
    n.onclick = event => {
      event.preventDefault();
      alert("Notification clicked");
    };
  } catch (error) {
    console.log(error);
  }
})();

We can make the notification do something when it’s closed by assigning an event handler function to the onclose property.

Likewise, we can do the same for the onerror property to handle errors and the onshow property to handle the show event, which is fired when the notification is displayed.

Conclusion

As we can see, the Notification API is a really simple way to display native notifications from the web apps we write. We ask for permission to display notifications with the static Notification.requestPermission method.

Once the promise is resolved when the user allows notifications to be displayed, then we just create a Notification object with the options we want. Then the notification will be displayed.

Categories
JavaScript APIs

Checking Network Status with the Network Information API

With the advent of mobile devices like phones and tablets, knowing the connection status is very important since it can change any time, affecting user experience in the process. We also have to be aware of different kinds of internet connections since they vary widely in speed.

Fortunately, we have the Network Information API built into browsers to check for internet connection status.

This API is available for browser and worker contexts.

In this article, we’ll look at how to use the API to get network connection type changes and connection status.

Detect Connection Changes

Detecting connection changes is simple. We can use the navigation.connection object to listen to network type changes as follows:

const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
let type = connection.effectiveType;

const updateConnectionStatus = () => {
  console.log(`Connection type changed from ${type} to ${connection.effectiveType}`);
  type = connection.effectiveType;
}

connection.addEventListener('change', updateConnectionStatus);

We can then test the connection type changes by going to the Chrome developer console by pressing F12. Then go to the Network tab, and then on the top right, there’s a dropdown to change the connection type.

If we switch between them, we should see something like:

Connection type changed from 4g to 3g
Connection type changed from 3g to 4g
Connection type changed from 4g to 2g

from the console.log output.

The connection object is a NetworkInformation object instance and it has the following properties:

  • downlink — effective bandwidth estimate in megabits per second rounded to the nearest 25 kbps.
  • downlinkMax — maximum downlink speed, in Mbps for the underlying connection technology
  • effectiveType — the type of connection determined by a combination of recently observed round-trip time and downlink values. It can be one of ‘slow-2g’, ‘2g’, ‘3g’, or ‘4g’.
  • rtt — estimated effective round-trip time of the current connection rounded to the nearest multiple of 25 milliseconds.
  • saveData — boolean indicating if reduced data usage optional has been set
  • type — type of connection to communicate with the network. It can be one of bluetooth, cellular, ethernet, none, wifi, wimax, other, unknown

Compatibility

This API is new and experimental, so we’ve to be careful when we use it. Chrome supports most properties out of the box since Chrome 61. Some options like downlinkMax and type are only available for Chrome OS. Firefox and Edge do not support this API.

It’s also available for use in other Chromium-based browsers like Opera, Android Webview, and Chrome for Android.

With the Network Information API, we can get information about the network connection. This is useful for detecting the connection type of mobile devices and lets us change the web page to accommodate slower connections accordingly.

Categories
JavaScript APIs

Getting Browser User Permission with the Permissions API

We have to get user consent when we want to do anything that changes the user experience. For example, we need to get user permission to show notifications or access their hardware.

Modern browsers are standardized in how permissions are obtained. It’s all in the Permissions API.

APIs that rely on the Permissions API for permissions include the Clipboard API, Notifications API, Push API, and Web MIDI API.

The navigator object has the permissions property in both the standard browser and worker contexts. It gives us a way to get the permissions. However, the way we request permissions is different for each API.

This API is experimental so check if the browsers you target are supported.

Querying Permissions

The navigation.permissions object lets us query permissions set with the query method.

It returns a promise which gets us the state of the permission. For example, we can write the following to check for permission for the geolocation API:

(async () => {
  const result = await navigator.permissions.query({
    name: 'geolocation'
  });
  console.log(result.state);
})();

The possible values for result.state are 'granted', 'denied', or 'prompt'.

There’s also one for Web Workers that do the same thing.

The object that we passed into the query method is the permission descriptor object, which has the following properties:

  • name — name of the API which we want to get the permission for. Firefox only supports geolocation, notifications, push, and persistent-storage
  • userVisibleOnly — indicates whether we want to show notification for every message or be able to send silent push notifications. Default value is false .
  • sysex — applies to MIDI only. Indicates whether we need to receive system exclusive messages. Default value is false .

Requesting Permission

Requesting permission is different between APIs. For example, the Geolocation API will show a prompt for permission when we call getCurrentPosition() as follows:

navigator.geolocation.getCurrentPosition((position) => {
  console.log('Geolocation permissions granted');
  console.log(`Latitude: ${position.coords.latitude}`);
  console.log(`Longitude: ${position.coords.longitude}`);
});

The Notifications API has a requestPermission method to request permissions:

Notification.requestPermission((result) => {
  console.log(result);
});

Watching for Permission Changes

The navigator.permissions.query promise resolves to a PermissionStatus object. We can use it to set an onchange event handler function to watch for permission changes.

For example, we can expand on this example to add an event handler function to watch for changes for the permission of the Geolocation API:

(async () => {
  const result = await navigator.permissions.query({
    name: 'geolocation'
  });
  console.log(result.state);
})();

We can write:

(async () => {
  const permissionStatus = await navigator.permissions.query({
    name: 'geolocation'
  });
  permissionStatus.onchange = () => {
    console.log(permissionStatus.state);
  }
})();

The permissionStatus.state will have the permission for the Geolocation API.

It’ll log whenever the permission changes, such as when we change the permission setting in the browser.

Revoking Permissions

We can revoke permission by using the revoke method.

To call it, we can access it from the navigator.permissions object as follows:

navigator.permissions.revoke(descriptor);

Where descriptor is the permission descriptor which we described above.

It returns a Promise that resolves with the permission status object indicating the result of the request.

This method throws a TypeError if getting the permission descriptor failed or the permission doesn’t exist or is unsupported by browsers.

The name property of the permission descriptor can accept one of the following values 'geolocation', 'midi', 'notifications', and 'push'.

Other properties remain the same as the query method.

For example, we can use it by writing:

(async () => {
  const permissionStatus = await navigator.permissions.revoke({
    name: 'geolocation'
  });
  console.log(permissionStatus);
})();

Note that we’ve to set dom.permissions.revoke.enable to true in Firefox 51 or later to use this method. It’s not enabled in Chrome.

The Permissions API lets us check and revoke browser permissions in a uniform way.

Requesting permissions are different for each API. This isn’t changing any time soon.

This is an experimental API, so using it in production is probably premature.