In this step, you will learn:
- How to wake your app at specified intervals to execute background tasks.
- How to use on-screen notifications to draw attention to something important.
Estimated time to complete this step: 20 minutes. To preview what you will complete in this step, jump down to the bottom of this page ↓.
Enhance your Todo app with reminders
Enhance the Todo app by adding functionality to remind the user if they have open todos—even when the app is closed.
First, you need to add a way for the app to regularly check for uncompleted todos. Next, the app needs to display a message to the user, even if the Todo app window is closed. To accomplish this, you need to understand how alarms and notifications work in Chrome Apps.
Add alarms
Use chrome.alarms
to set a wake up interval. As long as Chrome is running, the alarm listener
is called at approximately the interval set.
Update app permissions
In manifest.json, request the "alarms"
permission:
"permissions": ["storage", "alarms"],
Update background scripts
In background.js, add an onAlarm
listener. For now, the callback function will just log
a message to the Console whenever there is a todo item:
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', {
id: 'main',
bounds: { width: 620, height: 500 }
});
});
chrome.alarms.onAlarm.addListener(function( alarm ) {
console.log("Got an alarm!", alarm);
});
Update HTML view
In index.html, add an Activate alarm button:
<footer id="info">
<button id="toggleAlarm">Activate alarm</button>
...
</footer>
You now need to write the JavaScript event handler for this new button. Recall from Step 2 that one of the most common CSP non-compliances is caused by inline JavaScript. In index.html, add this line to import a new alarms.js file which you will create in the following step:
</footer>
...
<script src="js/app.js"></script>
<script src="js/alarms.js"></script>
</body>
Create alarms script
Create a new file in your js folder called alarms.js.
Use the code below to add checkAlarm()
, createAlarm()
, cancelAlarm()
and toggleAlarm()
methods, along with a click event handler to toggle the alarm when the Activate alarm button is
clicked.
(function () {
'use strict';
var alarmName = 'remindme';
function checkAlarm(callback) {
chrome.alarms.getAll(function(alarms) {
var hasAlarm = alarms.some(function(a) {
return a.name == alarmName;
});
var newLabel;
if (hasAlarm) {
newLabel = 'Cancel alarm';
} else {
newLabel = 'Activate alarm';
}
document.getElementById('toggleAlarm').innerText = newLabel;
if (callback) callback(hasAlarm);
})
}
function createAlarm() {
chrome.alarms.create(alarmName, {
delayInMinutes: 0.1, periodInMinutes: 0.1});
}
function cancelAlarm() {
chrome.alarms.clear(alarmName);
}
function doToggleAlarm() {
checkAlarm( function(hasAlarm) {
if (hasAlarm) {
cancelAlarm();
} else {
createAlarm();
}
checkAlarm();
});
}
$$('#toggleAlarm').addEventListener('click', doToggleAlarm);
checkAlarm();
})();
Reload your app and spend a few moments activating (and deactivating) the alarm.
Whenever you have the alarm activated, you should see log messages being printed in the Console every time the alarm "rings":
You should notice that:
- Even when you close the Todo app window, the alarms will keep coming.
- On platforms other than ChromeOS, if you completely close all Chrome browser instances, alarms won't trigger.
Let's go over some of the pieces in alarms.js that use chrome.alarms
methods one by one.
Create alarms
In createAlarm()
, use the chrome.alarms.create()
API to create an alarm when Activate
alarm is toggled.
chrome.alarms.create(alarmName, {delayInMinutes: 0.1, periodInMinutes: 0.1});
The first parameter is an optional string identifying an unique name for your alarm, for example,
remindme
. (Note: You need to set an alarm name in order to cancel it by name.)
The second parameter is an alarmInfo
object. Valid properties for alarmInfo
include when
or
delayInMinutes
, and periodInMinutes
. In order to reduce the load on the user's machine, Chrome
limits alarms to once every minute. We are using small values (0.1 of a minute) here for demo
purposes only.
Clear alarms
In cancelAlarm()
, use the chrome.alarms.clear()
API to cancel an alarm when Cancel
alarm is toggled.
chrome.alarms.clear(alarmName);
The first parameter should be the identifying string you used as an alarm name in
chrome.alarms.create()
.
The second (optional) parameter is a callback function that should take on the format:
function(boolean wasCleared) {...};
Get alarms
In checkAlarm()
, use the chrome.alarms.getAll()
API to get an array of all created alarms
in order to update the UI state of the toggle button.
getAll()
accepts a callback function that passes in an array of Alarm
objects. To see what's in
an Alarm
, you can inspect running alarms in the DevTools Console like so:
chrome.alarms.getAll(function(alarms) {
console.log(alarms);
console.log(alarms[0]);
});
This will output an object such as
{name: "remindme", periodInMinutes: 0.1, scheduledTime: 1397587981166.858}
as seen below:
Get ready for the next section
Now that alarms are in place to poll the app at regular intervals, use this as a base for adding visual notifications.
Add notifications
Let's change the alarm notification to something the user can easily notice. Use
chrome.notifications
to show a desktop notification like the one below:
When the user clicks on the notification, the Todo app window should come into view.
Update app permissions
In manifest.json, request the "notifications"
permission:
"permissions": ["storage", "alarms", "notifications"],
Update background scripts
In background.js, refactor the chrome.app.window.create()
callback into a standalone method
so you can reuse it:
chrome.app.runtime.onLaunched.addListener(function() {
function launch() {
chrome.app.window.create('index.html', {
id: 'main',
bounds: { width: 620, height: 500 }
});
}
});
chrome.app.runtime.onLaunched.addListener(launch);
...
Update alarm listener
At the top of the background.js, add a variable for a database name that's used in the alarm listener:
var dbName = 'todos-vanillajs';
The value of dbName
is the same database name set in line 17 of js/app.js:
var todo = new Todo('todos-vanillajs');
Create a notification
Instead of simply logging a new alarm to the Console, update the onAlarm
listener to get stored
data via chrome.storage.local.get()
and call a showNotification()
method:
chrome.alarms.onAlarm.addListener(function( alarm ) {
console.log("Got an alarm!", alarm);
chrome.storage.local.get(dbName, showNotification);
});
Add this showNotification()
method to background.js:
function launch(){
...
}
function showNotification(storedData) {
var openTodos = 0;
if ( storedData[dbName].todos ) {
storedData[dbName].todos.forEach(function(todo) {
if ( !todo.completed ) {
openTodos++;
}
});
}
if (openTodos>0) {
// Now create the notification
chrome.notifications.create('reminder', {
type: 'basic',
iconUrl: 'icon_128.png',
title: 'Don\'t forget!',
message: 'You have '+openTodos+' things to do. Wake up, dude!'
}, function(notificationId) {});
}
}
chrome.app.runtime.onLaunched.addListener(launch);
...
showNotification()
will check for open (uncompleted) todo items. If there is at least one open
todo item, create a notification popup via chrome.notifications.create()
.
The first parameter is an uniquely identifying notification name. You must have an id set in order
to clear or handle interactions with that particular notification. If the id matches an existing
notification, create()
first clears that notification before making a new notification.
The second parameter is a NotificationOptions
object. There are many options for rendering
the notification popup. Here we are using a "basic" notification with an icon, title, and message.
Other notification types include images, lists, and progress indicators. Feel free to return to this
section when you are done Step 3 and experiment with other notification features.
The third (optional) parameter is a callback method that should take on the format:
function(string notificationId) {...};
Handle notification interactions
Open the Todo app when the user clicks on the notification. At the end of background.js, create a
chrome.notifications.onClicked
event handler:
chrome.notifications.onClicked.addListener(function() {
launch();
});
The event handler callback simply calls the launch()
method. chrome.app.window.create()
either
creates a new Chrome App window if one doesn't already exist, or brings into focus the currently
open window that has the window id of main
.
Launch your finished Todo app
You are done Step 3! Reload your Todo app now with reminders.
Check these behaviors work as expected:
- If you don't have any uncompleted todo items, there are no popup notifications.
- If you click on the notification when your app is closed, the Todo app will open or come into focus.
Troubleshooting
Your final background.js file should look like this. If notifications are not showing up, confirm that your Chrome is version 28 or higher. If notifications still don't show up, check for error messages in the DevTools Console on both the main window (right click > Inspect Element) and the background page (right click > Inspect Background Page).
For more information
For more detailed information about some of the APIs introduced in this step, refer to:
- Declare Permissions ↑
- chrome.alarms ↑
- chrome.alarms.onAlarm ↑
- chrome.alarms.create() ↑
- chrome.alarms.clear() ↑
- chrome.alarms.getAll() ↑
- chrome.notifications ↑
- chrome.notifications.create() ↑
- NotificationOptions ↑
- chrome.notifications.onClicked ↑
Ready to continue onto the next step? Go to Step 4 - Open external links with a webview »