YUI Datatable - call arbitrary function *once* on sort - javascript

We're using a lot of YUI data tables to display data, and rather than using the built-in pagination we've done our own so we can paginate on the server side using AJAX without downloading the whole data set (which is often huge).
Whenever we use the data table's sorting funcionality, though, it will only sort the one page because from YUI's point of view that's the entire data set.
I need to be able to call an arbitrary function to reload the page data whenever the user tries to sort the data. I've looked into DataTable's sortFunction parameter and it's not ideal because it gets called multiple times (once for each row combination it needs) and I need to do it just once.
There are probably plenty of hacky ways I could do this, but what's the "nicest" way of going about this?

Ideally, you would sort on the server side.
when create the datatable, one of the config options is generateRequest (see this example: http://developer.yahoo.com/yui/examples/datatable/dt_bhm.html )
generateRequest is a meant to be a function which generates a URL which returns the correct data set with which to fill the table. You probably have this.
For me, whenever I click on the column header (to sort), it makes a new request to the server, getting the correct page of sorted data.

Why not write a custom function and close over a variable that tracks whether it's been called?
var hasBeenCalled = false;
function mySortFunction(){
if(!hasBeenCalled){
// do something
hasBeenCalled = true;
}
}
Then replace the sortFunction with that.

Related

Tabulator Ajax Response Blocked - setFilter

I have Tabulator nearly working as I need for a web application I am designing. This app is calling web services in a backend app written in Java.
I created an InitialFilter set, the filtering, sorting, and pagination is handled by the backend. Next, I am creating an Accordion control for the various filter inputs by the end-user. No issues yet. I created two buttons, one to Apply the filter based on the user preferences, and another to Reset/Clear the filter parameters.
The Tabulator object is already created and has the default data already showing on the page. When the user sets the custom filter and clicks the Apply button, a JQuery function captures the on-click event and executes the following code.
$(function(){
$('#btn-apply').on('click', function(e){
// handle click event of button
// Get values first
var subFrom = $('#txt-submission-from').val();
var subTo = $('#txt-submission-to').val();
// Set filters
NIBRSTable.clearFilter();
NIBRSTable.addFilter("submissionPeriod", ">=", subFrom);
NIBRSTable.addFilter("submissionPeriod", "<=", subTo);
// Call function to load data
NIBRSTable.setData();
});
});
Error Returned
Ajax Response Blocked - An active ajax request was blocked by an
attempt to change table data while the request was being made
tabulator.min.js:5:24222
I have tried commenting out one source line at a time. It appears the setFilter() calls are causing the Ajax Response Blocked error even though there is not anything actively occurring (the tabulator DOM is already loaded)
I have many more items for which the end-user may filter. The two filters shown in the code listing above are just a start.
That isn't an error message, that is just a console warning.
What it means is that multiple ajax requests have been made in quick succession and that one request has been made before the first one returned, therefore the response of the first request will be ignored so the table isn't partially redrawn.
In this case it is being triggered because you are calling the addFilter function twice in quick succession which is triggering the ajax request twice with the second filter being added before the first ajax request has been sent. (there is also no need to call the setData function, adding a filter when ajaxFiltering is enabled will automatically trigger the request).
To avoid this double ajax request you could pass an array of filter objects into the addFilter function and only call it once:
NIBRSTable.addFilter([
{
field:"submissionPeriod",
type:">=",
value:subFrom
},
{
field:"submissionPeriod",
type:"<=",
value:subTo
},
]);
Oli,
Thank you for the detailed response. Since the filters are dynamic and set by the end-user (i.e. cannot be hardcoded), I created an Object and conditionally adding the filter parameters. Using this object, I can call the NIBRSTable.addFilter(userFilter) and it works like a charm! I did make the mistake of trying to JSON Stringify the object and passing it to the addFilter method, but quickly learned JSON Stringify was unnecessary since the object array was already a JSON object.
Oddly, though I am still receiving a single warning "Ajax Response Blocked" even though there were no pending Ajax actions. I only have one .addFilter() and removed the .setData() as you responded. I will ignore for now since the filtering is working!
Ben

Attempting to use a global array inside of a JS file shared between 2 HTML files and failing

So I have one HTML page which consists of a bunch of form elements for the user to fill out. I push all the selections that the user makes into one global variable, allTheData[] inside my only Javascript file.
Then I have a 2nd HTML page which loads in after a user clicks a button. This HTML page is supposed to take some of the data inside the allTheData array and display it. I am calling the function to display allTheData by using:
window.onload = function () {
if (window.location.href.indexOf('Two') > -1) {
carousel();
}
}
function carousel() {
console.log("oh");
alert(allTheData.toString());
}
However, I am finding that nothing gets displayed in my 2nd HTML page and the allTheData array appears to be empty despite it getting it filled out previously in the 1st HTML page. I am pretty confident that I am correctly pushing data into the allTheData array because when I use alert(allTheData.toString()) while i'm still inside my 1st HTML page, all the data gets displayed.
I think there's something happening during my transition from the 1st to 2nd HTML page that causes the allTheData array to empty or something but I am not sure what it is. Please help a newbie out!
Web Storage: This sounds like a job for the window.sessionStorage object, which along with its cousin window.localStorage allows data-as-strings to be saved in the users browser for use across pages on the same domain.
However, keep in mind that they are both Cookie-like features and therefore their effectiveness depends on the user's Cookie preference for each domain.
A simple condition will determine if the web storage option is available, like so...
if (window.sessionStorage) {
// continue with app ...
} else {
// inform user about web storage
// and ask them to accept Cookies
// before reloading the page (or whatever)
}
Saving to and retrieving from web storage requires conversion to-and-from String data types, usually via JSON methods like so...
// save to...
var array = ['item0', 'item1', 2, 3, 'IV'];
sessionStorage.myApp = JSON.stringify(array);
// retrieve from...
var array = JSON.parse(sessionStorage.myApp);
There are more specific methods available than these. Further details and compatibility tables etc in Using the Web Storage API # MDN.
Hope that helps. :)

