Datatables and "Back" feature

Datatables and "Back" feature

abrachetabrachet Posts: 8Questions: 0Answers: 0
edited July 2012 in DataTables 1.9
Hi there,

I try to implement a back feature and I'm having problem. Let me explain.

I have a first page with some search criteria + a search action + a datatable component. Here is the datatable code :
[code]
// target DataTables for members
var Members = $('#Members').dataTable({
aoColumns: [
{ mDataProp: 'avatar', bSortable: false, bUseRendered: true, fnRender: function (o, val) { return tools.dtRenderMemberAvatar(val); }, sClass: 'centeredRow', sWidth: '100px' },
{ mDataProp: 'lastName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
{ mDataProp: 'firstName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
{ mDataProp: 'gender', sClass: 'centeredRow', sType: 'string', sWidth: '100px' },
{ mDataProp: 'age', sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
{ mDataProp: 'level', fnRender: function (o, val) { return tools.dtRenderLevelWithColor(val); }, sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
{ mDataProp: 'lastConnection', sClass: 'centeredRow', sType: 'date', sWidth: '300px' }
],
fnCreatedRow: function (nRow, aData, iDataIndex) {
$(nRow).attr('data-user-id', aData.userID);
},
fnServerParams: function (aoData) {
tools.dtSearchOnField(aoData, '#institution', 'InstitutionID');
tools.dtSearchOnField(aoData, '#group', 'GroupID');
tools.dtSearchOnField(aoData, '#level', 'LevelID');
tools.dtSearchOnField(aoData, '#sex', 'IsMaleGender');
tools.dtSearchOnField(aoData, '#lastname', 'LastName');
tools.dtSearchOnField(aoData, '#firstname', 'FirstName');
},
iDisplayLength: 10,
sAjaxSource: '@Url.Action("SearchMembers", "DataTables")',
oLanguage: {
sUrl: '/assets/js/resources/jquery.dataTables.fr-FR.txt'
}
});
[/code]

When the table is bound, I get a list member. I can click on each member to access a second page that displays detailed information (in the same time, criteria are persisted using cookies). On this second page I added a back button to come back on the search page.

On the search page I added this code :
[code]
// handle back action
if (tools.parseQueryString().back) {
// load search form state
tools.loadFormField('members', 'institution', '#institution');
tools.loadFormField('members', 'group', '#group');
tools.loadFormField('members', 'level', '#level');
tools.loadFormField('members', 'sex', '#sex');
tools.loadFormField('members', 'lastname', '#lastname');
tools.loadFormField('members', 'firstname', '#firstname');
tools.loadFormField('members', 'pagination', '#NumberResultItemsToDisplay');

// draw members DataTables
Members.fnDraw();
}
[/code]

When I return on the initial page, I get the following error :
Uncaught TypeError: Cannot read property 'sSortAscending' of undefined

After some tests, if I remove this section :
[code]
oLanguage: {
sUrl: '/assets/js/resources/jquery.dataTables.fr-FR.txt'
}
[/code]
in the code above, everything works fine.

Of course I need to keep localization and I can't remove these lines...

Any help would be greatly appreciated ;)
Thx

Replies

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin
    My guess is that it is the async behaviour of the table that using sUrl adds which is causing the problem (the Ajax get is async, so the table constructor will complete and run your following code before the table has fully been constructed!).

    So two options I think:

    1. Put the contents of your translation file into oLanguage - you don't have to get it by Ajax (although it can be useful).

    2. Move your continuation code (tools.loadFormField etc) into fnInitComplete which is fired once the table is finally ready.

    Allan
  • abrachetabrachet Posts: 8Questions: 0Answers: 0
    Hi Allan,

    Thank u for these advices, it was very helpfull. However I still have a problem about reload the datatable on the selected page (example : I leave by clicking a member on the third page, I need to come back on the third page).

    Here is the datatable initialization code :

    [code]
    // defines default configuration for DataTables
    $.extend($.fn.dataTable.defaults, {
    bAutoWidth: false,
    bFilter: false,
    bLengthChange: false,
    bProcessing: true,
    bServerSide: true,
    iDisplayLength: 10,
    iDeferLoading: 0,
    fnStateLoad: function (oSettings) {
    // define datatable prefix for localstorage
    var datatablePrefix = 'DataTables_' + window.location.pathname + '_';

    // check if back button is clicked
    if (tools.parseQueryString().back) {
    // restore form values from localstorage
    tools.loadFormFields();

    // restore datatable settings from localstorage
    oSettings._iDisplayLength = JSON.parse(localStorage.getItem(datatablePrefix + 'PageSize'));
    oSettings._iDisplayStart = JSON.parse(localStorage.getItem(datatablePrefix + 'PageStart'));
    oSettings.aaSorting = JSON.parse(localStorage.getItem(datatablePrefix + 'Sorting'));
    }
    },
    fnStateSave: function (oSettings, oData) {
    // define datatable prefix for localstorage
    var datatablePrefix = 'DataTables_' + window.location.pathname + '_';

    // store form values to localstorage
    tools.saveFormFields('div.dt-searchform');

    // store datatable settings to localstorage
    localStorage.setItem(datatablePrefix + 'PageSize', JSON.stringify(oSettings._iDisplayLength));
    localStorage.setItem(datatablePrefix + 'PageStart', JSON.stringify(oSettings._iDisplayStart));
    localStorage.setItem(datatablePrefix + 'Sorting', JSON.stringify(oSettings.aaSorting));
    },
    sPaginationType: 'full_numbers'
    });
    [/code]

    and here is the datatable code in the page :

    [code]
    // target DataTables for members
    var Members = $('#Members').dataTable({
    aoColumns: [
    { mDataProp: 'avatar', bSortable: false, bUseRendered: true, fnRender: function (o, val) { return tools.dtRenderMemberAvatar(val); }, sClass: 'centeredRow', sWidth: '100px' },
    { mDataProp: 'lastName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
    { mDataProp: 'firstName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
    { mDataProp: 'gender', sClass: 'centeredRow', sType: 'string', sWidth: '100px' },
    { mDataProp: 'age', sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
    { mDataProp: 'level', fnRender: function (o, val) { return tools.dtRenderLevelWithColor(val); }, sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
    { mDataProp: 'lastConnection', sClass: 'centeredRow', sType: 'date', sWidth: '300px' }
    ],
    bStateSave: true,
    fnInitComplete: function(oSettings, json) {
    if (tools.parseQueryString().back) {
    Members.fnDraw();
    }
    },
    fnCreatedRow: function (nRow, aData, iDataIndex) {
    $(nRow).attr('data-user-id', aData.userID);
    },
    fnServerParams: function (aoData) {
    tools.dtSearchOnField(aoData, '#institution', 'InstitutionID');
    tools.dtSearchOnField(aoData, '#group', 'GroupID');
    tools.dtSearchOnField(aoData, '#level', 'LevelID');
    tools.dtSearchOnField(aoData, '#sex', 'IsMaleGender');
    tools.dtSearchOnField(aoData, '#lastname', 'LastName');
    tools.dtSearchOnField(aoData, '#firstname', 'FirstName');
    },
    oLanguage: {
    sUrl: '/assets/js/resources/jquery.dataTables.fr-FR.txt',
    },
    sAjaxSource: '@Url.Action("SearchMembers", "DataTables")'
    });
    [/code]

    I can restore sorting and items per page correctly but the current page isn't recovered. Should I use iDisplayStart parameter to do it ? If yes, how ? Because the code above doesn't work.

    Once again, thank you in advance for your help.
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin
    In your fnStateLoad function , what is the value of oSettings._iDisplayStart that you get from the localStorage?
  • abrachetabrachet Posts: 8Questions: 0Answers: 0
    That is 10 when I use the second page, 20 when I come from the third one and so on... Here everything sounds good but our question is why this parameter is not applied ?
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin
    Ah okay - according to the DataTables source, you need to set the following parameters of the object that is used to load the state data:

    [code]
    oSettings._iDisplayStart = oData.iStart;
    oSettings.iInitDisplayStart = oData.iStart;
    oSettings._iDisplayEnd = oData.iEnd;
    oSettings._iDisplayLength = oData.iLength;
    [/code]

    So I suspect the issue is that iInitDisplayStart is not being set.

    Allan
  • abrachetabrachet Posts: 8Questions: 0Answers: 0
    edited July 2012
    Hi Allan,

    I really appreciate your help. Thank you so much.

    To be sure that I do the right thing, here is my new code :
    [code]
    // target DataTables for members
    var Members = $('#Members').dataTable({
    aoColumns: [
    { mDataProp: 'avatar', bSortable: false, bUseRendered: true, fnRender: function (o, val) { return tools.dtRenderMemberAvatar(val); }, sClass: 'centeredRow', sWidth: '100px' },
    { mDataProp: 'lastName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
    { mDataProp: 'firstName', sClass: 'centeredRow', sType: 'string', sWidth: '150px' },
    { mDataProp: 'gender', sClass: 'centeredRow', sType: 'string', sWidth: '100px' },
    { mDataProp: 'age', sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
    { mDataProp: 'level', fnRender: function (o, val) { return tools.dtRenderLevelWithColor(val); }, sClass: 'centeredRow', sType: 'numeric', sWidth: '50px' },
    { mDataProp: 'lastConnection', sClass: 'centeredRow', sType: 'date', sWidth: '300px' }
    ],
    bStateSave: true,
    fnInitComplete: function(oSettings, json) {
    if (tools.parseQueryString().back) {
    Members.fnDraw();
    }
    },
    fnStateLoad: function (oSettings) {
    // check if back button is clicked
    if (tools.parseQueryString().back) {
    // define prefix for localstorage
    var fieldsPrefix = 'Fields_' + window.location.pathname + '_';
    var datatablePrefix = 'DataTables_' + window.location.pathname + '_';

    // restore combo values from sessionstorage
    deserializeCombo('#institution', JSON.parse(sessionStorage.getItem(fieldsPrefix + 'InstitutionCombo')));
    deserializeCombo('#group', JSON.parse(sessionStorage.getItem(fieldsPrefix + 'GroupCombo')));

    // restore fields values from sessionstorage
    $('#NumberResultItemsToDisplay').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'NumberResultItemsToDisplay')));
    $('#institution').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'Institution')));
    $('#group').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'Group')));
    $('#level').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'Level')));
    $('#lastname').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'LastName')));
    $('#firstname').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'FirstName')));
    $('#sex').val(JSON.parse(sessionStorage.getItem(fieldsPrefix + 'Sex')));

    // restore datatable settings from sessionstorage
    oSettings._iDisplayLength = JSON.parse(sessionStorage.getItem(datatablePrefix + 'PageSize'));
    oSettings._iDisplayStart = JSON.parse(sessionStorage.getItem(datatablePrefix + 'PageStart'));
    oSettings.aaSorting = JSON.parse(sessionStorage.getItem(datatablePrefix + 'Sorting'));
    }
    },
    fnStateSave: function (oSettings, oData) {
    // define prefix for sessionstorage
    var fieldsPrefix = 'Fields_' + window.location.pathname + '_';
    var datatablePrefix = 'DataTables_' + window.location.pathname + '_';

    // store fields combo values to sessionstorage
    sessionStorage.setItem(fieldsPrefix + 'InstitutionCombo', JSON.stringify(serializeCombo('#institution')));
    sessionStorage.setItem(fieldsPrefix + 'GroupCombo', JSON.stringify(serializeCombo('#group')));

    // store fields values to sessionstorage
    sessionStorage.setItem(fieldsPrefix + 'NumberResultItemsToDisplay', JSON.stringify($('#NumberResultItemsToDisplay').val()));
    sessionStorage.setItem(fieldsPrefix + 'Institution', JSON.stringify($('#institution').val()));
    sessionStorage.setItem(fieldsPrefix + 'Group', JSON.stringify($('#group').val()));
    sessionStorage.setItem(fieldsPrefix + 'Level', JSON.stringify($('#level').val()));
    sessionStorage.setItem(fieldsPrefix + 'LastName', JSON.stringify($('#lastname').val()));
    sessionStorage.setItem(fieldsPrefix + 'FirstName', JSON.stringify($('#firstname').val()));
    sessionStorage.setItem(fieldsPrefix + 'Sex', JSON.stringify($('#sex').val()));

    // store datatable settings to sessionstorage
    sessionStorage.setItem(datatablePrefix + 'PageSize', JSON.stringify(oSettings._iDisplayLength));
    sessionStorage.setItem(datatablePrefix + 'PageStart', JSON.stringify(oSettings._iDisplayStart));
    sessionStorage.setItem(datatablePrefix + 'Sorting', JSON.stringify(oSettings.aaSorting));

    oSettings._iDisplayStart = oData.iStart;
    oSettings.iInitDisplayStart = oData.iStart;
    oSettings._iDisplayEnd = oData.iEnd;
    oSettings._iDisplayLength = oData.iLength;
    },
    fnCreatedRow: function (nRow, aData, iDataIndex) {
    $(nRow).attr('data-user-id', aData.userID);
    },
    fnServerParams: function (aoData) {
    tools.dtSearchOnField(aoData, '#institution', 'InstitutionID');
    tools.dtSearchOnField(aoData, '#group', 'GroupID');
    tools.dtSearchOnField(aoData, '#level', 'LevelID');
    tools.dtSearchOnField(aoData, '#sex', 'IsMaleGender');
    tools.dtSearchOnField(aoData, '#lastname', 'LastName');
    tools.dtSearchOnField(aoData, '#firstname', 'FirstName');
    },
    oLanguage: {
    sUrl: '/assets/js/resources/jquery.dataTables.fr-FR.txt',
    },
    sAjaxSource: '@Url.Action("SearchMembers", "DataTables")'
    });
    [/code]
    Is it what you expected ?

    If I do that, the pagination doesn't work anymore. I systematically stay on page 1 when I try to go on another page. So I can't go on page 2 to process my test...
  • abrachetabrachet Posts: 8Questions: 0Answers: 0
    I've also tried to set settings in fnStateLoad :

    [code]
    // restore datatable settings from sessionstorage
    oSettings._iDisplayStart = JSON.parse(sessionStorage.getItem(datatablePrefix + 'Start'));
    oSettings.iInitDisplayStart = JSON.parse(sessionStorage.getItem(datatablePrefix + 'Start'));
    oSettings._iDisplayEnd = JSON.parse(sessionStorage.getItem(datatablePrefix + 'End'));
    oSettings._iDisplayLength = JSON.parse(sessionStorage.getItem(datatablePrefix + 'Length'));
    oSettings.aaSorting = JSON.parse(sessionStorage.getItem(datatablePrefix + 'Sorting'));
    [/code]

    The initial pagination works now (as before), but the current page is still not selected when I use Back feature. fnDraw seems to systematically reset _iDisplayStart property to 0...
  • abrachetabrachet Posts: 8Questions: 0Answers: 0
    Is anyone have an idea ? I still have not found a solution to retrieve the current page :'(
This discussion has been closed.