1

sometimes my javascript code is mixing with html and css. in this stuation, my code is beind unreadable. How do you separate the javascript and html side in javascript?

For example: (using javascript dojo toolkit)

addLayer: function (layer, index) {                
var layerClass = layer.visible === true ? 'layer checked' : 'layer';
var html = '';
html += '<li class="' + layersClass + '">';
html += '<div class="cover"></div>';
html += '<span tabindex="0" class="info" title="MyTitle"></span>';
html += '<span tabindex="0" class="toggle box"></span>';
html += '<div class="clear"></div>';                    
html += '</li>';
var node = dom.byId('layersList');
if (node) {
    domConstruct.place(html, node, "first");
    HorizontalSlider({
        name: "slider",
        value: parseFloat(layer.opacity),
        minimum: 0,
        maximum: 1,
        showButtons: false,
        discreteValues: 20,
        intermediateChanges: true,
        style: "width:100px; display:inline-block; *display:inline; vertical-align:middle;",
        onChange: function (value) {
            layer.setOpacity(value);
        }
    }, "layerSlider" + index);

    if (!this.layerInfoShowClickHandler) {
        this.layerInfoShowClickHandler = on(query(".listMenu"), ".cBinfo:click, .cBinfo:keyup", this._onLayerInfoShowIconClicked);
    }
}                 
}

In this stuation, my code is adding html to view side dynamically. Adding event handlers to created html code. Adding additional tools(HorizantalSlider) same time. This workflow is binded one to another. This code is unreadable. Is there a way to solve this with clean code?

Phoenix Bird
  • 1,187
  • 1
  • 8
  • 22
barteloma
  • 6,403
  • 14
  • 79
  • 173
  • Where and how you use `HorizontalSlider` ? I mean is the way `HorizontalSlider` is built or your problem is with the `html` variable? – Roko C. Buljan Feb 20 '14 at 07:30

4 Answers4

2

This answer uses Dojo to split your HTML + CSS from JavaScript.

HTML template

The recommended approach is by defining your HTML template in a seperate HTML file. For example:

<li class="{layersClass}">
    <div class="cover"></div>
    <span tabindex="0" class="info" title="MyTitle"></span>
    <span tabindex="0" class="toggle box"></span>
    <div class="clear"></div>
</li>

Also notice the replacement of layersClass by a placeholder.


Load the HTML template

Now, to load the template you use the dojo/text plugin. With this plugin you can load external templates, for example by using:

require(["dojo/text!./myTemplate.html"], function(template) {
    // The "template" variable contains your HTML template
});

Converting the placeholders

To replace {layersClass}, you can use the replace() function of the dojo/_base/lang module. Your code would eventually look like:

require(["dojo/text!./myTemplate.html", "dojo/_base/lang"], function(myTemplate, lang) {
    var html = lang.replace(myTemplate, {
        layersClass: layersClass
    });
});

This would return exactly the same as your html variable, but seperated the HTML from your JavaScript code.


Seperate CSS

To seperate the CSS style from your HorizontalSlider you could define an id property and just put your CSS in a seperate CSS file. Your HorizontalSlider would become:

HorizontalSlider({
    name: "slider",
    value: parseFloat(layer.opacity),
    minimum: 0,
    maximum: 1,
    showButtons: false,
    discreteValues: 20,
    intermediateChanges: true,
    id: "mySlider",
    onChange: function (value) {
        layer.setOpacity(value);
    }
}, "layerSlider" + index);

Now you can use the following CSS:

#mySlider {
    width:100px;
    display:inline-block;
    *display:inline;
    vertical-align:middle;
}
g00glen00b
  • 41,995
  • 13
  • 95
  • 133
  • Is this way the same thing with Creating Template-based Widgets in dojo? else what difference? – barteloma Feb 20 '14 at 08:05
  • It's similar, but template based widgets use another parser. In this example I used `dojo/_base/lang::replace()`, but template based widgets use a seperate parser that also interpretes `data-dojo-attach-point` and `data-dojo-attach-event` attributes. Placeholder notation is also slightly different because in a template you would use `${layerClass}`, while now we did a similar thing, but without the dollar sign `$` (but you can override the pattern with `dojo/_base/lang`). – g00glen00b Feb 20 '14 at 08:10
