views:

144

answers:

2

I am currently building a very dynamic table for a list application, which will basically perform basic CRUD functions via AJAX.

What I would like to do is separate the visual design and javascript to the point where I can change the design side without touching the JS side. This would only work where the design stays roughly the same(i would like to use it for rapid protyping)

Here is an example.

<table>
<tr><td>record-123</td><td>I am line 123</td><td>delete row</td></tr>
<tr><td>record-124</td><td>I am line 124</td><td>delete row</td></tr>
<tr><td>record-125</td><td>I am line 125</td><td>delete row</td></tr>
<tr><td>add new record</td></tr>
</table>

Now, when I add a new record, I would like to insert a new row of html, but I would rather not put this html into the javascript file.

What I am considering is creating a row like this on the page, near the table.

<tr style='visble:none;' id='template-row'><td>record-id</td><td>content-area</td><td>delete row</td></tr>

And when I come to add the new row, I search the page for the tags with the id=template-row , and then grab it, do a string replace on it, and then put it in the right place in the page.

As long as the design doesn't shift radically, and I keep the placeholder strings the same, it means designs can be quickly modified without touching the js.

Can any give any advice on a methodology like this?

+6  A: 

Take a look at John Resig's Micro-Templating.

Use:

<script type="text/html" id="row_tmpl">
    <tr><td><%=id%></td><td><%=content%></td><td>delete row</td></tr>
</script>

<script type="text/javascript" src="templating.js"></script>
<script type="text/javascript">
    (function(){
       var dataObject = {"id":"myid","content":"some content"};
       var html = tmpl("row_tmpl", dataObject);
       // do whatever you want with the new HTML...
    }());
</script>

NOTES
As there are some SO users that are rightfully concern with XSS attacks using this approach I just want to point out that the micro-templating function provides ways to circumvent the problem. Any javascript within the <% %> tags will be executed. So if you have a function that cleans input of malicious content you can call it within these <% %> tags.

David Murdoch
Unfortunately this, like most examples with ‘micro-templating’, introduces a client-side cross-site-scripting security hole due to lack of HTML-escaping of the `content`.
bobince
what are you talking about?
David Murdoch
Imagine your data object contains user input (as it usually does). The user has decided to input `Hello <script>sendToMaliciousServer(document.cookie);</script>`. Allow that to get inserted into the HTML without escaping the `<`​s and you've got a problem. We've spent a long, long time trying to get people to fix HTML injection problems at the server side; let's not introduce them at the client-side too.
bobince
Just as the templating function will allow a malicious user to run some arbitrary JS it will allow the developer to run some code to HTML-escape the content. E.G.: `<%=cleanEvilFromContent(content)>` will insert the return value of the cleanEvilFromContent function.
David Murdoch
Having a little trouble with this, I'm using it with .net mvc, so I think the tags used in the tempate are conflicting, I've changed that over but I'm getting another error now. I think this is the right idea, but I'll have to see if I can get it working.
optician
yah, the `<% %>` tags won't work when using .net. You will need to change them out with your own set of tag like `<* *>`. You will need to update them in both your template and the templ function.
David Murdoch
I went for the django style {% %}, but still having a little bug. Still this is exactly the kind of answer I was looking for regardless of if I can get it working or not, so thank you.
optician
+1  A: 

grab it, do a string replace on it, and then put it in the right place in the page.

String replace? If it's in the page, you've got a DOM node already. There's no need to go around serialising your node to an HTML string, hacking it around and re-parsing it into a DOM node. That way lies madness and cross-site-scripting security holes as you forget to escape your text for HTML.

Instead, use cloneNode to get a copy of the DOM objects, change the bits you need to, and add it into the document.

<style type="text/css">
    .hidden { display: none; }
</style>

<table id="sometable">
    <tr class="hidden"><td>-</td><td>-</td><td>delete row</td></tr>
</table>
<input type="button" id="sometable-newrow" value="New row"/>

<script type="text/javascript">
    var recordn= 1;

    document.getElementById('sometable-newrow').onclick= function() {
        var table= document.getElementById('sometable');
        var tr= table.rows[0].cloneNode(true);

        tr.className= ''; // remove hiddenness
        tr.cells[0].firstChild.data= 'record-'+recordn;
        tr.cells[1].firstChild.data= 'I am line '+recordn;
        tr.cells[2].onclick= removeRow;

        table.rows[table.rows.length-1].parentNode.appendChild(tr);
        recordn++;
    };

    function removeRow() {
        var tr= this.parentNode;
        tr.parentNode.removeChild(tr);
    }
</script>
bobince