Posts Tagged ‘User Experience’
More jQuery Magic – iPhone Style Password Box
I like to think of myself as a technology-neutral developer that can look past any Microsoft-Apple rivalries and instead focus on the best tool for the job…
I like to think that — but I know that I’m a total Microsoft fanboy… 🙂
So wouldn’t you know it that my entire FAMILY has been purchasing Apple stuff lately? Each (adult) family member has an iFail iPhone (except me, of course), my brother has an iTouch, sister-in-law with MacBook – Blasphemy! From my own flesh and blood!! ACK!!
However, despite this treachery I did discover that I did like the way that Apple handled inputting passwords.
iPhone Style Password Box
It’s worth mentioning up front that this code is just an experiment — it’s not a finished product and probably shouldn’t be pasted into a live site.
If you’ve used an iPhone before then you’ve probably noticed that you can see the last character you entered when inputting your password. This character disappears after a moment or two or the next time you enter a character. Using some jQuery and a hidden password field I attempted to create something similar.
Now unfortunately, by using a div
instead of an input
I’ve taken away the ability to select the characters in the field. When I was working on this I had an idea that I might try using the ‘contenteditable’ property instead and then display the normal password box for browsers that don’t support it.
Why Not A Input[Type=Text]
I tried doing a similar idea with by using a regular text box and just masking the characters on the fly, but ran into a problem where pasting a password would cause the whole thing visible for a moment — which seems like too much of a risk.
Another Approach
The basic idea of the Apple style password box was to show the most recently entered character but the first example lost some of the usability of a normal password box. I figured I’d give the idea a second pass, but adjusted it to be a little more HTML friendly.
You’ll notice in this version that the characters actually float up as you enter them. Similar to before, after a few moments, or when you press a new key, they will disappear.
This version is better from a usability standpoint, but it does have a couple problems of its own. For example, if you enter a really long password then the floating box stops moving at the end — no big deal right? Well for the end of the box, no, it looks fine — but if you click back out in the middle then your floating hints may be off-centered.
Simple But Effective Interface Designs
The code above isn’t ready for publishing, but they are some interesting examples of how you can take a typical form element and use a little jQuery to make some great usability enchancements to them.
You may have read some of my earlier jQuery posts about mimicking Vista style password boxes or creating search highlighting for web pages and noticed that it doesn’t take that much code to transform the functionality of your pages.
How do you enhance your pages for your visitors? It doesn’t take much!
Simulate Threading Using Javascript
One of the cool things about .NET is how easy it is to create more than one thread for your application to run on. On a recent project I had to make many calls to different web services on our network. They were all identical, but each call took quite awhile, roughly around 2 or 3 seconds each.
Instead of doing one at a time, I created 10 separate threads and then merged the results together. Instead of taking around 20 seconds, the calls were reduced to the length of the slowest call. (Web Services also have an Asynchronous method to call a service, so that is an alternative as well).
So What Does This Have To Do With Javascript?
In Javascript, any long running process will cause a noticeable lag for a user. Buttons won’t respond, links don’t do anything, the screen may even turn white — clearly not the user experience we want to deliver.
Recently I was experimenting with joining records using jLinq. jLinq was doing fairly well with the records I was using – I had about 850 records to join against a handful (about 10) of other records. The process finished in around 250ms to 500ms. I was pretty satisfied — until I tried a different set of records…
A different set of records, around 90, crippled the browser. After about 8 seconds the browser finally released itself and we were back in business. Yikes.
Simulating A Thread
So what are the options here? Well unless someone has built threading into Javascript then we’re forced to come with a more creative solution — enter setTimeout.
If you’ve read some of my blog posts before, you know I’m a big fan of enclosures. Using Javascript we can take advantage of both enclosures and setTimeout to try and simulate threading and reduce the time a browser is locked up.
So let’s say we’re working with a really large loop, say around 500,000 records – What can we do? One idea is to break up the work into smaller, more manageable chunks.
//loops through an array in segments var threadedLoop = function(array) { var self = this; //holds the threaded work var thread = { work: null, wait: null, index: 0, total: array.length, finished: false }; //set the properties for the class this.collection = array; this.finish = function() { }; this.action = function() { throw "You must provide the action to do for each element"; }; this.interval = 1; //set this to public so it can be changed var chunk = parseInt(thread.total * .005); this.chunk = (chunk == NaN || chunk == 0) ? thread.total : chunk; //end the thread interval thread.clear = function() { window.clearInterval(thread.work); window.clearTimeout(thread.wait); thread.work = null; thread.wait = null; }; //checks to run the finish method thread.end = function() { if (thread.finished) { return; } self.finish(); thread.finished = true; }; //set the function that handles the work thread.process = function() { if (thread.index >= thread.total) { return false; } //thread, do a chunk of the work if (thread.work) { var part = Math.min((thread.index + self.chunk), thread.total); while (thread.index++ < part) { self.action(self.collection[thread.index], thread.index, thread.total); } } else { //no thread, just finish the work while(thread.index++ < thread.total) { self.action(self.collection[thread.index], thread.index, thread.total); } } //check for the end of the thread if (thread.index >= thread.total) { thread.clear(); thread.end(); } //return the process took place return true; }; //set the working process self.start = function() { thread.finished = false; thread.index = 0; thread.work = window.setInterval(thread.process, self.interval); }; //stop threading and finish the work self.wait = function(timeout) { //create the waiting function var complete = function() { thread.clear(); thread.process(); thread.end(); }; //if there is no time, just run it now if (!timeout) { complete(); } else { thread.wait = window.setTimeout(complete, timeout); } }; }; // Note: this class is not battle-tested, just personal testing on large arrays
This example class allows us to pass in a loop and then supply a few actions for us to use on each pass. The idea here is that if we do a section, pause for the browser to catch up, and then resume work.
How exactly do you use this? Well let’s just say we have a really large loop of strings we’re wanting to compare…
var array = [];
for (var i = 0; i < 500000; i++) {
array.push("this is some long string");
}
[/sourcecode]
That's a lot of work to check all those - Let's move it into our new class we created...
[sourcecode language='javascript']
//create our new class
var work = new threadedLoop(array);
//create the action to compare each item with
work.action = function(item, index, total) {
var check = (item == "this is some long string comparison to slow it down");
document.body.innerHTML = "Item " + index + " of " + total;
};
//another action to use when our loop is done
work.finish = function(thread) {
alert("Thread finished!");
};
//and start our 'thread'
work.start();
[/sourcecode]
If you run this test in a browser, you'll see that our page is updated as each pass of the array is completed. This way our browser remains 'responsive' to a degree, but continues to process our work in the background.
This code allows you to set a few additional properties as well as an additional function.
- chunk: The number of records to loop through on each interval. The default is numberOfRecords * 0.005.
- interval: The number of milliseconds to wait between passes. The default is 1. A longer value gives the browser more time to recover, but makes the loop take longer.
- wait([timeout]): Waits the number of milliseconds before canceling the thread and blocking the browser until the work finishes. If no time is provided, as in left blank, the waiting starts immediately.
Threading Possibilities?
It’s always amazing to see what enclosures can do – I’m not so sure how simple this same creation would be in Javascript without them. With a little bit of code we can create a half-way decent attempt at creating an asynchronous experience for our user, even if we have a lot of work to do.
Could your heavy client side scripts benefit from ‘threading’?