Manipulate ajax.dataSrc after the fact

Manipulate ajax.dataSrc after the fact

nizdiznizdiz Posts: 11Questions: 1Answers: 0

Pre-post update: I just managed to get DataTables to behave how I wanted. Keep reading.

For starters, I have found numerous examples of delay-loading ajax data by not setting the ajax/url property at the time of table initialization but instead calling the DataTable().ajax.url('/myApi/Url').load() at a later time. What I don't understand is why can I not also manipulate the ajax.dataSrc property in the same way? It seems in order to be able to do anything with that, it needs to be done at initialization. Which, if I initialize with my ajax.url, the DataTable() hits the server upon initialization (not desired).

In my testing, I am also unable to set the ajax.dataSrc property upon initialization without setting the url. BUT, as posted above, I can set the url after the fact, and it will hit the server for data just fine. The crux of this issue basically boils down to this bit of logic inside jquery.datatables.js:

var data = _fnAjaxDataSrc( settings, json );

which ultimately runs:

var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
    oSettings.ajax.dataSrc :
    oSettings.sAjaxDataProp; // Compatibility with 1.9-.

This all results in the following exception which, again, has been posted many times:

Uncaught TypeError: Cannot read properties of undefined (reading 'length')
    at jquery.datatables.js:7734:29

And, whoa, look at that, I was just able to force it to do what I wanted by utilizing the deprecated sAjaxDataProp value:

__Deprecated__ The functionality provided by this parameter has now been
superseded by that provided through `ajax`, which should be used instead.

By default DataTables will look for the property `data` (or `aaData` for
compatibility with DataTables 1.9-) when obtaining data from an Ajax
source or for server-side processing - this parameter allows that
property to be changed. You can use Javascript dotted object notation to
get a data source for multiple levels of nesting.
@type string
@default data

@dtopt Options
@dtopt Server-side
@name DataTable.defaults.ajaxDataProp

@deprecated 1.10. Please use `ajax` for this functionality now.
"sAjaxDataProp": "data",

I don't think the comment above is accurate: "By default DataTables will look for the property data." In the event you want to delay-load data in this way, IT FORCES A JSON PROPERTY called "data", there is no default; it is hard-coded.

Frankly, I'd love to simply use the ajax property but it does not support this use-case. Given that this "deprecated" property actually makes the code function as desired, may I humbly ask that you implement/expose a way to modify the ajax.dataSrc property late just as you have implemented/exposed the ability to set ajax.url late?

A couple suggestions:

myTable.DataTable().ajax.url('/myApi/Url', '').load(); //where '' is dataSrc

OR something like:

myDataTable.ajax({url: '/myApi/Url', dataSrc: ''}).load();

I prefer the latter because it's more obvious what is happening versus the former empty-string parameter.

Any help would be greatly appreciated. While I have found a way for this code to work, with sAjaxDataProp flagged as deprecated, I'm afraid at some point this work-around will no longer work.

