So, the situation is this. There is a HTML page with a table in it, that is using the DataTables plugin. I have to show data that I'm receiving from a jQuery POST call in the table, but I always seem to get errors and am lost in how to go about doing that.
This is what the response from the POST call looks like:
[{"idoperatore":10,"nome_cognome":"Daniele Torrini","tariffa_esterno":"50.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":11,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"DT"},{"idoperatore":12,"nome_cognome":"Irene Cavalletto","tariffa_esterno":"75.00","tariffa_interno":"45.00","tariffa_viaggio":"30.00","idtariffa_esterno":9,"idtariffa_interno":15,"idtariffa_viaggio":13,"attivo":1,"rs":1,"iniziali":"IC"},{"idoperatore":14,"nome_cognome":"Sandra Moschetti","tariffa_esterno":"50.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":11,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"SM"},{"idoperatore":15,"nome_cognome":"Federica Coucourde","tariffa_esterno":"90.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":8,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"FC"},{"idoperatore":16,"nome_cognome":"Matteo Belgero","tariffa_esterno":"75.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":9,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"MB"},{"idoperatore":17,"nome_cognome":"Luca Belgero","tariffa_esterno":"90.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":8,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"LB"},{"idoperatore":18,"nome_cognome":"Federico Bottoni","tariffa_esterno":"50.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":11,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"FB"},{"idoperatore":19,"nome_cognome":"Giuseppe Pantaleo","tariffa_esterno":"60.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":10,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"GP"},{"idoperatore":20,"nome_cognome":"Matteo Ferrario","tariffa_esterno":"90.00","tariffa_interno":"75.00","tariffa_viaggio":"30.00","idtariffa_esterno":8,"idtariffa_interno":9,"idtariffa_viaggio":13,"attivo":1,"rs":1,"iniziali":"MF"},{"idoperatore":21,"nome_cognome":"Alessandro Mazzeranghi","tariffa_esterno":"100.00","tariffa_interno":"0.00","tariffa_viaggio":"30.00","idtariffa_esterno":7,"idtariffa_interno":16,"idtariffa_viaggio":13,"attivo":1,"rs":0,"iniziali":"AM"}]
I have no way of modifying the call, I have to work with that. I just have access to the variable that contains that response from the callback, but I can however transform or modify that data if needed.
This is what the HTML table looks like:
<table class="display nowrap" id="table_operatori">
<thead>
<tr>
<th>
<span></span>
</th>
<th class="mdl-data-table__cell--non-numeric">Nome e Cognome</th>
<th>Tariffa Esterno</th>
<th>Tariffa Interno</th>
<th>Tariffa Viaggio</th>
<th>Attivo?</th>
<th>RS?</th>
<th class="mdl-data-table__cell--non-numeric">Iniziali</th>
</tr>
</thead>
<tbody id="table_operatori_tbody">
</tbody>
</table>
There are not the same number of columns in the table as fields in the JSON because the fields in JSON starting with "id" have to be hidden values, and were used before as attributes of the HTML elements, to use them in later moments. It's also the reason for the empty header: the table was actually filled with pure HTML before, and had a checkbox in front to select the row, like this:
data.forEach(function (element) {
element["attivo"] == "1" ? element["attivo"] = "Si" : element["attivo"] = "No";
element["rs"] == "1" ? element["rs"] = "Si" : element["rs"] = "No";
var i = element['idoperatore'];
var tableRow = '<tr><td><label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select" for="table_operatori_checkbox_row[' + i + ']"><input type="checkbox" id="table_operatori_checkbox_row[' + i + ']" class="mdl-checkbox__input" onClick="fOperatore_Checkbox_SelectUnique(' + i + ')" /></label></td>'
tableRow += '<td class="mdl-data-table__cell--non-numeric" id="table_operatori_nomecognome_row[' + i + ']">' + element['nome_cognome'] + '</td>';
tableRow += '<td id="table_operatori_tariffaesterno_row[' + i + ']" idtariffa="' + element["idtariffa_esterno"] + '">' + element['tariffa_esterno'] + '</td>';
tableRow += '<td id="table_operatori_tariffainterno_row[' + i + ']" idtariffa="' + element["idtariffa_interno"] + '">' + element['tariffa_interno'] + '</td>';
tableRow += '<td id="table_operatori_tariffaviaggio_row[' + i + ']" idtariffa="' + element["idtariffa_viaggio"] + '">' + element['tariffa_viaggio'] + '</td>';
tableRow += '<td id="table_operatori_attivo_row[' + i + ']">' + element['attivo'] + '</td>';
tableRow += '<td id="table_operatori_rs_row[' + i + ']">' + element['rs'] + '</td>';
tableRow += '<td class="mdl-data-table__cell--non-numeric" id="table_operatori_iniziali_row[' + i + ']">' + element['iniziali'] + '</td></tr>';
$("#table_operatori_tbody").append(tableRow);
This worked, in a sense, (apart from being extremely ugly) meaning that the table formed and you could select rows like we wanted and act on those later. But you couldn't sort, or filter with search, any of the rows in the table.
Still, I was willing to maintain the ugly HTML building if it meant getting the DataTable to work, since with .row.add() you can add a element, I tried that as well, changing the .append(tableRow) with:
.DataTable().row.add($.parseHTML(tableRow));
This didn't work either, and gave the same error. Also displayed this on the table though: Displays object picture
At the moment of initialization, I don't have the data to put inside the table. The table has to be initialized empty, and rows from the response added at a later time. I tried (with "data" being the variable containing the response from the server):
$("#table_operatori").DataTable().rows.add(data);
Which would remove a lot of the ugly HTML building, but it gives error:
DataTables warning: table id=table_operatori - Requested unknown parameter '1' for row 0, column 1. For more information about this error, please see http://datatables.net/tn/4
So, by looking at that tech-notes link, it says that it may be that you have more columns in the table head than in the table body, so I matched exactly the fields that I get, when defining the table, thinking that I may eventually be able to hide the columns that I don't need if that works.
$("#table_offerte").DataTable({
paging: false,
info: false,
columns: [
{ title: "idoperatore" },
{ title: "nome_cognome" },
{ title: "tariffa_esterno" },
{ title: "tariffa_interno" },
{ title: "tariffa_viaggio" },
{ title: "idtariffa_esterno" },
{ title: "idtariffa_interno" },
{ title: "idtariffa_viaggio" },
{ title: "attivo" },
{ title: "rs" },
{ title: "iniziali" }
]
});
But it still gives the same error. It also does if I match the table structure with the DataTable initialization :
columns: [
{ title: "idoperatore" },
{ title: "nome_cognome" },
{ title: "tariffa_esterno" },
{ title: "tariffa_interno" },
{ title: "tariffa_viaggio" },
{ title: "attivo" },
{ title: "rs" },
{ title: "iniziali" }
]
Documentation from DataTables also says that it looks inside a data: property when looking at JSON data, and you have to specify if it is not an object but an array by setting an empty string in the dataSrc property:
DataTable({ ajax: { url: "something.json", dataSrc: "" } });
The problem is that it requires the data being requested by the url: property, and I cannot do that, because I only have the "data" variable which contains the JSON.
I should also mention that by maintaining the old HTML building and appending it inside the table body, makes the table work and display stuff right, like this, but of course as soon as you try to sort or filter anything, it all disappears because the DataTable doesn't ACTUALLY have the rows inside it, just the HTML does.
I have no idea how to get this data in there. I hope I explained everything clearly, otherwise feel free to ask anything and I will try my best to clarify.
Thanks in advance for any help.
The doc is a bit confusing, because there are so many different ways to set up a table, and it's pretty much one guy (Allan Jardine) both writing the plugin and documenting it.
First, you don't need any table headers. Change your HTML to this:
<table class="display nowrap" id="table_operatori"></table>
If you want to add ids or classes to tbody tags, then you'll need to add them in as well. But to start, this is all the HTML you need.
What's confusing here is that a lot of Allan's examples include the data hard-coded into the HTML, with no JSON or AJAX or anything involved. When you do that, then you do need to set up the HTML headers, and all the cells, and everything else. Take a look at the HTML in one of his examples (this one, for example) and see this for yourself. And then, when he moves on to JSON examples, he pulls the data but he leaves the headers in. And again, you can put them in, but don't have to.
Rather, if you're pulling your data from JSON, you can either specify your headers with HTML th tags or you can do it with the columns (or colDefs) option. You don't need to do both. This isn't as clear from the doc as it might be, since in most of the examples Allan does do both.
Whichever way you specify the headers, they have to match the column count of the JSON feed. If they don't, you'll get some form of the error you're getting. Furthermore, if you use both column and th, they both have to match your JSON field count or you'll get that error. That's why you're getting your error. You matched your columns definition correctly, but you've left some th tags out in your table definition. The solution is to remove the th tags entirely.
I'm going to presume that the reason that you left out some th tags is that you are under the impression that that's the way to make the column invisible. It isn't, for the reasons I've described above. The easiest way to define whether a column is visible or not (as well as define a lot of other possible attributes, listed here) is in your columns array: just set the column's visible option to false. (You could also use th tags with a class and set visibility:none in CSS, but this is simpler. Less to keep track of.)
Also, the title value on a column is the value for title in your columns array for that column. So, you need to make it look the way you want it, not put the name of your JSON field there.
Finally, with the data option, you're reading the wrong part of the documentation, which is about how to pull JSON from a URL using AJAX at the time you run dataTable(). You have the data already in your POST data, so you don't need to do that. So, read this instead. Have a look at the second example, which shows an array of objects as a data source. From what I see of your JSON string, you should just have to add an option like this:
data: myPOSTResponse,
Putting all that together:
$("#table_offerte").DataTable({
paging: false,
info: false,
data: myPOSTResponse,
columns: [
{ visible: false }, //this is the ID you don't want to see, no need to give it a title
{ title: "Nome e Cognome", className: "mdl-data-table__cell--non-numeric" },
{ title: "Tariffa Esterno" },
{ title: "Tariffa Interno" },
{ title: "Tariffa Viaggio" },
{ visible: false },
{ visible: false },
{ visible: false },
{ title: "Attivo?" },
{ title: "RS?" },
{ title: "Iniziali", className: "mdl-data-table__cell--non-numeric" }
]
});
That should get you running, if you haven't done something else interesting. :)
Edit: as DocCobra mentions in the comments, you also have to specify the data: option at the field level here, since the array elements are objects. If they are themselves arrays, you do not.
I have a similar question in which I didn't have the right data in a fiddle to show. What the other question shows is doing a table row clone, but my data is table append to a div
The jQuery $.each loop shows where I have a dynamically created the title (tooltip)
This is the fiddle: http://jsfiddle.net/bthorn/Lpuf0x7L/1/
$.each(allData, function (index, issues) {
strResult += "<tr><td class='nameField'> <a href='#'>" + issues.LAST_NAME + " " + issues.FIRST_NAME + " " + issues.INITIALS + "</a></td><td>" + issues.OFFICE + "</td><td>" + issues.TITLE + "</td>";
strResult += "<td>" + issues.DEPARTMENT + "</td><td class='alias'>" + issues.ALIAS_NAME + "</td>";
// NEED TO ADD QTIP to the issues.DEPARTMENT title tooltip //////
addTooltips();
/////////
strResult += "</tr>";
});
strResult += "</table>";
$("#divEmpResult").html(strResult);
My old question from a few hours with OP answer should be helpful
dynamic javascript data with qtip is overriding all tooltips with same message
I am trying to call this function but i know that I needs to have additional data from qtip appended to it.
OP was doing a .insertBefore(this) but I am not sure how to do that with my table row
$('button').on('click', function() {
$('<div/>', {
class: 'tips',
text: 'Dynamically inserted.'
}).insertBefore(this);
addTooltips();
In the second code snippet, the addTooltips function was called after the dynamic element(s) were inserted into the DOM via the .insertBefore() method.
In your first code snippet, you are calling the addTooltips function before the elements are actually appended, which is why it isn't working as expected:
$("#divEmpResult").html(strResult);
addTooltips(); // Call the function *after* the elements exist in the DOM
In order to prevent the previous tooltips from being overridden, negate all the elements with data-hasqtip attributes. You can also set the tooltip text based on the title attribute, or some pre-defined defaults like in the example below:
$('.tips:not([data-hasqtip])').each(function() {
$(this).qtip({
content: {
text: $(this).attr('title') || 'This is the message!'
},
hide: {
fixed: false
},
position: {
corner: {
target: 'topLeft',
tooltip: 'bottomRight'
}
}
});
});
To address your last issue where the tooltips only included the first word, you need to enclose the title attribute value in quotes. Previously, your HTML was being rendered like: title=some words here, which resulted in the browser automatically inserting quotes around the first white-space separated word and turning the following words into separate attributes.
Working Example Here
The title attribute value needs to be enclosed in quotes:
strResult += '<td class="tips" title="' + issues.DEPARTMENT + '">' + issues.DEPARTMENT + '</td><td class="alias">' + issues.ALIAS_NAME + '</td>';
To avoid mistakes like this, I would highly suggest using a JS templating engine such as handlebars.
I am developing an app where users can perform CRUD operations on multiple data models (aka. DB tables). I am using Dojo and I am quite happy with the dojox.grid module. But users also need to add records, so there has to be an Add Dialog for each table.
Is there a way/module that generates a Dojo grid and an Add Dialog given only the data structure of the model? Sort of like the structure parameter of dojox.grid, so that both the grid and the add Dialog have the same data types, default values, contraints etc.
Of course I could write a custom widget that would just do that but I am looking for something existing here.
The answer is, no there is no such module. You'd need to build a derived dialog.
Lets see whats needed;
The current grid
the grid layout (celltypes)
names and labels (structure)
Assuming there is one 'Add contents' button defined pr-grid and that this button 'knows' the ID of the said grid, its onClick function should fire up a form in dialog.
While there are dijit.form Widgets there's also a range of predefined cellTypes, residing under dojox/grid/cells/_base.js. Lets make a map where type and widget is 1to1:
var map = [{
type: 'dojox.grid.cells.Cell',
dijit: 'dijit.form.TextBox'},
{
type: 'dojox.grid.cells.Bool',
dijit: 'dijit.form.CheckBox'},
{
type: 'dojox.grid.cells.Select',
dijit: 'dijit.form.Select'},
{
type: 'dojox.grid.cells.DateTextBox',
dijit: 'dijit.form.DateTextBox'}
];
In our addContents function we will make use of the 'editable' functionality in the dojox.grid.DataGrid. When we know there's a such - there is certainly also a function pr-cell that generates the DOM. This is the formatEditing function which is present in any cellType.
// for instance
dojox.grid.cells.Select.prototype.formatEditing( /* value */ "", /* row */ -1);
Only thing thats needed is to construct the contents which should be shown in the dialog - following uses the above mentioned functionality and provides dijit suitable markup for presentation in a dijit.Dialog.
function addContents(gridId) {
var grid = dijit.byId(gridId);
var contents = ['<form action="MySubmitUrl" data-dojo-type="dijit.form.Form"><table>'];
dojo.forEach(grid.layout.cells, function(cell, idx) {
var szHtml = cell.formatEditing("", -1);
var dijitType = map.filter(function(e) {
return e.type == cell.declaredClass;
})[0].dijit;
var name = grid.structure[0][idx].field;
var label = grid.structure[0][idx].name;
var elementMod = ' data-dojo-type="' + dijitType + '" id="' + name + '" name="' + name + '" ';
contents.push('<tr><td>');
contents.push('<label for="' + name + '">' + label + ': </label>');
contents.push('</td><td>');
contents.push(szHtml.replace(/^([^\ ]*)/, "$1" + elementMod));
contents.push('</td></tr>');
});
contents.push('</table></form>');
var dialog = new dijit.Dialog({
content: contents.join("")
});
dialog.show();
}
The contents is easy style-able and should also supply a submit/cancel button but im certain you get the idea. Running sample
Let me know how it runs (havent tested combobox / datetime types)
To build a menu block which should be switchable with hide/unhide of the menu items, I'm using .append html.
The code idea is this:
navigat += '<h3 class="infoH3"> <a id="' + menuID +'"'
+ ' href="javascript:slideMenu(\'' + menuSlider + '\');">'
+ menuName + '</a></h3>';
navigat += '<div id="' + menuSlider + '" style="display:none">';
navigat += ' <ul>';
navigat += ' <li>aMenu1</li>'
navigat += ' <li>aMenu2</li>'
navigat += ' <li>aMenu3</li>'
navigat += ' </ul>';
navigat += '<!-- menuName Slider --></div>';
$("#someElement").append (navigat);
This is doing well .. so far.
But the point is::
I use JS to read the required menu items (eg. 'aMenu1' together with title and/or link info) from a file to build all that, eg. for 'aMenu1' a complex is composed and $("#someElement").append(someString) is used to add that the 'someElement'.
At the moment I build those html elements line by line. Also OK .. as far as the resulting string has the opening and closing tag, eg. "<li>aMenu2</li>".
As can be seen from above posted code there is a line "<div id="' + menuSlider + '" style="display:none">".
Appending that -- AFAIS -- the .append is automatically (????) adding "</div>" which closes the statement.
That breaks my idea of the whole concept! The menu part isn't included in the 'menuSlider '.
QQ: How to change it -- NOT to have that "</div" added to it??
Günter
You could change you method around to use document fragment style creation and an object to populate the properties on the elements, like this:
var someElement = $("#someElement");
$('<h3 class="infoH3"></h3>').append($('<a />',
{ 'id': menuID,
'href': '#',
click: function() { slideMenu(menuSlider); }
})
).appendTo(someElement);
var div = $('<div />', { 'id': menuSlider, css: {display: 'none'} });
$('<ul />').append('<li>aMenu1</li>')
.append('<li>aMenu2</li>')
.append('<li>aMenu3</li>')
.appendTo(div);
div.appendTo(someElement);
This is a very different way of doing it, first we're caching the $("#someElement") object so we're not searching for it repeatedly. Then we're creating the <h3> as an object, putting the link inside, then inserting then appending the whole thing to someElement. In the last, the same approach it's creating the <div>, setting it's properties, then creates the <ul> menu and appends it inside...then appends that whole div to someElement as well.
As a side note, I'm not sure how .slideMenu() works, but an event handler that works via $(this).parent().next() (or give the div a class) would work as well, and you wouldn't need a function with the slider argument passed.