0

Using jQuery I'm doing a call to my server which returns some json. I then have a callback defined using .done to create a callback, which doesn't seem to behave sequentially.

I've got a div in my html (<div id="properties"></div>), and I try to fill that div with a table of results:

request.done(function(data){
    if (data['result'].length == 0) {
        $("#properties").html("<h3>No results were found..</h3>");
    } else {
        $("#properties").html("<table><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody>");
        data['result'].forEach(function(prop){
            $("#properties").append("<tr>");
            $("#properties").append("<td>prop.status</td>");
            $("#properties").append("<td>prop.title</td></tr>");    
        });
        $("#properties").append("</tbody></table>");
    }
});

The result I get is this:

<div id="properties">
    <table class="table table-hover"><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody></tbody></table>
    <tr></tr>
    <td>prop.status</td>
    <td>prop.title</td>
</div>

I know that .done is only called once the ajax call returns something, but withint that call, it should behave sequentially right? There are 2 things I really really don't understand here:

  1. Why do the table row and data get written after the </table> tag?
  2. And why on earth does the <tr></tr> gets written before the <td> tags, even though the last </tr> is appended together with the last <td> in the lastappend()` in the foreach loop?

So I also tried appending the whole table row in one go:

$("#properties").append("<tr><td>prop.status</td><td>prop.title</td></tr>");

This works a bit better, but still only produces this:

<div id="properties">
    <table class="table table-hover"><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody></tbody></table>
    <tr><td>prop.status</td><td>prop.title</td></tr>
</div>

Javascript has puzzled me before, but this really blows my mind. Any tips are welcome!

5
  • 2
    html('<table>') adds full table like html('<table></table>'); Commented Oct 19, 2014 at 12:43
  • 1
    This is not how works append() which appends full DOM node, not only part Commented Oct 19, 2014 at 12:44
  • @A.Wolff - So how do I build the table in parts using jQuery then? Commented Oct 19, 2014 at 12:45
  • 4
    You should either generate full table content as string and then html(tableString) or make a selector like $('#properties table') and work with it Commented Oct 19, 2014 at 12:46
  • @u_mulder - Awesome! That solved it! If you add your comment as an answer I can accept it. Commented Oct 19, 2014 at 12:50

3 Answers 3

4

What you are seeing here are tags closing out on you, because those elements are getting created in whole on append/html. In order to get the behavior you're expecting build in a string, say something more like this:

request.done(function(data){
    if (data['result'].length == 0) {
        $("#properties").html("<h3>No results were found..</h3>");
    } else {
        var propertiesTableHTML = "<table><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody>";
        data['result'].forEach(function(prop){
            propertiesTableHTML += "<tr>";
            propertiesTableHTML += "<td>" + prop.status + "</td>";
            propertiesTableHTML += "<td>" + prop.title + "</td>";
            propertiesTableHTML += "</tr>";
        });
        propertiesTableHTML += "</tbody></table>";
        $("#properties").html(propertiesTableHTML);
    }
});
Sign up to request clarification or add additional context in comments.

Comments

1

You are expecting .html() and .append() to work like document.write() but they don't. When used with HTML, they expect proper HTML. Broken HTML (for example missing end tags) is corrected which leads to the unexpected behavior. This part of your code for example:

$("#properties")
    .html("<table><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody>");

Produces the following result:

<table>
    <thead>
        <tr>
            <th>Status</th>
            <th>Title</th>
        </tr>
    </thead>
    <tbody>
    </tbody><!-- tag closed automatically -->
</table><!-- tag closed automatically -->

Along the same lines, this code:

 $("#properties").append("<tr>");
 $("#properties").append("<td>prop.status</td>");
 $("#properties").append("<td>prop.title</td></tr>");   

Produces the following result:

...
</table>
<tr></tr><!-- tag closed automatically -->
<td>prop.status</td>
<td>prop.title</td><!-- </tr> ignored -->

One possible solution is to revise your code like this:

$("#properties").html("<table><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody></tbody></table>");
data['result'].forEach(function(prop){
    var $tr = $("<tr></tr>").appendTo("#properties > table > tbody");
    $("<td></td>").text(prop.status).appendTo($tr);
    $("<td></td>").text(prop.title).appendTo($tr);
});

Comments

0

You can't add tags to the DOM, you can only add elements. When you try to add a <table> tag, it will add a complete table element. When you try to add the ending tag, it will be ignored (or possibly cause an error, depending on the browser) because it's not code that can be parsed into an element.

Rewrite the code to add elements instead of tags:

$("#properties").html("<table><thead><tr><th>Status</th><th>Title</th></tr></thead><tbody></tbody></table>");
var tbody = $("#propertis tbody");
data['result'].forEach(function(prop){
  var row = $("<tr>");
  row.append($("<td>").text(prop.status));
  row.append($("<td>").text(prop.title));
  tbody.append(row);
});

By creating table cells as elements and use the text method to set the content, you avoid the problem with any special characters that would need HTML encoding (e.g. <. >, &) to mess up the HTML code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.