Hash in JS

Generating hashes from strings is a very handy thing to have. Surprisingly, in JavaScript, an arithmetic-operation-based algorithm is about *three times* faster than one using bit-wise operators–see for yourself. I suggested to add the most performant method as hash method to underscore.string.js.

So much about statements on stackoverflow like

The hash << 5 - hash is the same as hash * 31 + char but a LOT faster.

(cf. here)

In times of interpreted languages and virtual machines one should reconsider before applying the same old rules again.

p.s. If you know about alternative algorithms/implementations, please add them to the test and leave a comment here, I'm curious to see what else there is. Btw. I was very surprised that the neat reduce-based version failed so miserably.

Callback Method for Twitter’s Typeahead

When you start using Twitter’s typeahead, e.g. because you switched from Bootstrap 2.3 to 3.0, you will notice that it is NOT a simple drop-in replacement for Bootstrap’s original typeahead!
Before, you generated the suggestions shown to the user by implementing a callback method while creating the typeahead like this:

  source: function(query, process) { 
    ... return a list of suggestions (see doc for details) 

Since version 3, Bootstrap does not provide its own typeahead any more, instead it is using Twitter’s own implementation which seems to be a good choice at least on the long run. But it does not provide any mean for defining a callback method to provide the suggestions — no clue why.
Instead you can provide a predefined array locally, a predefined array that will be loaded on start-up, or a remote service defined by a URL.
You will find several good examples of why you need a callback method sometimes.

  • You want/have to use a Javascript library to access the service.
  • There is no database for the suggestions, they a generated on the fly, e.g.if you want to suggest sentence completion while the user types.
  • You are using Meteor’s collections holding your suggestions, thus, there is no URL you could point to.

But taking a look into the internals revealed following solution: completely by-pass the internal suggestion aggregation of Twitter’s typeahead by replacing the getSuggestions(query, callback) method of the first dataset, which we defined by local: [];.

(t = $("field")).typeahead({ local: [] });
t.data("ttView").datasets[0].getSuggestions = function(query, callback) {
  var suggestions = ... gather your suggestions here ...
  var data = [];
  for (suggestion in suggestions) { data.push(this._transformDatum(suggestion)); }

(Translated from Coffeescript on-the-fly – consider as a draft than an out-of-the-box solution.)

Happy hacking. 🙂

p.s. for Meteor users: The callback breaks each time the template gets re-rendered – despite that you use the package preserve-inputs or <#constant> due to a bug. Somehow, constant areas and that particular package do not get along with each other. Solution: removed the package and use constant areas around typeahead input fields works. This should be fixed as soon as the new template engine gets rolled out.

“An invalid or illegal string was specified” Exception in GWT

While working with canvas (drawing stuff on it) in GWT, suddenly and in a seemingly unpredictable manner I got following error message now and then from within the GWT framework code:

com.google.gwt.core.client.JavaScriptException: (NS_ERROR_DOM_SYNTAX_ERR): An invalid or illegal string was specified;

Again, GWT tricked me into thinking I am writing Java code and made me forget about that it is going to be compiled into Javascript. And because of the latter, a division by zero does not throw an DevisionByZeroException, no, it returns NaN even for native data types (there is no differentiation between double and Double in Javascript – there is only the object-version of double, which can be of value Double.NaN).

But also GWT was not prepared to handle Double.NaN. When calling canvas.getContext().drawImage(image,x,y) and one of x and y or both were Double.NaN I got the error message shown above. If you got the same… you know what to do now: check all devisions in your code for potential devisions by zero!!