Adding type annotations to JavaScript
A few people have mentioned that there is value in TypeScript for the developer to express his/her intent while writing code. e.g. "I want you to pass a string as the first parameter". TypeScript, and ES6, do this by adding in an optional type annotation.
function foo (bar:string)
{}
Given my assertion that the only way you gain any benefit from type checking is by writing ALL of your client code in TypeScript, what's to stop us from adding that type annotation now? Take the TypeScript code from before and specify the type like so:
function foo(bar/*string*/)
{}
Ugly? Yes. But it has the benefit of being stripped out if you minify your JS before deployment while not requiring you to use a compiler and still communicates the intent.
Because really, isn't type checking in JavaScript really just typO checking?
Review of Building Android apps using HTML, CSS, and JavaScript
This book is the Android counterpart of “Building iPhone apps using HTML, CSS, and JavaScript” and covers much of the same material. It explains how to mark up your HTML page to support the Android mobile browser, as well as covering some basic JavaScript, HTML, and CSS. It shows how to build and submit a native Android app using the Phonegap too.
One of the the aspects that I appreciated about this book was the focus on incorporating lttle touches in your web application that make the application feel more like an Android application. Chapter 2: Basic Styling includes a section on adding the Android look and feel and the chapter on Animation adds extra features. Noting that when Android users drill down into a list, the page slides off to the left. The book also includes sections on using client-side storage to allow your application to be used offline.
Building Android Apps with HTML, CSS, and JavaScript at O'Reilly.
Announcing Bootstrap – a simple JS library for loading scripts
I ran into a problem, more than once. The problem was, I needed to use a JavaScript library on only a few pages in a site. It didn't make any sense to load the library on pages where it wasn't being used, it just added to the page load time. So I had two options:
- Make sure that I only included the library on the pages that needed it. - This wouldn't work very well because my users could create new pages based on my template. Some would need the library and some would not.
- Dynamically inject the script into the DOM only when I needed it from my JavaScript
Script tag injection is nothing new, it's been around for a long time. Neither are dynamic script loaders. YUI has had one for years, renamed to "get" in YUI3, that I've used quite a few times. LabJS and Require.JS are both full featured, well supported script loaders and work great in a wider variety of use cases. NBL was recently updated.
So why did I bother making this one?
Well, it's really not that hard to do for one thing. I love making micro-libraries like this. It has no external dependencies and the list of possible features I'd like to add is very short.
What I really wanted to do was be able to modify and existing script to dynamically load a script it was dependent on. I could see doing this in several different pages, so I put it in a library.
bootstrap("myLibrary.js", "ScriptTagId");
//or
$b("myLibrary.js","ScriptTagId");
The road map looks a little bit like this.
- Add a "script loaded" event or , more likely, allow a callback to be passed in and executed once the script has loaded.
- Add the ability to dynamically load CSS files
- make the "script tag id" parameter an optional parameter and auto-generate an ID if none is provided
- Make a cool icon for the project
So, to summarize, this library is really simple. The code is easy to understand right now. I believe is releasing early and releasing often. I didn't want the lack of features to stop me from releasing.
The code is licensed under the Apache 2.0 license.
How simple could it be? Lemme post the source code for you.
/**
Copyright 2010 Scott Koon
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
var bootstrap = (function() {
var bootstrap = function(scriptSrc, id) {
var scriptTag = document.createElement("script");
scriptTag.setAttribute("type", "text/javascript");
scriptTag.setAttribute("charset", "utf-8");
scriptTag.setAttribute("src", scriptSrc);
scriptTag.setAttribute("id", id);
var head = document.getElementsByTagName("head").item(0).appendChild(scriptTag);
};
return (window.bootstrap = window.$b = bootstrap);
}());
A third option for using jQuery templates
Dave Ward has a great post about defining jQuery templates. There's a third method that he doesn't mention in his post. The "embedd-and-grab/clone" method. I've used this method before for simple element cloning of templates.
<div id="templates">
<div id="hello">
<p>Hello, ${name}.</p>
</div>
</div>
We can create a div, or really any element you want, to hold our templates. What does this gain us? Well if we are using a design tool, we can see what the template will look like before we have to render it. That may make it easier for a designer on your project. We don't have to make an AJAX call out to retrieve the external template, although Dave talks about how this really isn't an issue if you have caching set up correctly on your server. And frankly, for the amount of bytes that are in a typical template I can't imagine any successful AJAX request taking very long.
To use them, you simply grab the templates div and detach it from the DOM. If you assign the detached elements to a var, you can just use jQuery selectors to find the one you want to use. Because, remember most of the jQuery methods return the jQuery object itself.
var templates = $("#templates").detach();
$.tmpl(templates.find("#hello").text(), person);
Why do you want to use the detach method rather than the remove method? The detach method removes the elements from the DOM but keeps any jQuery data associated with them intact. Meaning you can use the $.data() method to add data to your templates and access the data before you compile your templates.
Dave Ward points out that I need to use "tempates.find()" rather than the default selector method on the jQuery object. Noted and updated
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.
//stick the footer at the bottom of the page if we're on an iPad/iPhone due to viewport/page bugs in mobile webkit
if(navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod')
{
$("#footer").css("position", "static");
};
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:
<script id="ItemTemplate" type="text/html" <li class="item" value="|rowNumber|"> <input type=”text” id=”input|rowNumber|” /> </li> </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.
<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.
function addItem() { var list = $('#url_list'), items = list.find('li'); list.append($('#ItemTemplate’) .html().replace(/\|rowNumber\|/gi, nextUniqueItemID++)) }
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.
var nextUniqueItemID = 0;
function addItem() {
var list = $('#url_list'),
items = list.find('li');
list.append($('#ItemTemplate').html().replace(/\|rowNumber\|/gi, nextUniqueItemID++));
};
$(document).ready(function(){
var output = $('#output');
$.benchmarks = {};
$.benchmarks.test_simple = function(){
addItem();
};
$.benchmarks.loop_test = function(){
for (var i=0; i < 5; i++){
addItem();
}
};
// use these lines to run the benchmark tests in your browsers JS console
// $.benchmark(1000, '#simple_test', $.benchmarks.test_simple);
// $.benchmark(1000, '#loop_test', $.benchmarks.loop_test);
});
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.
<script id="ItemTemplate" type="text/html"> <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> </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.
function addItem() {
var list = $('#url_list'),
items = list.find('li');
list.append($('#ItemTemplate').html()
.replace(/\|name\|/gi, "Clone template method")
.replace(/\|source\|/gi, "http://girldeveloper.com/waxing-dev/easy-html-templating-with-jquery/")
.replace(/\|url\|/gi, "http://girldeveloper.com/waxing-dev/easy-html-templating-with-jquery/"));
};
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.


