Tabulator Ajax Response Blocked - setFilter - javascript

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

Related

How to track custom events

I have a form that has multiple drop-downs and a submit button. This form posts via ajax and returns a different result depending on the combination selected in the dropdowns. Assuming I get a desired result, I want to be able to track this combination in analytics.
I would have expected to be able to use a javascript snippet that would allow me to push the custom event, along with the custom parameters, when the ajax result has come back. However I'm finding it very difficult to understand how to do this.
I've taken a look at the GA4 / Tag Manager documentation and I can see how to create the event and parameters, but when it comes to triggers I'm not sure what to do? GA provides the option to create a button click trigger, but I don't want to capture this data when the button is clicked - I only want to capture it when the response is received from the server. Ideally I'd do something like this:
$.post('/my_endpoint',
{
dropdown1: dropdown1_value
dropdown2: dropdown2_value,
dropdown3: dropdown3_value,
dropdown4: dropdown4_value
})
.done(function (response) {
if(<my_condition>) {
// Push to GA with dropdown1_value, dropdown2_value, dropdown3_value, dropdown4_value
}
});
Is there no way via script to push this event with the required parameters? You can see I require the ability to push the event manually, rather than relying on GA's triggers.
I recall in the past I've used dataLayer.push(), however this was years ago and analytics has evolved since I've last used it. I guess I'm trying to find Google Analytics APIs for pushing custom events, or does such a thing no longer exist?
You can do a dataLayer.push() of your parameters and an event like following:
dataLayer.push({'event': 'your-event-name', 'dropdown1_value' : value1, 'dropdown2_value' : value2, ...});
So in Google Tag Manager you have to create a dataLayer variable for how many values of dropdwon you want to pass. Then you have to create a GA4 Tag with the name you want, you enter the parameters with the values you retrieve from the dataLayer variables and as trigger you use an event named 'your-event-name'.

JavaScript - Promise fulfilled too early?

I created a small sample application using VueJs and created a C# REST API to store and retrieve data in a SQL Server back end.
For testing, I created a simple web page with a form to create a "note". The note is stored by the following function, 'saveData()':
saveData()
{
let promiseStack = [];
var jsondata = JSON.stringify(this.note);
promiseStack.push(this.$http.post('REST_API/note', jsondata));
Promise.all(promiseStack).then(data =>
{
this.$http.get('REST_API/note');
this.$router.push({ name: 'viewnotes', params: { id: data[0].body.id }})
}, error =>
{
console.log(error);
});
}
I tried to use a promise to wait until the 'store' operation in the backend is complete, and issue a GET request to retrieve all notes once the promise is fulfilled.
However, the get request inside the promise doesn't return any data. If I issue the get request manually later one, I retrieve the data that was stored previously.
So I had look into the C# REST API. There are currently two functions: createNote(...), getAllNotes(...). I used a StreamWriter to log to the filesystem when these functions are called, using milisecond precision. What I see is that 'createNote' is called after 'getAllNotes'. So I suspect that the API is working correctly, but something with the way I'm using promises seems to be awfully wrong.
Maybe somebody has a hint?
UPDATE
I know that the GET request doesn't return any data by using the developer toolbar in Chromium. The response is empty
The developer toolbar in the network tab shows that the requests are submitted in the correct order, so the "POST" request is issued first
It seems I found the problem. I had a 'href' tag in my 'Save' link, which triggered an early routing. The intended 'POST' and 'GET' were fired correctly, but there was another 'GET' inbetween somewhere because of the 'href' tag in the link, even though it was empty.
I removed the tag, now it works as intended.

Use of Tealium's utag.view and/or utag.link for dynamically loaded elements

This may be a long shot but I'm looking for someone who has worked with the Tealium UDO (Universal Data Object). I have a search page with a Google Search Appliance, my utag_data object in the data layer that looks like this:
var utag_data = {
"country":"US",
"language":"EN",
"search_keywords": "blahblah",
"search_results": "0"
}
The problem here is the search_results property has not had enough time to wait for the real results number to load so it is defaulting to 0 instead of the real number 1200. I've read Tealium's documentation around the utag.view() and utag.link() and want to use one of these to update the search_results tag. I tried:
utag.link({'search_results':'1200'});
and
utag.view(utag_data,null,[12]);
where 12 is the UID of the tag in Tealium but when using Omnibug in firefox I'm not seeing any updated values, but it is sending the click event to AT Internet.
Does anyone have any experience with this? Thank you in advance
You can either wait to call the main utag.js Tealium script, or send along another data point using utag.link or utag.view. It is not possible to "update" the initial utag_data object once sent.
These methods are used to handle sending dynamic events/data. See additional discussion on the Tealium blog at ajax tracking.. when urls no longer change
From utag.link() and utag.view() on Tealium Learning
Syntax
The link and view methods allow you to pass three different parameters:
parameter 1: a JSON object
utag.view({'search_results':'1200'});
parameter 2: a callback function (optional, may be set to null)
parameter 3: an array of Tags (optional: if used, these are the only Tags that will fire)
utag.link(
{'search_results':'1200'},
function(){alert("Only fired tag 12 with this call");},
[12]
);
Notes:
The utag_data object declared on initial page landing is not re-purposed with these calls. If data from the initial page landing needs to be used it will need to be re-declared and passed again in the method call. For example, if language:"en" was passed on page landing, if language is needed for a tag fired by a utag method call then language will need to be passed again.
utag.view() calls should not be called on initial page load - they should only exist in the dynamic content loaded within the page.
Global and Tag-scoped Extensions are executed during these calls. Pre-loader and DOM Ready extensions will not executed during these calls.

Losing context reference

I am encountering a 'small' problem when making a new object in the options page.
In the options page I create a few objects and save them as general settings. These objects have method to communicate with different API's. But as soon as I get one of those objects to work with, I lose the context on the page I am.
For example:
The options page I create an object that has a method 'request' and I send an ajax request to some api with this method. When I call this on an other page the ajax request is logged within the options page. When I close the options page I lose all context of the logs it makes.
Is there a way to force the context reference to the current page? or did I make a mistake with creating objects on the wrong pages/saving them and retrieving them on a page that needs them? (IE Should I only save the data I need to create objects on the page itself? (which seems like alot of overhead for the the same thing(?)).
Thanks in advance.
EDIT
I have an option page which creates an Object lets call it MyApi. I create a new MyApi and store it in chrome.storage.local . When a user has some text selected and clicks on the context menu I open a new page(selectedText.html) which shows the selected text and some API calls are made, which are mostly ajax requests. The moment I get the object from storage in selectedText.html and make any request with MyApi I see no logs in the network tab of the ajax requests, neither any console logs. But with my options page open I see everything in there.
EDIT2
save : function()
{
var obj = {'api':this.data};
chrome.storage.local.set(obj,function() { if(chrome.runtime.lastError) console.warn(chrome.runtime.lastError); });
}
This is in the background script.
You could achieve what you want this way:
Define your object/function/whatever in the background page.
Use chrome.runtime.getBackgroundPage() to get a hold on the background pages window object.
Execute the desired method, passing as argument an object of the local context. (Of course you have to modify the function to accept and make use of such an argument.)
Example:
In background.js:
function myFunc(winObj, msg) {
winObj.console.log(msg);
}
In otherPage.js:
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.myFunc(window, "This will be logged in 'otherPage.html' !");
});
It is not the cleanest solution, but it might work...

YUI Datatable - call arbitrary function *once* on sort

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.

Categories

Resources