I do have the contents of html tables stored in a database and I use jQuery to extract the data from it and place it in another table by creating JSON objects from these tables.
I get the stored table and append it to the DOM as follow:
$('#divfortable).append(storedtable);
The next step is to create my object :
var tableObject = $('# divfortable tbody tr').map(function(i) {
var row = {};
$(this).find('td').each(function(i) {
var rowName = columns[i];
row[rowName] = $(this).text().trim();
});
return row;
}).get();
where I have an existing array with the relevant column names.
The next step is to upload these details to the server:
data = { id: id, tableObject: tableObject };
$.ajax({
dataType: 'json',
url:'my_url',
data: $.param(data),
error: function(jqXHR, textStatus, errorThrown) { },
success: function(data) { }
});
It works fine and I am very happy with the results but my problem is when repeating the process on another table. I want to get a new table and extract its contents in a similar fashion but I cannot get rid of the previous result. The result contains the newly loaded table plus that of the previous table and if I repeat it once again, it contains the result of all 3 tables!
It is obvious to me that I must empty all objects and DOM elements from the previous extraction but I tried different ways, to no avail. I gathered from searching the internet and this forum that you can use delete or empty to destroy the tableObject so that you can create a brand new one, but it does not do the job.
I tried the following:
delete tableObject;
and
$('#divfortable).remove(storedtable);
in the success function, together and separately
I also used
$('#divfortable).remove(storedtable);
after I created my data object
data = { id: id, tableObject: tableObject };
but in this case the script does not progress to the ajax call, but by displaying $('#divfortable) it displayed both tables!
How can I get rid of the previous result?
You should be able to simply clear the current #divfortable before the second operation:
$('#divfortable').empty();
Related
I'm currently trying to get select2 to work, however, I'm struggling a little bit right now. What I want to achive, is fairly simple: I fetch a JSON from a webserver which consists out of key/value pairs (one ID to one string). After fetching those, I want to create options out of those and add them to select2 so they user can select one of them.
I kept as close to the code in the documentation as humanly possible:
$('#catSearchBox').select2({
width: '500px',
ajax: {
url: "url/to/data",
dataType: 'json',
delay: 250,
cache: false,
data: function (params) {
return {
searchKey: params.term
};
},
processResults: function (data, params) {
$.each(data, function(catName, catId) {
var newOption = new Option(catId, catName, false, false);
$('#catSearchBox').append(newOption).trigger('change');
});
}
},
placeholder: 'Suche nach Kategorie ...',
minimumInputLength: 3
});
Now, everything here works up until the append. When I search for anything, the options are generated correctly, however, the append seems to fail as no options are displayed at all. It looks like this:
However, it's not because of an empty or invalid response, because the options are definitely created:
I'm kinda at a loss here, I don't see why my code is not working, especially since I kept as close as possible to the code in the documentation (https://select2.org/data-sources/ajax and https://select2.org/programmatic-control/add-select-clear-items).
Does anyone have any idea on how to solve this problem? If you need any additional information I might have missed out, please let me know.
processResults Is not used to append options to the select2. It is used to transform the response from the API. It should return a valid array of objects to feed select2.
Something like:
var newData = [];
$.each(data, function(catName, catId) {
newData.push({ id: catId, text: catName });
});
return { results: newData };
I believe the main problem is in your processResults function and Select2's expectations of it.
From what I was able to partly read and partly deduce from the documentation at https://select2.org/data-sources/ajax#transforming-response-data is that processResults is supposed to return an object containing a key results and those results should be an array of objects. Further down there were some examples and one of them shows that those objects contain 2 keys - id and text.
Moreover, the info box at the top of the docs it says that select2 will create <option> only for element that was chosen (it's done for performance reasons). This implies that you are not supposed to create the <option> elements yourself, but just return the data in the expected format and select2 will take care of the rest.
This is a fiddle based on your code: https://jsfiddle.net/mkilmanas/jkx2mwv5/1/ and it doesn't work, it throws an error of trying to access results of undefined.
This is another fiddle with analogous behaviour but done according to those findings from the documentation: https://jsfiddle.net/mkilmanas/3s0kupaw/5/
I'm not sure if this is the solution but there are 2 things in your code that I don't like so much.
Try this:
processResults: function (data, params) {
// First, remove all previous elements
$('#catSearchBox').html('');
$.each(data, function(catName, catId) {
var newOption = new Option(catId, catName, false, false);
$('#catSearchBox').append(newOption);
});
// Second, fire change when all elements are appended
$('#catSearchBox').trigger('change');
}
I thought this question would have been answered but I can't work this out. Have tried:
https://datatables.net/forums/discussion/25833/is-there-any-way-to-programmatically-select-rows
https://datatables.net/reference/api/row().select()
I'm using DataTables 1.10.16 in serverSide mode - my data is loaded in via ajax as opposed to being there on page load.
My markup is simply a table with an ID, #substancesTable:
<table id="substancesTable" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>EC</th>
<th>CAS</th>
<th>Name</th>
</tr>
</thead>
</table>
The js to load the data is as follows:
var substancesTable = $('#substancesTable').DataTable({
"processing": true,
"serverSide": true,
"searching": false,
"ajax": {
"url": "/get-substances.json",
"dataSrc": function (json) {
return json.data;
}
}
});
This populates my table fine. I have an event handler such that when a user manually clicks on on a row (any <td> element inside the #substancesTable) it makes a further ajax request to obtain more data which is then populated inside the <td> that the user clicked. This code is also responsible for closing/collapsing any open rows:
$('#substancesTable tbody').on('click', 'td', function () {
var tr = $(this).closest('tr');
var row = substancesTable.row( tr );
if ( row.child.isShown() ) {
row.child.hide();
tr.removeClass('shown');
}
else {
row.child( expand_substance(row.data()) ).show();
tr.addClass('shown');
}
} );
The code above calls a function expand_substance which handles the ajax request mentioned. This all works fine.
What I'm trying to do is find a way to programatically open certain rows. What I mean by this is having an array of row ID's that the user has clicked on, e.g.
var openRows = [5, 6, 8, 33, 100];
This array data will be stored in Redis (cache) so if the user navigates away from the page, when they return, the data in openRows will be loaded and I want to open the appropriate rows. But I don't know how to tell DataTables to open rows 5, 6, 8, 33, 100, etc.
The links above don't seem to work for me. For example, if I try:
substancesTable.row(':eq(0)', { page: 'current' }).select();
I get a console error:
VM308:1 Uncaught TypeError: substancesTable.row is not a function
I'm not sure if that's even how to open the row but couldn't find any more information that helped.
So, is it possible to use JavaScript to open certain rows of the table based on an array of known ID's (openRows)?
That one was fun to resolve (hoping I did)... since it is quite complicated and tricky.
First, I have to mention that it's not possible (or at least a pain) to build a demo using the server side feature, so I used DataTable's "zero configuration" example.
Now, I hope I correctly understand that a row index array is to be previously stored from user row clicks... And that it's the starting point of the current question to reuse that array to manipulate the rows.
In my example, there are only 57 rows... So I used this array: var targets = [5, 6, 8, 33].
The solution step by step:
Use the drawCallback to run a for loop on the array.
Get the drawn rows in the right order... Which means after sort.
We need to use the row-selector along with the useful { order: 'applied' } trick.
(Found in a dataTables forum question)
Get the nodes from it.
Target the right rows, based on the array, using the jQuery .eq() method.
So we have to create a jQuery object with the row collection first (wrap with $()).
Manipulate the rows!
In my example, I just added a red background color to the child td.
You will do your things from here.
So here is the whole function:
"drawCallback": function(){
var api = this.api();
for(i=0;i<targets.length;i++){
$(api.rows({ order: 'applied' }).nodes()).eq(targets[i]).find("td").addClass("red");
console.log(targets[i]);
}
}
CodePen
Remember that rows are zero-based...
Notice that the row indexes manipulated above are after sort (so it reflects the order as currently displayed to user, not the order as supplied to Datatables from the markup or from Ajax.) That means the sorting shall be the same as when the user clicked the rows (thus saved the indexes). That may be a problem... ;)
The answer to this was provided by a colleague and makes use of the rowCallback (https://datatables.net/reference/option/rowCallback) callback which DataTables provides.
var substancesTable = $('#substancesTable').DataTable({
// ...
"rowCallback": function(row) {
var id = $(row).find('td:first').text();
var index = $.inArray(id, openRows);
if (index !== -1) {
var tr = $(row).closest('tr');
var row = substancesTable.row( tr );
row.child( expand_substance(row.data()) ).show();
tr.addClass('active');
}
}
});
This callback will post process each row (represented by row). The line var index = $.inArray(id, openRows); means is the current row (identified by the text from var id) in the array of openRows. Since the first column in my table contains the ID that's how we can get a match between var id and openRows.
If the ID is found it will then trigger a function I've written called expand_substance(). This is nothing to do with DataTables, it's a custom js function.
In my case the expand_substance() function is responsible for doing an ajax call to obtain some more details which are then populated into the row:
function expand_substance ( rowData ) {
var div = $('<div/>')
.text('Loading...');
$.ajax( {
url: '/view-substance/expand-substance/' + rowData.id,
dataType: 'html',
success: function ( data ) {
div.html(data);
}
});
return div;
}
This is only required because when the user expands a row in my application the details which are shown are obtained via an ajax request. In theory expand_substance() might not be used if the data was there on page load.
This works in my application. The other Answer provided to this post is along the right lines but does not use ajax source data, and it does not expand a row, but instead just highlights it in red. Therefore I've provided my own answer because this fully addresses the question and others may find it useful.
I have a sharepoint list where the users can create new items. Sometime the users create very similar items so they requested me to create an option to copy an existing item's data to the new item form and autofill with it (except unique/autogenerated fields). So they have to modify just few input to create a new item.
I added a new column and autofilled it with hyperlinks to the new item form (text:"copy"), but I don't know how to get the rowindexid or any unique field value of the clicked hyperlink's row and bring it to the next page. If I could do that I could easily search in the list and fill the new form. Sadly I am new to JavaScript so even after hours of research, I am not sure how to approach this, so pls lend me a hand. Thanks you very much for any idea!
Since it is not mentioned in your original question, I am making the assumption you are using SharePoint 2013+.
To start with I would add a lookup column to the field list. This will allow them to select the item they want to copy. You will need to get the ID of this element and all the other input elements in the page. for my demo i am putting them into an object. You can use Developer tools (F12 in ie or Ctrl+Shift+i for chrome).
var idsAndNames = {
"fieldName":"id of field",
....
}
Next create a function to read the data from that item and add it to the form. For the code below I am using to the Rest API. You can also use SharePoint's CSOM.
function addData(e) {
var opt = e.target.options[e.target.selectedIndex];
var idOfItem = opt.value;
$.ajax({
url: path/to/list/_api/lists/getByTitle('<name of list>')/items(idOfItem),
type: "GET",
headers: { "Accept": "application/json;odata=verbose" },
success: function (data, textStatus, xhr) {
for (var key in idsAndNames){
$(idsAndNames[key]).html(data.d[key]);
}
},
error: function (data, textStatus, xhr) {
alert('failed to get data');
}
});
}
finally add an event listener to make the changes when the user selects a different item.
$(idOfSelect).on('change', addData);
or
document.getElementById(idOfSelect).addEventListener('change', addData)
or using ES6
document.querySelector(#idOfSelect).addEventListener('change',()=>addData(data));
I found that Parse is now supported by the Buddy platform, but all the forum/help files from the old Parse website are gone...
What i would like to do is query for one row in a table by row number/index.
I now do this, but it seems inefficient to me to get all data and then select the row (although it works fine):
var thisRow = Parse.Object.extend(GlobTable);
var query= new Parse.Query(thisRow);
query.descending('updatedAt');
query.find({
success: function(results) {
var object = results[RowNumberThatINeed];
//etc using object
#Ran, thanks! Somehow it doesn't work, Parse will store '1' for every row: 1,1,1,1. But it saves all other data ok.
var Object = Parse.Object.extend(LocTable);
var obj = new Object();
obj.set("User", LocUser);
obj.set("Happened", d);
obj.set("Happy", b);
obj.set("Learned",a);
obj.set("ConnectedTo",c);
obj.increment("rowIndex");
obj.save({
success: function(obj) {
updateDatabase();
alert("Your data is saved");
},
error: function(obj, err) {
alert("Your data was not saved. Sorry..." + err);
}
});
you solution will work but you will experience a lot performance issues when your table will growth.
What i suggest to you is the following solution:
Add another field to your GlobTable of type integer. This field will be incremental field and will store your row index (let's call this field rowIndex)
Each time you save a new object to this table make sure you increment this field by using the following command:
object.increment("rowIndex");
Now your query should look like the following:
var thisRow = Parse.Object.extend(GlobTable);
var query= new Parse.Query(thisRow);
query.equalTo("rowIndex",RowNumberThatINeed);
query.first().then(function(result){
// do something with the result
},function(error){
// error handling
});
If you want event better performance you can create index (in MongoDb) on your rowIndex.
In my code snippets i use Promises according to the best practices.
I use first and not find because there will always be one object for this index
I have an ajax call that looks like so;
success: function(data) {
//Return the results of the campaign data and populate the page.
$(data).find('campaign').each(function(i) {
campaignTitle = $(data).find('campaignTitle').text(),
campaignDesc = $(data).find('campaignDesc').text(),
campaignType = $(data).find('campaignType').text(),
campaignStatus = $(data).find('campaignStatus').text(),
campaignDuration = $(data).find('duration').text(),
campaignAuthor = $(data).find('whoCreated').text(),
campaignCreated = $(data).find('dateCreated').text(),
campaignTypeText = $(data).find('type').text(),
campaignDataID = $(data).find('typeID').text(),
campaignTypeName = $(data).find('typeName').text();
});
There are 2 records being returned but the only difference in the 2 is the Data ID which I get from a relational join in my table.
My page is a single "record" with campaign details on it.
For example, there is a title of the campaign.
$('[name=campaignTitle]').empty().append(campaignTitle);
Now because its returning multiple records, its duplicating the campaign title which I understand that it will do that.
Since all of the data is the same in the rows except the data ID's, I only need to show everything one time and then I would keep the multiple ID's that it returns and do something with them.
I am trying to do something like so :
campaignTitle = $(data).find('campaignTitle')[0].text(),
This returns undefined.
In short, I only want the campaign title to show one time, even if there are 5 records and I would do this by specifying which it as [0] since I know it would be the same as 1-4.
Why don't you return a DataSet or DataTable in your return and break down the value-pairs?