Answers

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    The comment about defaulting to "data" is correct above. It is specific to the deprecated property sAjaxDataProp.

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0
    edited March 5

    And, I'm getting a "legacy interface notice." I am running jquery.datatables.js v1.10.18. Pretty sure that notice was flagged for the included comment from the codebase.

  • allanallan Posts: 63,441Questions: 1Answers: 10,459 Site admin

    Yes, the legacy interface notice is purely a simple regex on the contents on the post here, checking for old parameter names and giving a warning if present (sAjaxDataProp specifically here).

    I don't recall any requests for an API to change ajax.dataSrc after init before, but I could be forgetting them. It can be provided as a function, so you can have complete control over it at any time, equally ajax can also be provided as a function to give complete control over the data fetch action and then data manipulation before passing it to on to DataTables.

    ajax.dataSrc does indeed default to data.

    Allan

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    Thanks Allan. I'm not so much saying my exact request has happened before, but I did find many posts touching on this.

    I think my primary thought here is why is ajax.url exposed to be manipulated in-line but ajax.dataSrc is not? They are inter-related.

    I will look at trying to set a function for the ajax property but I was having zero luck with anything on that side of things last night. The only way I was able to achieve what I wanted was by using the deprecated property sAjaxDataProp.

  • allanallan Posts: 63,441Questions: 1Answers: 10,459 Site admin

    I think my primary thought here is why is ajax.url exposed to be manipulated in-line but ajax.dataSrc is not?

    I don't recall a case where the data property name in the JSON data feed changes. For example if you load JSON with the data array in a property called data, you wouldn't really expect it to change to people on a reload. Perhaps it could be used to switch to a different array in the JSON feed, but I just don't think that is very common, which is why there isn't an API for it.

    Can you give me a link to a page showing what you are doing with 1.x perhaps? I might be able to see a way to do it with 2.x.

    Allan

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    It's not changing. I'm trying for 2 things:

    1. I do not want to set ajax.url at the time of initialization because I do not want the table fetching data off the bat.
    2. Because I do not set ajax.url upon initialization, I have now lost the opportunity to manipulate ajax.dataSrc.

    I need ajax.dataSrc = ''. I cannot set that upon initialization without also setting ajax.url. And, if I do not set it upon initialization, it forces ajax.dataSrc = 'data' because there is no way to manipulate it after the fact.

    I will see if I can whip up a working example somehow to illustrate what my exact use-case is.

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    The API returns a list of JSON objects, it does not return a JSON document with a data property with a value of an array of those JSON objects.

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    I whipped this up. I couldn't think of a good way to actually execute an ajax call in the same way as my scenario so I just put some comments inside the block where that work is performed.

    https://jsfiddle.net/dg9xe61v/

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    The ViewModel of this page returns the initial load of data, the HTML is rendered, and then the DataTable is initialized.

    There is an AJAX-specific API which is used for AJAX-only interactions. in the jsfiddle above, the delete happens via AJAX and responds to the client that it succeeded or failed. If it succeeded, I need to call the AJAX-specific API to fetch the current data and reload/redraw the table.

    If I set ajax = { url: '/myApi/Url', dataSrc: ''} when the table is initialized, it'll hit the server again for data the UI already has. And, I am not allowed to pre-populate dataSrc without also setting the url. BUT, after reading through the code, I discovered I can do exactly that with sAjaxDataProp.

    So, when you said:

    I don't recall a case where the data property name in the JSON data feed changes. For example if you load JSON with the data array in a property called data, you wouldn't really expect it to change to people on a reload.

    That's not at all the scenario. dataSrc is a constant ''. I just want the ability to reload the DataTable through ajax calls but I also already have it's first load of data retrieved and do not want it to hit the server a second time upon initialization.

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    Another approach could be a new property:

    ajax: {
        url: '/myApi/Url',
        dataSrc: '',
        fetchDataUponInitialization: false //default to true, current behavior
    }
    

    fetchDataUponInitialization is a crummy property name but you get the gist. The whole reason I am using .ajax.url('/myApi/Url).load()` is to circumvent the DataTable re-pulling data the View already has collected.

  • allanallan Posts: 63,441Questions: 1Answers: 10,459 Site admin

    Right - I think I understand now. Thanks for the clarification. If I understand correctly, you want something like this:

    var table = new DataTable('#example', {
      ajax: {
        url: '',
        dataSrc: 'data'
      },
      columns: [
        { data: 'name' },
        { data: 'position' },
        { data: 'office' },
        { data: 'extn' },
        { data: 'start_date' },
        { data: 'salary' },
      ],
    });
    
    setTimeout(function () {
        table.ajax.url('/ajax/objects.txt').load();
    }, 1000);
    

    I've used a setTimeout to load the data, but really you could use anything? The key is that ajax.url as an empty string means no data load?

    That actually had been my intention with DataTables 2, but it looks like there was an error for some conditions, such as this one. I've fixed that now and the nightly build has the fix.

    You can see the result here: https://live.datatables.net/dodobuge/73/edit .

    Allan

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    You, sir, are amazing. Thanks for listening and helping!

  • nizdiznizdiz Posts: 11Questions: 1Answers: 0

    And whoa... just saw in the DataTables 2.0 release notes that sAjaxDataProp was indeed dropped so my above work-around would've stopped working upon updating (which is planned soon).

    Thanks again, Allan!

Sign In or Register to comment.