Lazycoder

27May/108

Quick jQuery hack to fix position:fixed toolbars in iPhone/iPad/iPod Touch

This is just a quick fix if your postion:fixed elements end up in weird places when your site is viewed on the iPhone, iPad, or iPod Touch.

Say you have a div with an id of "#footer" that you want to stay at the bottom of the page. If you set it's position to "fixed" and set the bottom to "0px". When viewed on an iPad, iPhone or iPod Touch, the footer may end up in the middle of your content if you have a long page.

CODE:
  1. //stick the footer at the bottom of the page if we're on an iPad/iPhone due to viewport/page bugs in mobile webkit
  2. if(navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod')
  3. {
  4.      $("#footer").css("position", "static");
  5. };

10Dec/097

Benchmarking a simple DOM based cloning template

Sara Chipps recently posted a simple DOM based clone template method she uses in one of her apps. "Easy HTML Templating with JQuery"

My template looks like this:

CODE:
  1. <script id="ItemTemplate" type="text/html"
  2.         <li class="item" value="|rowNumber|">
  3.               <input type=”text” id=”input|rowNumber|” />
  4.         </li>
  5.     </script>


Now within my code I need to put a place holder where I want my HTML to go. I have my unordered list called url_list.

CODE:
  1. <ul id="url_list"></ul>

Now, you see that most of my items look like this “|rowNumber|” I have a variable in my code called nextUniqueItemID (I believe in extremely descriptive variable names). Here is my “addItem” function.

JAVASCRIPT:
  1. function addItem() {
  2.         var list = $('#url_list'),
  3.                       items = list.find('li');
  4.         list.append($('#ItemTemplate’)
  5.                                     .html().replace(/\|rowNumber\|/gi, nextUniqueItemID++))
  6.     }

The use of global variables aside (cough,cough),I looked at it and, having used something like this myself, thought that it would work find for data sets containing a very small number of items. The problem is these kinds of clone based templates are VERY slow compared to the templating engines that are available for various JavaScript libraries.

I happened to read a post by Brian Landau called "Benchmarking Javascript Templating Libraries" this morning and wondered just HOW MUCH slower is the naive template method than a good template library?

I grabbed the benchmarking code and modified it to run the new clone based template method.

JAVASCRIPT:
  1. var nextUniqueItemID = 0;
  2.     function addItem() {
  3.         var list = $('#url_list'),
  4.         items = list.find('li');
  5.         list.append($('#ItemTemplate').html().replace(/\|rowNumber\|/gi, nextUniqueItemID++));
  6.     };
  7.    
  8.     $(document).ready(function(){
  9.         var output = $('#output');
  10.         $.benchmarks = {};
  11.    
  12.       $.benchmarks.test_simple = function(){
  13.         addItem();
  14.       };
  15.      
  16.       $.benchmarks.loop_test = function(){
  17.         for (var i=0; i <5; i++){
  18.           addItem();
  19.         }
  20.       };
  21.  
  22.       // use these lines to run the benchmark tests in your browsers JS console
  23.       // $.benchmark(1000, '#simple_test', $.benchmarks.test_simple);
  24.       // $.benchmark(1000, '#loop_test', $.benchmarks.loop_test);
  25.     });

Since the template Sara provided contains an input tag you get a different benchmark if you run the simple_test and the loop_test separately after refreshing your browser. You can run the tests for yourself here, the loop test *may* cause your browser to give you a "script is running slow" message, hit continue as the loop will eventually end. You may also get different numbers if you run the tests in IE, Chrome, and Safari.

results: using FF 3.5.5
Simple Test: 1.71s
Loop test: 31.534s

When you consider that the slowest loop test using a template library was just around 4.5s, you get a better idea of just how slow this method is when you have an input in your template.

So that's fine, but it's known that dynamically adding text inputs is slow in just about every browser and the original tests don't use inputs at all, just divs. So let's modify the template and see what the results are.

CODE:
  1. <script id="ItemTemplate" type="text/html">
  2. <div class="test"><h2>This is a test of |name|</h2><p>The homepage is <a href="|url|">|url|</a>.</p><p>The sources is: |source|</p></div>
  3. </script>

I modified the addItem function to account for the new data. n.b. The data I'm using is static, if you wanted to use a data source you would just modify this method to take in your data parameters.

JAVASCRIPT:
  1. function addItem() {
  2.         var list = $('#url_list'),
  3.         items = list.find('li');
  4.         list.append($('#ItemTemplate').html()
  5.             .replace(/\|name\|/gi, "Clone template method")
  6.             .replace(/\|source\|/gi, "http://girldeveloper.com/waxing-dev/easy-html-templating-with-jquery/")
  7.             .replace(/\|url\|/gi, "http://girldeveloper.com/waxing-dev/easy-html-templating-with-jquery/"));
  8.     };

results using FF 3.5.5 - refresh between each test
simple test: 1.285s
loop test: 3.771

results using ff 3.5.5 with no refresh between tests
simple test: 1.434
loop test: 4.227

So that's looking a little bit better. Not too much slower than the template libraries.

So what do the template libraries give you? Well the replace method works find provides your data is escaped properly. But say instead of a url in the "source" replacement, you use a file path like "file:\\foodrive\source.txt". Well it still gets replaced, but the text looks like this "file:\foodrivesource.txt". So in addition to the replacement, you have to make sure your data is properly escaped. A lot of template libraries will do this for you. Also notice that the addItem method has to do a DOM lookup on every iteration of the loop to get the template. If you have a large DOM, this could impact the performance.

29Sep/093

A new JavaScript CDN from Microsoft

Microsoft announced a new Content Delivery Network for their ASP.NET AJAX JavaScript libraries and jQuery. This means that instead of hosting those libraries on your server, you can just link to the versions on Microsofts server. I made a simple page that takes a querystring parameter (q=) and uses the ASP.NET AJAX dynamic templates to bind search results from a call to the Bing API.

The money lines in the source are the following:

CODE:
  1. <script type="text/javascript"
  2. src="http://ajax.microsoft.com/ajax/beta/0909/MicrosoftAjax.debug.js"></script>
  3.  
  4. <script type="text/javascript"
  5. src="http://ajax.microsoft.com/ajax/beta/0909/MicrosoftAjaxTemplates.js"></script>

These two lines tell the browser to load the MS AJAX scripts from the CDN. There are some security concerns around the fact that the files are served from the microsoft.com domain. Both Google and Yahoo serve there files from a separate, non-cookied domain (googleapis.com and yahooapis.com respectively). Hopefully, these fears will be unfounded.

On a side note, it is surprisingly easy to use the Bing API if you are familiar with script tag injection. The easiest way is to put an empty script tag in your page.

CODE:
  1. <script id="jsonResults" type="text/javascript"></script>

And then just create your Bing URL and set the script elements src attribute to the URL you created.

CODE:
  1. function MakeSearchRequest(searchPhrase)
  2.             {
  3.                 var req = "http://api.bing.net/json.aspx?"
  4.                 + "AppId=" + YOUR API KEY GOES HERE
  5.                 + "&Query=" + searchPhrase
  6.                 + "&Sources=Web"
  7.                 + "&JsonType=callback"
  8.                 + "&JsonCallback=BuildResults";
  9.                
  10.                 $get("jsonResults").src = req;
  11.             };

Filed under: Javascript, Web, jQuery 3 Comments
13Aug/092

JavaScript: Not for the faint at heart?

JavaScript: A tool too sharp?

Script# (Script Sharp) – writing javascript in C#

Both Jimmy and roy have great posts discussing JavaScript. Roy is looking at it as a C# developer lured by the many, many articles about how jQuery is the only thing that makes JavaScript worth using and using Script# to abstract away some of the messiness and pain usually associated with writing JavaScript. Jimmy discusses the merits of JavaScript itself and how it has changed how he approaches writing C# code.

One thing I like to point to is a great quote I heard on Twitter

Java is to JavaScript as ham is to hamster

hamster2.jpg

JavaScript actually has more in common with Scheme or Lisp than it does Java or C#. I first realized this when I saw that Douglas Crockford had re-written all of the examples in The Little Schemer
in JavaScript. It's easy to miss that fact when you see all of the pseudo OOP noise like "var foo = new Foo();". But when you see how trvial it is to implement something like a map method in JavaScript, you realize how powerful the language can be. Most of the hatred for JavaScript comes from two things I've found:

  1. Broken DOM implementations - every browsers implementation of the DOM is broken in one respect or another.
  2. A misunderstanding of either scope or inheritance.

Roy has a great point about the lack of good tooling surrounding JavaScript. There are excellent libraries like jQuery and PrototypeJS, but the usual tool support, intellisense, re-factoring, profiling, is a little more difficult to come by. I'll address this in another post as I feel a lot of people are new to JavaScript and are struggling along with some substandard tools.

12Aug/094

A simple map function for plain JavaScript arrays

So this isn't anything new, but sometimes you have to work with plain JavaScript and can't lean on a library. I thought I'd put this out there. This is my map function. There are many like it, but this one is mine.

CODE:
  1. Array.prototype.map = function(fn) {
  2.               var r = [];
  3.               var l = this.length;
  4.               for(i=0;i<l;i++)
  5.               {
  6.                   r.push(fn(this[i]));
  7.               }
  8.               return r; 
  9.             };

note bene: Why do I declare the "l" variable at all instead of just checking i against this.length directly? The JavaScript for loop is much faster if you don't perform the length lookup and instead check against a static value.

Filed under: Javascript 4 Comments
4Aug/095

jQuery tip – beware anonymous functions in your event handlers

jQuery makes it really easy to wire up event handlers using anonymous functions.

CODE:
  1. <script type="text/javascript">
  2.     $(document).ready(function()
  3.     {
  4.         $("#Button1").click(function(event)
  5.         {
  6.             alert("You Clicked Me!");
  7.         });
  8.     });
  9. </script>

In this case you are just wiring up one element to an event. Lets consider the case where you have a larger number of elements on the page and want to hook up to a click event on each one.

CODE:
  1. $(document).ready(function(){
  2.             for(var i =0;i<10000;i++)
  3.             {
  4.                 $("#bigContainer").append("<input type='button' class='clickybutton' id='button" + i + "' value='button" + i + "'> ");
  5.             };
  6.            
  7.             $(".clickybutton").click(function(e){
  8.                 alert(e.target.id);
  9.             });
  10.         });

In this case, a new anonymous function will be created for each element on the page. This can waste a lot of memory. It's sometimes better to use event delegation. That is, to let the event bubble up to a single containing element which then determines a course of action for the element that was clicked.

CODE:
  1. $(document).ready(function(){
  2.             for(var i =0;i<10000;i++)
  3.             {
  4.                 $("#bigContainer").append("<input type='button' class='clickybutton' id='button" + i + "' value='button" + i + "'> ");
  5.             };
  6.             $("#bigContainer").click(function(e){
  7.                 if($(e.target).hasClass("clickybutton"))
  8.                     alert(e.target.id);
  9.             });
  10.         });

If you want to learn more about JavaScript, I'd recommend reading the following books:

Filed under: Javascript 5 Comments