GridX clear the sort without making new request

I am using GridX to display data, but I often change the data store that the GridX is using. I do this by using grid.setStore() and pass in a Dojo JsonStore (this is asynchronous data of course). I do not recreate the grid every time I change the data store, just call setStore(), then refresh().
The grid also has the NestedSort module activated. My problem is this:
If the user sorts on a store, and then chooses a set of different data to look at, the code calls:
grid.sort.clear();
grid.setStore( /* new store*/ );
grid.refresh();
Without .clear() being called, the grid will try to sort the new store of data (which is usually invalid, and throws a 500).
With .clear(), the store will make a call to the server to sort the first data store, before then calling for a fresh batch of the next data store.
Ideally I want to tell the grid to clear any sort preference before I grab the next set of data, so that it is not attempting to sort it. I do not want it to make an additional call to sort the first data immediately before it gets replaced.
I finally worked it out. To clear the sort information in the grid you must modify the grid model. The sorting in the grid model can be done using this:
grid.model.sort();

Passing DOM elements to another page with JQuery

So, I understand this is an odd question. I have 2 pages, one that somebody fills out w/ a bunch of inputs. The next page would be a "print to pdf" type deal w/ Coldfusion. However, I want to send all the info to the next page and not lose what the person entering data has put in. Is there a way with jQuery (or some other option in CF that I haven't seen) to potentially grab the $('body') and pass it to sub in on the next page so it keeps the <input> values? I don't want to do a form submit, as there are a bunch of calculations that also take place based off those inputs that are shown, using javascript, and <cfdocument> has trouble with javascript after the fact.
I would serialize all the form input values using jQuery's serializeArray, and store it in the localStorage. In the next page, just read the localStorage and parse your data back to an object using JSON.parse.
Page 1 :
localStorage.formData = $("form").serializeArray()
Page 2 :
var formData = JSON.parse(localStorage.formData)
...aaaand you'll get all your data in an object on page 2.
Ok, so the element data to local storage worked, but the way I actually did it was writing the $('body').html() to a string, passing that using $.ajax() to a cfc file, where I wrote a text file to the CF temp directory using <cffile>, then re-rendered that text into HTML/CFML on the PDF page using <cfinclude>. Hope this helps someone if they need it!
You can cache the data for use on another page in CFML. I do this with Railo, but Adobe CF has a similar function. Any data I want to use on the next page goes in to an array of structs. I haven't tried cacheput('formdata', form), but it seems like it would work.
Page 1
// Empty cache storage
cacheClear();
// call the function to cache data
cachePut('cData', data);
Page 2
// get items from the cache
data = cacheGet('cData');

Auto refresh label in MVC View

I have an auto refresh method (something like below) in my controller. In which I will update data in ViewBag, which I use in label of view. But I'm unable to refresh my label automatically. Please help me.
var waitHandle = new AutoResetEvent(false);
ThreadPool.RegisterWaitForSingleObject(waitHandle,(state, timeout) =>
{
// my viewbag
viewbag.time = DateTime.Now.TimeOfDay;
viewbag=date
}, null, TimeSpan.FromSeconds(5), false);
MVC doesn't work like WebForms (where reassigning a value populates to the UI). You'll need to write a separate action (or WebAPI method) and use AJAX/JavaScript to pull updates. (Alternatively you could use SignalR, but that may be overkill).
Also, if this is a recurring event, you may want to look into a library like Quartz.NET to perform the action. Then, post updates to a shared resource (looks like you're storing timestamp of last execution). From there, use setInterval/AJAX on the client to retrieve and display that value.

Categories

Resources