I'm looking for a more efficient way to generate some DOM changes and update the .data() object.
Presently, data is provided in an array of objects and I'm building the strings in sections, appending them to the table body, and adding the .data object onto the element.
Here's a snapshot.
for (i in data.users) {
//Build the string
var rowData = "<tr class=\"";
rowData += (i%2) ? "odd":"even";
rowData +="\">";
rowData +="<td>";
rowData +=data.users[i]["FirstName"];
rowData +="</td>";
rowData +="<td>";
rowData +=data.users[i]["LastName"];
rowData +="</td>";
rowData +="<td>";
rowData +=data.users[i]["UserName"];
rowData +="</td>";
//Could be many more columns
rowData +="</tr>";
//Change the DOM, add to the data object.
$(rowData).appendTo("#list > table > tbody").data('ID', data.users[i]["ID"]);
}
I'm mostly upset over having to manipulate the DOM n times, rather than make one change with all the data-- or be able to release data as if there were a buffer. I would also like to update .data() all-at-once.
Using jQuery 1.4.3+ you can just put a data-XXX attribute into a node. That is automatically picked by jQuery into the data() hash for that node.
var Buffer = [];
for (i in data.users) {
//Build the string
Buffer.push("<tr data-ID=\"" + data.users[i]["ID"] + "\" class=\"");
Buffer.push((i%2) ? "odd":"even");
Buffer.push("\">");
Buffer.push("<td>");
Buffer.push(data.users[i]["FirstName"]);
Buffer.push("</td>");
// and so forth
Buffer.push("</tr>");
}
$("#list > table > tbody").append(Buffer.join(''));
I am assuming that the data is coming from some server-side source somewhere. Why don't you using something like jqGrid in which you'll pass a JSON object (or XML or etc.) from your server (AKA, all manipulation is done server side) and then just display the data to the users. The graphs that jqGrid generates are very nice and you won't need to do all the work you are currently doing.
take a look at the jquery templates plugin .. still in beta but very nice!
http://api.jquery.com/category/plugins/templates/
I would vote for not putting that information in the DOM at all. Use a JS model to manage that data, then query it as needed. This keeps the DOM uncluttered and properly and efficiently separates semantic markup and the data that supports/drives it. MVC ftw!
Related
I have jqGrid parent and another jqGrid child in a popup dialoag. The parent jqGrid has already a set of records in it and whenever I add new set of records from child jqGrid to parent jqGrid, I am losing the existing data from the parent jqGrid.
I tried the following.
concat the data from the parent to the child and then set it to the parent jqGrid.
var gridParent = jQuery("#parentGrid");
var existingRowsInParentGrid = gridParent.jqGrid('getGridParam','data');
var gridChild = jQuery("#childGrid");
var newRowsInChildGrid = gridChild .jqGrid('getGridParam','data');
var json = existingRowsInParentGrid.concat(newRowsInChildGrid );
//set the new concatnated data to parent
gridParent.jqGrid('setGridParam', {data: json}).trigger('reloadGrid');
Tried to use
Object.assign(existingRowsInParentGrid, newRowsInChildGrid)
Tried to use the extend feature.
var sum = jQuery.extend(existingRowsInParentGrid, newRowsInChildGrid );
It simply replaces the existing records with the new set of records. I am not adding records one at a time but setting the data in bulk. Does this make the difference?
I see lots of code, which tells me to add one record at a time. I was hoping that there will one way where we just need to add the whole set of new records at the end of the existing records.
Since you do not post the configuration of both grids it is difficult to help.
In most cases it is better to read the up to date documentation, rather than to read some posts. If you do not know addRowData can add multiple rows at once.
For more info refer the docs here (search for addRowData method)
Thanks, Tony.
I've found the solution after doing trial and error. Below is what I did which worked for me, perhaps it might help someone else!
Find the number of rows from the first jqGrid.
var existingRowsInParentGrid = gridParent.jqGrid('getGridParam','data');
var noOfRowsInParentGrid = existingRowsInParentGrid.length;
Find the number of rows from the second jqGrid.
var noOfRowsInChildGrid = gridChild.length;
Iterate through the 2nd grid elements and add rows to the parent grid at the correct position.
for(var i = 0;i < noOfRowsInChildGrid; i++) {
gridParent.jqGrid('addRowData', noOfRowsInParentGrid +1 , gridChild[i]);
noOfRowsInParentGrid = noOfRowsInParentGrid + 1;
}
My initial intention of loading the data in bulk still did not work though. But for now, I am happy as I will not have a huge amount of data in 2nd grid.
Using DataTables 1.10,
I have a DataTable with a default sort and the user can resort by some of the other columns.
How do I detect the column by which the table is currently sorted?
Some context which may not be relevant to answering the question: What I'm really trying to do is "export" the table to a non-interactive HTML table. This DataTable is generated programmatically and then turned into a DataTable, so after some searching for export options it looks like it will be easier to essentially regenerate the original table than to actually export. But I need the regenerated table to have the rows in the same order as the current sort.
The current sort state sortInfo can be retrieved like this:
var apiObject = $("#myPlainTable).DataTable( dtOptions );
// ...
var sortInfo = apiObject.settings().order()
More specifically, the column and direction are encoded like this:
var sortCol = sortInfo[0][0]; // counting from left, starting with 0
var sortDir = sortInfo[0][1]; // either "asc" or "desc"
Caveats:
The sortInfo object will have the above format after the user changes the sorting; if you specify the initial sort by setting dtOptions.order using a different format, then the sortInfo object will have the original value you specified until the user changes the sorting. (For example, DataTables will accept [1,'asc'] in addition to the above [[1,'asc']]; I didn't test what happens if you pass a value DataTables can't use.)
This describes the default case where you sort by one column only, not using the multi-column sort feature.
When you are using dataTables 1.10.x already, why not use the API? By that it is easy :
table.rows().data()
returns an array of arrays containing the current content of the table, i.e the rows as they are currently sorted. So if you want to export or clone the content of a dataTable to a static table, you can actually do it very simple :
$("#clone").click(function() {
var cloneTable = '';
table.rows().data().each(function(row) {
cloneTable += '<tr><td>' + row.join('</td><td>') + '</td></tr>';
})
$('#cloneTable tbody').html(cloneTable);
})
demo -> http://jsfiddle.net/zuxm2e68/
If sending to the server you check the
order[i][column]
order[i][dir]
for column and direction. See here
Since you are using 1.10, you can use the following:
var table = $('.myTable').dataTable({ /* Your options */ });
var sortArray = table.api().settings().aaSorting; // gives array
If you are using API already via $('.myTable').DataTable({...}), you can omit the .api().
Let's say I want to store some custom value in a element, I would need:
$('div').data('k','v');
But now I need to add more data to that element: v2.
The only way I could come up with is to somehow store or reference the previous data, and append to it, but it doesn't look like the best way to do it nor the most efficient:
$('div').data('k','v');
var prevData = $('div').data('k');
$('div').data('k',prevData + ',v2');
alert($('div').data('k'));
This will alert v,v2 as it should, but is this the correct approach?
You can use lists as data attributes:
$('.selector').data('test', []);
var list = $('.selector').data('test');
list.push('foo')
It's pretty useful, also because you can fill data- attributes with JSON in the HTML at page generation time, and .data() will automatically convert them to normal JS objects.
if you are using array as data atribute, you can do this
$('.selector').data('list', []);
$('.selector').data('list').push(1);
$('.selector').data('list').push(2);
$('.selector').data('list'); // Will return [1,2]
I have a grid in ExtJS where I am looping store items. I'd like to find a find to access the item's HTML element, but I'm having hard time finding the way to do this.
Simply put: how do you find the corresponding row HTML element for grid store's one record?
Use its index in the store to retrieve the corresponding row, like so:
var htmlElement = grid.getView().getRow(index);
ExtJS 4.x: grid.getView().getNode(index)
getNode can take an HTML ID (not very useful), an index, or a store record.
Just to add a little to it, if you've got a record that exists in a store that has a grid, but it came from say a separate ajax request, you might do
var objFromJSON: {
id: 134,
name: "Articulated Lorry"
}
var gridIndex = Ext.getStore("myStore").find("id", objFromJSON.id);
var htmlElement = grid.getView().getRow(gridIndex);
Is there a pattern to extract structured data from an HTML page using XPath? I'm trying to extract data from one or more HTML tables on a page. XPath makes it easy to find the table(s), but I'm struggling once I've got that far.
I'm currently doing the following:
Iterate the tables (there may be more than one)
Iterate the rows within that table
Iterate the cells within that row
(Then probably put them in an array and parse the contents)
My code is something like this:
var tables = mydoc.evaluate( "//table", mydoc, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null );
table = tables.iterateNext();
while (table)
{
var rows = mydoc.evaluate("tbody/tr", table, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
row = rows.iterateNext();
while (row)
{
var tds = mydoc.evaluate("td", row, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null)
td = tds.iterateNext()
while(td)
{
// TODO: store content in an array to process later
print('*' + td.textContent);
td = tds.iterateNext();
}
row = rows.iterateNext();
}
table = iterator.iterateNext();
}
This seems a little nasty as all the XPath examples seem to do their processing in one step. There appear to be few non-trivial examples where two types of data (e.g. labels and values in a table) are selected and combined. I can use the following selectors, but I end up with two lists with no structure:
//table/tbody/tr/td[#class='label']
//table/tbody/tr/td/a[#class='value']
(I know I'm using XPath for HTML parsing for which it wasn't really intended, but it seems to work so far.)
There appear to be few non-trivial
examples where two types of data (e.g.
labels and values in a table) are
selected and combined. I can use the
following selectors, but I end up with
two lists with no structure:
//table/tbody/tr/td[#class='label']
//table/tbody/tr/td/a[#class='value']
Use:
//table/tbody/tr/td[#class='label']
|
//table/tbody/tr/td/a[#class='value']
This single XPath expression selects all the wanted nodes (all XPath engines I am aware of return the selected nodes in document order). The | (union) operator produces the set union of its arguments.
If the (x)Html document has regular structure, you may expect in the returned result every selected td element (label) to be followed by its corresponding a element (value)
If it's on the main HTML page, you could just do:
for(var tables=document.getElementsByTagName("table"),i=0;i<tables.length;++i)
for(var rows=tables[i].getElementsByTagName("tr"),j=0;j<rows.length;++j)
for(var cells=rows[j].getElementsByTagName("td"),k=0;k<cells.length;++k)
print("*"+cells[i].textContent);
getElementsByTagName does /not/ return an array - it returns a live NodeList similar to ORDERED_NODE_ITERATOR_TYPE.