1

You could store the html variable in a different place, let's say in a file called template.js. However, doing so you can't concatenate the HTML string immediately since you need to inject this layersClass variable. Here is a possible workaround :

// template.js

var template = function () {
    return [
        '<li class="', this.layersClass, '">',
            '<div class="cover"></div>',
            '<span tabindex="0" class="info" title="MyTitle"></span>',
            '<span tabindex="0" class="toggle box"></span>',
            '<div class="clear"></div>',
        '</li>'
    ].join('');
};
// view.js

html = template.call({ 
    layersClass: layerClass 
});

Effective and easy to use. However, if you want to use a template in the form of a string rather than a function, you'll need a template parser. The following one will give the same kind of result as above (notice that regex capturing is not supported by IE7 split()) :

function compile(tpl) {
    tpl = Array.prototype.join.call(tpl, '').split(/{{(.*?)}}/);
    return Function('return [' + tpl.map(function (v, i) {
        if (i % 2) return 'this["' + v + '"]';
        return v && '"' + v.replace(/"/g, '\\"') + '"';
    }).join(',') + '].join("");');
}

Usage example :

var template = '<b>{{text}}</b>';
var compiled = compile(template);
// compiled -> function () {
//     return ["<b>",this["text"],"</b>"].join("");
// }
var html1 = compiled.call({ text: 'Some text.' });
var html2 = compiled.call({ text: 'Bold this.' });
// html1 -> "<b>Some text.</b>"
// html2 -> "<b>Bold this.</b>"

Now, let's see how you could use this tool to organize your files in a clean way.

// product.data.js

product.data = [{ 
    name: 'Apple iPad mini', 
    preview: 'ipadmini.jpeg', 
    link: 'ipadmini.php',
    price: 280
}, { 
    name: 'Google Nexus 7',
    preview: 'nexus7.jpeg', 
    link: 'nexus7.php',
    price: 160
}, { 
    name: 'Amazon Kindle Fire',
    base64: 'kindlefire.jpeg', 
    link: 'kindlefire.php',
    price: 230
}];
// product.tpl.js

product.tpl = [
    '<div class="product">',
        '<img src="{{preview}}" alt="{{name}}" />',
        '<span>{{name}} - ${{price}}</span>',
        '<a href="details/{{link}}">details</a>',
    '</div>'
];
// product.view.js

var html = [];
var compiled = compile(product.tpl);
for (var i = 0, l = product.data.length; i < l; i++) {
    html.push(compiled.call(product.data[i]));
}
document.getElementById('products').innerHTML = html.join('');

Demo : http://jsfiddle.net/wared/EzG3p/.

More details here : https://stackoverflow.com/a/20886377/1636522.


This compile function might not be enough for your needs, I mean, you might quickly need something more powerful that includes conditional structures for example. In this case, you may take a look at Mustache, Handlebars, John Resig or Google "javascript templating engine".

Community
  • 1
  • 1
0

Consider using templates for building dynamic view elements

E.g:

http://handlebarsjs.com/

http://underscorejs.org/#template

Diode
  • 24,570
  • 8
  • 40
  • 51
0

One way is to use HTML (not that cool if you don't like to split your logic):

 <div style="display:none" id="jQ_addLayer">    
    <div class="cover"></div>
    <span tabindex="0" class="info" title="MyTitle"></span>
    <span tabindex="0" class="toggle box"></span>
    <div class="clear"></div>
  </div>

than in jQuery create the LI with the passed variable and insert your #jQ_addLayer content:

var html = '<li class="'+layersClass+'">'+ $("#jQ_addLayer").html() +'</li>';

Another way is to escape your string newlines:

var html = '\
   <li class="' + layersClass + '">\
     <div class="cover"></div>\
     <span tabindex="0" class="info" title="MyTitle"></span>\
     <span tabindex="0" class="toggle box"></span>\
     <div class="clear"></div>\
   </li>'; //don't forget to escape possible textual single-quotes in your string
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313