HTML5 Download Attribute: Success!

HTML5 Download Attribute Success Meme

Providing direct and easy download of files can be simplified using the HTML5 download attribute. Historically, forcing a browser to save a file has been an over complicated programming task. New HTML5 specifications have identified this gap in browser technology and have mapped out a straightforward approach to downloading resources using the new download attribute on anchor and area elements. In this post, I will briefly outline the challenges that developers had before the download attribute was available and then show how simple it is to implement.

Direct Download Challenges

Historically, there have been a number of different methods developers could try to employ to force a file to be downloaded in the browser. One popular choice is to use JavaScript to open a new window pointed at the file. Unfortunately, if the Content Type header of the HTTP response from the server is a MIME Type that the browser knows how to handle, the browser will simply open the file in the newly opened browser window. This approach can work for files that a browser is not used to handling (executables etc.) but will not work for common web files like images.

docuement.getElementById("download-button").addEventListener("click", function() {
            window.open(urlToFileLocation);
        });

Another more complicated approach involves writing server side code (C#, PHP, Java) that would receive an HTTP request, process it based on whatever logic is needed, and return a response that included the file with a Content-Disposition field set to attachment. This is a more reliable approach and can handle any file type the server is capable of serving up, but requires access to server side code and greater level of effort.

// ASP.NET C# Example
Response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.WriteFile(filePath);
Response.Flush();
Response.End();

The download attribute

(At the time of this writing, the feature is not available in IE or Safari. Click here for existing support.)

Thankfully, with new HTML5 specifications for Downloading Resources, this additional effort can now be avoided by adding a single download attribute to any link.

<a href="download-success.jpg" download>Download Meme</a>

Here is the above link in action:  Download Meme

This approach is very straightforward and has the potential to save time and headaches for developers moving forward. Support for IE and Safari is still missing, but since the the target file is referenced in the href of the link, if a browser is missing support for the download attribute, it will attempt request the file like any other link.

Detect Device Battery Level via JavaScript

battery-half

I’ve recently come across a handy feature that allows web applications to detect device battery level via javascript from the browser. Currently, the spec for this interface (Battery Status API) is in Working Draft status with W3C but will hopefully see wider adoption in coming months. Google Chrome and Opera have already adopted this feature for desktop and there appears to be early support for Chrome on Android.

At first glance, this might seem like a trivial piece of information that a web app would want to access, but the more I think about it, I see a lot of potential especially in the context of mobile. If an application can detect battery level and charging status it could be smart enough to throttle data requests, save progress to avoid data loss. It could even be used behind the scenes as a diagnostic tool to determine where an application is a power suck.

The Battery Manager Interface

Detecting a device battery level and charging status is done through the Battery Manager interface via a Promise. This object is accessible via the navigator object in the browser. When the promise is returned there are a number of read only properties available are:

  • level (double): Current battery level from 0 to 1.0
  • charging (boolean): Represents if a device is charging
  • chargingTime (unrestricted double): Set to 0 if battery is full or there is no battery attached to the device. Set to Infinity if the battery is discharging.
  • dischargingTime (unrestricted double): Set to Infinity if the battery is charging.

The initial call is very straightforward:

navigator.getBattery().then(function (batt) {
    // Access to interface properties here                
});

Events Available

Along with the read only properties on the interface, there are a handful of events that get fired. They are fairly straight forward and mirror the available properties:

  • onlevelchange (levelchange): Event added to the browser queue when battery level property changes
  • onchargingchange (chargingchange): Event added to the browser queue when charging property changes
  • onchargingtimechange (chargingtimechange): Event added to the browser queue when chargingTime property changes
  • ondischargingtimechange (dischargingtimechange): Event added to the browser queue when dischargingTime property changes

Battery Level via Javascript Example

To accompany this post I’ve put together a quick example that illustrates accessing properties on the interface as well as firing the onlevelchange and onchargingchange events. You can see live demo here (Remember, you will need to use Chrome or Opera).

(function () {

            //#region Constants
            var NOT_APPLICABLE = "N/A";
            //#endregion

            //#region Helper Methods
            function setBatteryLevel(level, callback) {
                document.getElementById("level").innerHTML = "Battery Level: " + level;

                if (callback &amp;&amp; typeof (callback) === "function") {
                    callback();
                }
            };

            function setChargingStatus(status, callback) {
                document.getElementById("charging").innerHTML = "Charging Status: " + (status === NOT_APPLICABLE ? NOT_APPLICABLE : (status === true ? "Charging" : "Un-plugged"));

                if (callback &amp;&amp; typeof (callback) === "function") {
                    callback();
                }
            };
            //#endregion

            try {

                navigator.getBattery().then(function (battery) {
                    // When initial promise from navigator.getBattery() is recieved set the current statuses.
                    setBatteryLevel(battery.level);
                    setChargingStatus(battery.charging);

                    battery.onlevelchange = function (evt) { // Event info is available as param
                        var _level = battery.level;
                        setBatteryLevel(_level, function () {
                            console.log("Battery level changed: " + _level, battery);
                        });
                    };

                    battery.onchargingchange = function (evt) { // Event info is available as param
                        var _charging = battery.charging;
                        setChargingStatus(_charging, function () {
                            console.log("Battery charging status changed: " + _charging, battery);
                        });
                    }
                });
            }
            catch (e) {
                // Catch the error if navigator.getBattery isn't defined
                document.getElementById("error").innerHTML = "Unable to retrieve battery status. You may be using an incompatible browser.

\
            At the time of this demo, the Battery Status API is only available in Google Chrome 38+ or Opera 25+ and is in Working Draft status.

\
            Error Message: " + e;

                // Update
                setBatteryLevel(NOT_APPLICABLE);
                setChargingStatus(NOT_APPLICABLE);

            }
        })();

Want to Learn More?

The following are a few valuable links on the subject:

Need motivation blogging as a developer?

I started this blog back in January with the best intent to post to it frequently. Initially my motivation was high. I was able to produce what I thought were a few well written posts on diverse subjects. But then, like so many other bloggers, I hit a wall. Every time I sat down to write something I would look at what I had already posted and had no idea what my next post should look like.  This led me to the question: Why is blogging as a developer so hard?

Free Blog Course

My frustration combined with this unanswered question led me where most developers default to when they are in this type of situation…Google.

It wasn’t long in this search before I came across a few references to a free email course available from John Sonmez so I decided to check it out. Initially, I was a pretty skeptical. The landing page where you can sign up for the course seems like a “too good to be true” shady marketing form (Sorry John). But, I figured I wasn’t making much progress on my blog so why not?

What I Learned

Fast forward one month, I have completed the course and I am so happy that I did. Each email in the course had great content that opened my eyes quite a bit as to where and why I was struggling. I won’t go into too much detail of the course in this post, but I do want to share my key takeaways:

  • Find a niche: A great point that John makes in the course is that for a blog to be successful, it needs to be focused on a niche. One of the reasons I have been struggling with writing consistently was I wasn’t focused enough on a particular topic. (When you actually set out to define a niche, it can be harder than you think. It actually took a number of email exchanges with John for me to finally nail one down.)
  • Plan your posts: Coming up with an idea for a post and then actually writing it all in one sitting is less than ideal. When you do have time to write, it is much easier to pick from a list that you maintain and have already put some thought into.
  • “Just Post It”: To generate traffic, you need to have content. To have content, you need to actually post something. It is very common to be hesitant to post something you have written that you feel isn’t perfect but at the end of the day, if you aren’t producing content your blog will never grow.

Try It Out

Like I mentioned above, I found the course to be worthwhile. If you are interested in signing up for the course, you can find it here. Also, to learn more about John Sonmez, check out his website: http://simpleprogrammer.com