Server-side ajax search, wait till finish entering

Server-side ajax search, wait till finish entering

MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
edited February 2011 in General
I am using server-side processing and retrieval and when you do a search, it makes an ajax call for each keypress. Is there a way for it to wait until the user is finished typing?

Replies

  • GerardoGerardo Posts: 66Questions: 0Answers: 0
    instead of binding the search function to keydown, bind it to focusout?

    Hth,
    Gerardo
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    how?
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    edited February 2011
    I figured it out but I'd rather do it differently. I can't use keypress and look for enter because I have a default button on the page and when I press enter, it does various things.
    Thanks for the thought but are there any more ideas?
  • big-dealbig-deal Posts: 38Questions: 0Answers: 0
    Gerardo haven't told you to capture "enter" but to use .focusout() instead of keypreased.
    I think that it's a good idea.
    Another approach would be to let the user to end all of his search and press on a "search" button that will do the actual search (fnDraw).
    That would mean that in the "keypress" you will not write:
    [code]
    $("tfoot input").keyup( function () {
    /* Filter on the column (the index) of this element */
    oTable.fnFilter( this.value, $("tfoot input").index(this) );
    } );
    [/code]
    but
    [code]
    $("tfoot input").keyup( function () {
    var oSettings = oTable.fnSettings();
    var iCol = $("tfoot input").index(this)
    oSettings.aoPreSearchCols[ iCol ].sSearch = this.value;
    } );
    [/code]

    If you want an exact match you can just replace the

    [code]
    oSettings.aoPreSearchCols[ iCol ].sSearch = this.value;
    [/code]

    in

    [code]
    oSettings.aoPreSearchCols[ iCol ].sSearch = "^\\s*"+'1'+"\\s*$";
    oSettings.aoPreSearchCols[ iCol ].bRegex = false;
    oSettings.aoPreSearchCols[ iCol ].bSmart= false;
    [/code]


    On the click of the search button just redraw the table.

    Have fun!
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    I'm using 1.7.5 and the filtering keyup doesn't look like that. it looks like this:
    [code]
    jqFilter.keyup( function(e) {
    /* Update all other filter input elements for the new display */
    var n = oSettings.aanFeatures.f;
    for ( var i=0, iLen=n.length ; i
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    How do I call the redraw from a TableTools button click?
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    OK, I know how to do the redraw but I don't know how to clear the search before it is redrawn.
    This doesn't work:

    [code]
    {
    "sExtends": "text",
    "sButtonText": "Clear Search",
    "fnClick": function ( nButton, oConfig, oFlash ) {
    oUserTable.fnFeatureHtmlFilter (oUserTable._aoSettings);
    oUserTable.fnDraw();
    }
    }
    [/code]

    What am I doing wrong? The input is not cleared as well.
  • MrBaseball34MrBaseball34 Posts: 96Questions: 0Answers: 0
    Cool, a search of the forum found the answer:
    [code]
    {
    "sExtends": "text",
    "sButtonText": "Clear Search",
    "fnClick": function ( nButton, oConfig, oFlash ) {
    oUserTable.fnFilter('');
    oUserTable.fnDraw();
    }
    }
    [/code]
  • UPEngineerUPEngineer Posts: 93Questions: 0Answers: 1
    Hello,

    If I am reading this correctly, there is an API that was developed just for this and I use it a lot.

    http://datatables.net/plug-ins/api

    The function you are looking for is fnSetFilteringDelay()

    I use this a lot. Play with the ms as in fnSetFilteringDelay(500), fnSetFilteringDelay(250), etc. to find the right time limits.

    It will wait that amount of time before invoking the ajax call.

    If I am way off base on the original problem, I apologize.

    Scott
  • GregPGregP Posts: 487Questions: 8Answers: 0
    Thanks for that, UPEngineer; I sometimes jump too quickly to implement my own solutions rather than looking at existing plugins and functions. As I read the thread, my suggestion was going to be to implement a delay between keypresses; fnSetFilgeringDelay() seems to already do this!

    Going to try to remember to check out the API functions more carefully in the future. :D

    Greg
  • MvcCmsJonMvcCmsJon Posts: 3Questions: 0Answers: 0
    edited April 2011
    FYI I am still rubbing the noob off myself as I have just been fully committed to datatables after recently realizing that flexigrid wasn't going to get any more development.

    So... I would just go for the first solution of

    "instead of binding the search function to keydown, bind it to focusout?"

    except I would want to bind it to the enter or return keydown, that is how flexigrid worked.

    But how should I do this? We aren't suggesting to modify the source are we? This is something I loathe.

    Thanks in advance!
    Jon

    although the delay thing might be cool... still would like to know how to change binding of things if it is possible without changing the source.
  • allanallan Posts: 61,436Questions: 1Answers: 10,049 Site admin
    The basic idea is that you would unbind the default event handler that DataTables adds to the input field and then bind your own, which will call fnFilter with the filtering value. How and when it called is then up to you. This plug-in ( http://datatables.net/plug-ins/api#fnSetFilteringDelay ) takes that approach to add a delay before firing off the request.

    Allan
  • MvcCmsJonMvcCmsJon Posts: 3Questions: 0Answers: 0
    edited April 2011
    Wow quick response. I whipped up a new api based off the delay one..

    The api looks great, basically I can do anything I want....

    Next I need to allow specification of the columns to be searched instead of just all of them all the time, but it won't be hard with the api. I read earlier today where I can push some custom info into the outgoing request, just have to look that up again...

    I wasn't sure what the purpose of the line

    $.fn.dataTableExt.iApiIndex = i;

    was but it looked important so I did it also.

    What is the etiquette here, should we all post on our api's that we make or is it just kind of understood that they are out there and we don't all have to share them all?

    [code]
    jQuery.fn.dataTableExt.oApi.fnSetFilteringPressEnter = function (oSettings) {
    /*
    * Type: Plugin for DataTables (www.datatables.net) JQuery plugin.
    * Name: dataTableExt.oApi.fnSetFilteringPressEnter
    * Version: 2.2.1
    * Description: Enables filtration to be triggered by pressing the enter key instead of keyup or delay.
    * Inputs: object:oSettings - dataTables settings object
    *
    * Returns: JQuery
    * Usage: $('#example').dataTable().fnSetFilteringPressEnter();
    * Requires: DataTables 1.6.0+
    *
    * Author: Jon Ranes (www.mvccms.com)
    * Created: 4/17/2011
    * Language: Javascript
    * License: GPL v2 or BSD 3 point style
    * Contact: jranes /AT\ mvccms.com
    */
    var _that = this;

    this.each(function (i) {
    $.fn.dataTableExt.iApiIndex = i;
    var $this = this;
    var anControl = $('input', _that.fnSettings().aanFeatures.f);
    anControl.unbind('keyup').bind('keypress', function (e) {
    if (e.which == 13) {
    $.fn.dataTableExt.iApiIndex = i;
    _that.fnFilter(anControl.val());
    }
    });
    return this;
    });
    return this;
    }

    /* Example call */
    $(document).ready(function() {
    $('.dataTable').dataTable().fnSetFilteringPressEnter();
    } );

    [/code]
  • allanallan Posts: 61,436Questions: 1Answers: 10,049 Site admin
    Hi Jon,

    That's superb - thanks for sharing your code with us :-). I've put it up on the plug-ins page here: http://datatables.net/plug-ins/api#fnFilterOnReturn . I've modified the header a little bit to make it easier to see all the code (done the same to the filtering delay function as well now - it was a bit verbose... if you'd like anything changed / added, just let me know). I've also named the function fnFilterOnReturn which I think might be slightly more appropriate for the action - although it's easy for any one to change. Hope this is okay :-)

    Regards,
    Allan
  • MvcCmsJonMvcCmsJon Posts: 3Questions: 0Answers: 0
    edited April 2011
    Ya, glad you changed it, I will follow the condensed format going forward, hopefully I can contribute some dough and more to the project.

    I also just finished up one more thing that .NET people might find to be epically awesome, and I mean epically. Basically I figured out how to use Dynamic Linq with a Generic IQueryable to build predicates for searching all columns of the grid with the much sought after "or" effect needed when building predicates. What that means is one reusable code piece can now search all the columns of any grid here.

    I have a write up on it here http://www.ranessoftwareconsulting.com/articles/reusable-dynamiclinq-with-predicatebuilder-to-search-every-column-of-jquerydatatables.

    And the full source of it is in the MvcCms project at codeplex in the source code section, this won't make it to release till later this year.

    Basically what you end up with is a filter method like this...

    [code]

    using System;
    using System.Linq;

    using MvcCms.Data.DynamicLINQ;
    using MvcCms.Service.Models;
    using System.Linq.Expressions;

    namespace MvcCms.Service.Code
    {
    public static class DataTablesSearch
    {
    //
    //This implemenation of DataTables filter will be for small return sets.
    //Will have another implementation for small sets that loads
    //from the dom also. Both of these will have all fields searchable by default.
    //Will have another using sprocs for all the searching for large tables.
    //
    public static IQueryable SearchForDataTables(this IQueryable query, DataTablesRequest dataTablesRequest, string[] columnNames)
    {
    if (!String.IsNullOrEmpty(dataTablesRequest.sSearch))
    {
    #region Search All Fields
    var predicate = PredicateBuilder.False();
    if (dataTablesRequest.sSingleSearchField == "All")
    {
    Expression predicateToAdd = null;
    for (int i = 0; i < dataTablesRequest.iColumns; i++)
    {
    if (dataTablesRequest.bSearchable[i]) // If the column is marked as searchable
    {
    string columnName = columnNames[i];
    Type columnType = query.DynamicType(z => z[columnName]);
    if (columnType == typeof(System.Int32))
    {
    var intToSearchFor = int.Parse(dataTablesRequest.sSearch);
    //for integer we do equals
    predicateToAdd = query.DynamicWhereForPredicateBuilder(z => z[columnName] == intToSearchFor);
    }
    else if (columnType == typeof(System.String))
    { //for string we do contains
    predicateToAdd = query.DynamicWhereForPredicateBuilder(z => z[columnName].Contains(dataTablesRequest.sSearch)); //contains or
    }
    predicate = predicate.Or(predicateToAdd);
    }
    }
    query = query.Where(predicate);
    }
    #endregion

    #region Search Single Field
    else if (!String.IsNullOrEmpty(dataTablesRequest.sSingleSearchField))
    {
    string columnName = dataTablesRequest.sSingleSearchField;
    Type columnType = query.DynamicType(z => z[columnName]);
    if (columnType == typeof(System.Int32))
    {
    try
    {
    var intToSearchFor = int.Parse(dataTablesRequest.sSearch);
    //for integer we do equals
    query = query.DynamicWhere(z => z[columnName] == intToSearchFor);
    }
    catch { }
    }
    else if (columnType == typeof(System.String))
    {
    //for string we do contains
    query = query.DynamicWhere(z => z[columnName].Contains(dataTablesRequest.sSearch));
    }
    }
    #endregion
    }
    return query;
    }
    }
    }

    [/code]
This discussion has been closed.