<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>tag:blog.danieljanus.pl,2019:category:mobile-safari</id>
  <title>Daniel Janus – Mobile-Safari</title>
  <link href="http://blog.danieljanus.pl/category/mobile-safari/"/>
  <updated>2011-07-08T00:00:00Z</updated>
  <author>
    <name>Daniel Janus</name>
    <uri>http://danieljanus.pl</uri>
    <email>dj@danieljanus.pl</email>
  </author>
  <entry>
    <id>tag:blog.danieljanus.pl,2011-07-08:post:meet-my-little-friend-createtree</id>
    <title>Meet my little friend createTree</title>
    <link href="http://blog.danieljanus.pl/meet-my-little-friend-createtree/"/>
    <updated>2011-07-08T00:00:00Z</updated>
    <content type="html">&lt;div&gt;&lt;p&gt;I’ve recently been developing an iPhone application in my spare time. I’m not going to tell you what it is just yet (I will post a separate entry once I manage to get it into the App Store); for now, let me just say that I’m writing it in JavaScript and HTML5, using [PhoneGap][1] and [jQTouch][2] to give it a native touch.&lt;/p&gt;&lt;p&gt;After having written some of code, I began testing it on a real device and encountered a nasty issue. It turned out that some of the screens of my app, containing a dynamically-generated content, sometimes would not show up. I tried to chase the problem down, but it seemed totally random. Finally, I googled up [this blog post][3] that gave me a clue.&lt;/p&gt;&lt;p&gt;My code was using jQuery’s &lt;code&gt;.html()&lt;/code&gt; method (and hence &lt;code&gt;innerHTML&lt;/code&gt; under the hood) to display the dynamic content. It turns out that, on Mobile Safari, using &lt;code&gt;innerHTML&lt;/code&gt; is highly unreliable (at least on iOS 4.3, but this seems to be a long-standing bug). Sometimes, the change just does not happen. I changed one of my screens, to build and insert DOM objects explicitly, and sure enough, it started to work predictably well.&lt;/p&gt;&lt;p&gt;So I had to remove all usages of &lt;code&gt;.html()&lt;/code&gt; from my app. The downside to it was that explicit DOM-building code is much more verbose than the version that constructs HTML and then sets it up. It’s tedious to write and contains much boilerplate.&lt;/p&gt;&lt;p&gt;To not be forced to change code, the above-quoted article advocates using a pure-JavaScript HTML parser outputting DOM to replace jQuery’s &lt;code&gt;.html()&lt;/code&gt; method. I considered this for a while, but finally decided against it — I didn’t want to include another big, complex dependency that potentially could misbehave at times (writing HTML parsers is &lt;em&gt;hard&lt;/em&gt;).&lt;/p&gt;&lt;p&gt;Instead, I came up with this:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs javascript"&gt;&lt;span class="hljs-keyword"&gt;function&lt;/span&gt; &lt;span class="hljs-title function_"&gt;createTree&lt;/span&gt;(&lt;span class="hljs-params"&gt;tree&lt;/span&gt;) {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (&lt;span class="hljs-keyword"&gt;typeof&lt;/span&gt; tree === &lt;span class="hljs-string"&gt;&amp;#x27;string&amp;#x27;&lt;/span&gt; || &lt;span class="hljs-keyword"&gt;typeof&lt;/span&gt; tree === &lt;span class="hljs-string"&gt;&amp;#x27;number&amp;#x27;&lt;/span&gt;)
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-variable language_"&gt;document&lt;/span&gt;.&lt;span class="hljs-title function_"&gt;createTextNode&lt;/span&gt;(tree);
    &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; tag = tree[&lt;span class="hljs-number"&gt;0&lt;/span&gt;], attrs = tree[&lt;span class="hljs-number"&gt;1&lt;/span&gt;], res = &lt;span class="hljs-variable language_"&gt;document&lt;/span&gt;.&lt;span class="hljs-title function_"&gt;createElement&lt;/span&gt;(tag);
    &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; (&lt;span class="hljs-keyword"&gt;var&lt;/span&gt; attr &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; attrs) {
        val = attrs[attr];
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (attr === &lt;span class="hljs-string"&gt;&amp;#x27;class&amp;#x27;&lt;/span&gt;)
            res.&lt;span class="hljs-property"&gt;className&lt;/span&gt; = val;
        &lt;span class="hljs-keyword"&gt;else&lt;/span&gt;
            $(res).&lt;span class="hljs-title function_"&gt;attr&lt;/span&gt;(attr, val);
    }
     &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; (&lt;span class="hljs-keyword"&gt;var&lt;/span&gt; i = &lt;span class="hljs-number"&gt;2&lt;/span&gt;; i &amp;lt; tree.&lt;span class="hljs-property"&gt;length&lt;/span&gt;; i++)
        res.&lt;span class="hljs-title function_"&gt;appendChild&lt;/span&gt;(&lt;span class="hljs-title function_"&gt;createTree&lt;/span&gt;(tree[i]));
    &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; res;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is very similar in spirit to &lt;code&gt;.html()&lt;/code&gt;, except that instead of passing HTML, you give it a data structure representing the DOM tree to construct. It can either be a string (which yields a text node), or a list consisting of the HTML tag name, an object mapping attributes to their values, and zero or more subtrees of the same form. Compare:&lt;/p&gt;&lt;p&gt;Using &lt;code&gt;.html()&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs javascript"&gt;&lt;span class="hljs-keyword"&gt;var&lt;/span&gt; html = &lt;span class="hljs-string"&gt;&amp;#x27;&amp;lt;p&amp;gt;This is an &amp;lt;span class=&amp;quot;red&amp;quot;&amp;gt;example.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;#x27;&lt;/span&gt;;
$(&lt;span class="hljs-string"&gt;&amp;#x27;#myDiv&amp;#x27;&lt;/span&gt;).&lt;span class="hljs-title function_"&gt;html&lt;/span&gt;(html);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using &lt;code&gt;createTree&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs javascript"&gt;&lt;span class="hljs-keyword"&gt;var&lt;/span&gt; tree = [&lt;span class="hljs-string"&gt;&amp;#x27;p&amp;#x27;&lt;/span&gt;, {},
            &lt;span class="hljs-string"&gt;&amp;#x27;This is an &amp;#x27;&lt;/span&gt;,
            [&lt;span class="hljs-string"&gt;&amp;#x27;span&amp;#x27;&lt;/span&gt;, {&lt;span class="hljs-string"&gt;&amp;#x27;class&amp;#x27;&lt;/span&gt;: &lt;span class="hljs-string"&gt;&amp;#x27;red&amp;#x27;&lt;/span&gt;}, &lt;span class="hljs-string"&gt;&amp;#x27;example.&amp;#x27;&lt;/span&gt;]];
$(&lt;span class="hljs-string"&gt;&amp;#x27;#myDiv&amp;#x27;&lt;/span&gt;).&lt;span class="hljs-title function_"&gt;empty&lt;/span&gt;().&lt;span class="hljs-title function_"&gt;append&lt;/span&gt;(&lt;span class="hljs-title function_"&gt;createTree&lt;/span&gt;(tree));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A side benefit is that it is just as easy to build up a tree dynamically as it is to create HTML, and the code often gets clearer. Note how the &lt;code&gt;createTree&lt;/code&gt; version above does not mix single and double quotes which is easy to mess up in the &lt;code&gt;.html()&lt;/code&gt; version.&lt;/p&gt;&lt;/div&gt;</content>
  </entry>
</feed>
