We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 26868
    • 15 Posts
    Hi everyone,

    I’m starting to discover the power of Modx. I’ve installed yesterday the powerfull AjaxSearch Snippet, and I’ve decided to add some hacks in order to use it without the need of the submit button.
    It monitor keyup event in the input field and shows the result directly.
    I’ve also changed the ’close’ button : i’ve moved it in the top-right corner of the result box.
    You can see the result in my home page : www.chiroux.com (try the search by typing ’test’)

    Here is the hacked source of AjaxSearch.js (i’ve added [hack by thomas] in the code to show the small modifications)

    //ajaxSearch.js
    //Created by: KyleJ ([email protected])
    //Created on: 03/14/06
    //Description: This code is used to setup the ajax search request.
    //My thanks to Steve Smith of orderlist.com for sharing his code on how he did this
    
    //set the loading image to the correct location for you
    //set the close image to the correct location for you
    //set the ajax call to the correct location of ajaxSearch.php
    
    function activateSearch() {
        if ($('ajaxSearch_form')) {
            var o = document.createElement('div'); // Old search results div
            var n = document.createElement('div'); // New search results div
            var i = document.createElement('img');
            i.src = 'assets/snippets/AjaxSearch/indicator.white.gif'; //Loading Image
            Element.toggle(i);
            i.id = 'indicator';
            
            var c = document.createElement('img');
            c.src = 'assets/snippets/AjaxSearch/close.gif';
            Element.toggle(c);
            c.id = 'searchClose';
            c.onclick = function() { closeSearch(); };
            
            //---begin--- hack by thomas : un deuxième bouton close directement dans la zone de résultat
            var c2 = document.createElement('img');
            c2.src = 'assets/snippets/AjaxSearch/close.gif';
            c2.id = 'searchClose2';
            c2.style.position = 'absolute';
            c2.style.top = '1px';
            c2.style.right = '1px';
            c2.onclick = function() { closeSearch(); };
            //---end--- hack by thomas
            
            $('ajaxSearch_form').onsubmit = function() { doSearch(); return false; };
            var s = $('ajaxSearch_output');
            var f = $('ajaxSearch_form');
            o.id = 'old-search-results';
            n.id = 'current-search-results';
            s.appendChild(c2); // hack by thomas
            s.appendChild(n);
            s.appendChild(o);
            f.appendChild(i);
            //f.appendChild(c); // hack by thomas : on enlève le close a côté de l'input 
            o.style.display = 'none';
            n.style.display = 'none';
            // 's' does not appear to be properly selected ... results in the form itself...
            is_searching = false;
            search_open = false;
            Event.observe($('ajaxSearch_input'), 'keyup', doSearch, false); // hack by thomas : on monitore le keyup..
            $('ajaxSearch_submit').style.display = 'none'; // hack by thomas : si c'est en ajax, on n'affiche pas le bouton GO
        }
    }
    
    function doSearch() {
        // If we're already loading, don't do anything
        if (is_searching) return false;
        s = $F('ajaxSearch_input');
        // Same if the search is blank
        if (s == '') return false;
        //---begin--- hack by thomas : same if the len of the search is less than 3 cars
        if (s.length<3) return false;
        //---end---
        is_searching = true;
        c = $('current-search-results');
        o = $('old-search-results');
        Element.toggle($('indicator'));
        //---begin--- hack by thomas : on ne toggle pas l'élément qui n'est pas créé
        //if (!search_open) Element.toggle($('searchClose'));
        //---end---
        search_open = true;
        b = $('ajaxSearch_submit');
        $('ajaxSearch_input').disabled = true; // hack by thomas
        b.disabled = true;
        o.innerHTML = c.innerHTML;
        c.style.display = 'none';
        o.style.display = 'block';
        // Setup the parameters and make the ajax call
        pars = 'search=' + encodeURIComponent(s) + '&maxResults=' + maxResults + '&stripHtml=' + stripHtml + '&stripSnip=' + stripSnip + '&stripSnippets=' + stripSnippets + '&useAllWords=' + useAllWords + '&searchStyle=' + escape(searchStyle) + '&minChars=' + minChars + '&showMoreResults=' + showMoreResults + '&moreResultsPage=' + moreResultsPage + '&moreResultsText=' + encodeURIComponent(moreResultsText) + '&resultsIntroFailure=' + encodeURIComponent(resultsIntroFailure) + '&extract=' + extract;
    
        //Make sure this points to the correct location.
        var myAjax = new Ajax.Request('index-ajax.php?q=assets/snippets/AjaxSearch/AjaxSearch.php', 
                  {method: 'get', parameters: pars, onComplete:doSearchResponse, onFailure: callBackAjaxFailure, onException: callBackAjaxExc}); // hack by thomas : added callbackFailure and Exception
    }
    
    function doSearchResponse(response) {
        var o = $('ajaxSearch_output');
        o.style.display = 'block';
        $('current-search-results').innerHTML = decodeURIComponent(response.responseText);
        new Effect.Fade('ajaxSearch_intro',{duration:.15});
        new Effect.BlindUp('old-search-results',{duration:.8});
        new Effect.Appear('current-search-results',{duration:.8, afterFinish:resetForm});
    
    }
    
    //---begin--- hack by thomas : a small ajax error handling
    function callBackAjaxFailure(request, e) {
      alert('FAILURE AJAX : '+e.message);
      resetForm();
    }
    
    function callBackAjaxExc(request, e) {
      alert('EXCEPTION AJAX : '+e.message); //
      resetForm();
    }
    ///---end---
    
    function resetForm() {
        s = $('ajaxSearch_submit');
        s.disabled = false;
        $('ajaxSearch_input').disabled = false; // hack by thomas
        Element.toggle($('indicator'));
        is_searching = false;
        $('ajaxSearch_input').focus(); // hack by thomas (TEST)
    }
    
    function closeSearch() {
        new Effect.BlindUp('current-search-results',{duration:.8, afterFinish:clearSearch});
        new Effect.BlindUp('old-search-results',{duration:.8});
    }
    
    function clearSearch() {
        //---begin--- hack by thomas : on ne toggle pas l'élément qui n'est pas créé
        //Element.toggle($('searchClose'));
        //---end---
        search_open = false;
        $('old-search-results').innerHTML = '';
        $('current-search-results').innerHTML = ''
        new Effect.Fade('ajaxSearch_output',{duration:.15});
        $('ajaxSearch_input').value=""; // hack by thomas
    }
    
    Event.observe(window, 'load', activateSearch, false);
    
    


    The css for the output is below :
            #ajaxSearch_output {
                position: absolute;
                margin-top:5px;
                z-index:10;
                border: 1px solid #444;
                padding: 10px;
                background: #fff;
                display: block;
                height: auto;
                vertical-align: top;
            }


    Enjoy !

    I still have some strange behaviours : when I go to another page (from home to blog for example), the ajax search is not alaws enabled. I have to refresh the page (F5) to enable it, I no idea why ...
      • 15987
      • 786 Posts
      Shadock,
      Nice update. I had been thinking about doing this for a while and just hadn’t got around to it. One thing you might want to try to see if you could add would be to have the search start delay after the keyup event after typing has stopped. Currently once you hit the third character it starts the search and you cannont type more until it is finished. I think it would be nice if you had it check to see if the user is done typing before starting the search, maybe have a delay after the keyup event that waits to see if another key is pressed, then start the search. That way you would type the entire word you are looking for regardless of length, or even multiple words.

      All in all though, nice mod.


      Kyle
        • 25663 MODX Staff
        • 12,272 Posts
        Very nice indeed. Wanna bundle this one in when the keypress delay is added in Kyle?
          Ryan Thrash, MODX Co-Founder
          Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
          • 15987
          • 786 Posts
          Ryan, I think it would be a great addition to add to the main snippet. I would also like to have it so you can set a parameter that if you want the button you can use it or if you want the auto response it will do that. I will give it a good look over.

          Kyle
            • 26868
            • 15 Posts
            Thanks for the comments and for the idea.
            I’ve followed your ideas and upgraded the last version.
            Based on the comments from http://serversideguy.blogspot.com/2004/12/google-suggest-dissected.html about google suggest, i’ve made a main loop (it’s first called by the first keyup in the input field) and it’s the main loop who decide to call doSearch or not based on the previous value of the field in the last search.
            I think the timeout needs some tuning, but it works (it’s running on my home page)

            //ajaxSearch.js
            //Created by: KyleJ ([email protected])
            //Created on: 03/14/06
            //Description: This code is used to setup the ajax search request.
            //My thanks to Steve Smith of orderlist.com for sharing his code on how he did this
            
            //set the loading image to the correct location for you
            //set the close image to the correct location for you
            //set the ajax call to the correct location of ajaxSearch.php
            
            //---begin--- hack by thomas
            var _oldInputFieldValue=""; // inputField value (set during call to google...)...(was ta)
            var _currentInputFieldValue="";
            var _timeoutAdjustment=0; 
            //---end--- hack by thomas
            
            function activateSearch() {
                if ($('ajaxSearch_form')) {
                    var o = document.createElement('div'); // Old search results div
                    var n = document.createElement('div'); // New search results div
                    var i = document.createElement('img');
                    i.src = 'assets/snippets/AjaxSearch/indicator.white.gif'; //Loading Image
                    Element.toggle(i);
                    i.id = 'indicator';
                    
                    var c = document.createElement('img');
                    c.src = 'assets/snippets/AjaxSearch/close.gif';
                    Element.toggle(c);
                    c.id = 'searchClose';
                    c.onclick = function() { closeSearch(); };
                    
                    //---begin--- hack by thomas : un deuxième bouton close directement dans la zone de résultat
                    var c2 = document.createElement('img');
                    c2.src = 'assets/snippets/AjaxSearch/close.gif';
                    c2.id = 'searchClose2';
                    c2.style.position = 'absolute';
                    c2.style.top = '1px';
                    c2.style.right = '1px';
                    c2.onclick = function() { closeSearch(); };
                    //---end--- hack by thomas
                    
                    $('ajaxSearch_form').onsubmit = function() { doSearch(); return false; };
                    var s = $('ajaxSearch_output');
                    var f = $('ajaxSearch_form');
                    o.id = 'old-search-results';
                    n.id = 'current-search-results';
                    s.appendChild(c2); // hack by thomas
                    s.appendChild(n);
                    s.appendChild(o);
                    f.appendChild(i);
                    //f.appendChild(c); // hack by thomas : on enlève le close a côté de l'input 
                    o.style.display = 'none';
                    n.style.display = 'none';
                    // 's' does not appear to be properly selected ... results in the form itself...
                    is_searching = false;
                    search_open = false;
                    Event.observe($('ajaxSearch_input'), 'keyup', mainLoop, false); // hack by thomas : on monitore le keyup..
                    $('ajaxSearch_submit').style.display = 'none'; // hack by thomas : si c'est en ajax, on n'affiche pas le bouton GO
                }
            }
            
            //---begin--- hack by thomas : loop for monitoring input change and call doSearch
            function recalculateTimeout(Mb){
              var H=100;
              for(var o=1; o<=(Mb-2)/2; o++){
                H=H*2
              }
              H=H+50;
              return H
            }
            
            function mainLoop() {
              _currentInputFieldValue = $F('ajaxSearch_input');
              if(_oldInputFieldValue!=_currentInputFieldValue){
                if (_currentInputFieldValue.length>2) {
                  if (doSearch())
                    _oldInputFieldValue=_currentInputFieldValue;
                }
                _timeoutAdjustment++;
                $('ajaxSearch_input').focus();
                
              }
              
              setTimeout("mainLoop()",recalculateTimeout(_timeoutAdjustment));
            }
            
            //---end--- hack by thomas
            
            
            
            function doSearch() {
                // If we're already loading, don't do anything
                if (is_searching) return false;
                s = $F('ajaxSearch_input');
                // Same if the search is blank
                if (s == '') return false;
                
                is_searching = true;
                c = $('current-search-results');
                o = $('old-search-results');
                Element.toggle($('indicator'));
                //---begin--- hack by thomas : on ne toggle pas l'élément qui n'est pas créé
                //if (!search_open) Element.toggle($('searchClose'));
                //---end---
                search_open = true;
                b = $('ajaxSearch_submit');
                b.disabled = true;
                o.innerHTML = c.innerHTML;
                c.style.display = 'none';
                o.style.display = 'block';
                // Setup the parameters and make the ajax call
                pars = 'search=' + encodeURIComponent(s) + '&maxResults=' + maxResults + '&stripHtml=' + stripHtml + '&stripSnip=' + stripSnip + '&stripSnippets=' + stripSnippets + '&useAllWords=' + useAllWords + '&searchStyle=' + escape(searchStyle) + '&minChars=' + minChars + '&showMoreResults=' + showMoreResults + '&moreResultsPage=' + moreResultsPage + '&moreResultsText=' + encodeURIComponent(moreResultsText) + '&resultsIntroFailure=' + encodeURIComponent(resultsIntroFailure) + '&extract=' + extract;
            
                //Make sure this points to the correct location.
                var myAjax = new Ajax.Request('index-ajax.php?q=assets/snippets/AjaxSearch/AjaxSearch.php', 
                          {method: 'get', parameters: pars, onComplete:doSearchResponse, onFailure: callBackAjaxFailure, onException: callBackAjaxExc}); // hack by thomas : added callbackFailure and Exception
                return true;
            }
            
            function doSearchResponse(response) {
                var o = $('ajaxSearch_output');
                o.style.display = 'block';
                $('current-search-results').innerHTML = decodeURIComponent(response.responseText);
                new Effect.Fade('ajaxSearch_intro',{duration:.15});
                new Effect.BlindUp('old-search-results',{duration:.8});
                new Effect.Appear('current-search-results',{duration:.8, afterFinish:resetForm});
            
            }
            
            //---begin--- hack by thomas : a small ajax error handling
            function callBackAjaxFailure(request, e) {
              alert('FAILURE AJAX : '+e.message);
              resetForm();
            }
            
            function callBackAjaxExc(request, e) {
              alert('EXCEPTION AJAX : '+e.message); //
              resetForm();
            }
            ///---end---
            
            function resetForm() {
                s = $('ajaxSearch_submit');
                s.disabled = false;
                //$('ajaxSearch_input').disabled = false; // hack by thomas
                Element.toggle($('indicator'));
                is_searching = false;
            }
            
            function closeSearch() {
                new Effect.BlindUp('current-search-results',{duration:.8, afterFinish:clearSearch});
                new Effect.BlindUp('old-search-results',{duration:.8});
            }
            
            function clearSearch() {
                //---begin--- hack by thomas : on ne toggle pas l'élément qui n'est pas créé
                //Element.toggle($('searchClose'));
                //---end---
                search_open = false;
                $('old-search-results').innerHTML = '';
                $('current-search-results').innerHTML = ''
                new Effect.Fade('ajaxSearch_output',{duration:.15});
                $('ajaxSearch_input').value=""; // hack by thomas
            }
            
            Event.observe(window, 'load', activateSearch, false);
            
              • 33175
              • 711 Posts
              Thanks Shadock for this great update of AjaxSearch smiley
                Sorry for my english. I&#39;m french... My dictionary is near me, but it&#39;s only a dictionary !
                • 15987
                • 786 Posts
                Looks great Shadock smiley

                I will try to get this added to the main snippet with a new parameter that allows you to use your functionality or the original.

                Let me know if you have anything else you are planning to add.

                Kyle
                  • 6726
                  • 7,075 Posts
                  I join the crowd to cheer on this mod and its integration to Ajax Search grin

                  Way to go, Shadock ! (BTW, your nick has anything to do with the french 60’s show "Les Shadoks" ?)
                    .: COO - Commerce Guys - Community Driven Innovation :.


                    MODx est l&#39;outil id
                    • 33337
                    • 3,975 Posts
                    Sounds great!

                    Thanks for sharing.

                    regards,

                    zi
                      Zaigham R - MODX Professional | Skype | Email | Twitter

                      Digging the interwebs for #MODX gems and bringing it to you. modx.link
                      • 26868
                      • 15 Posts
                      Way to go, Shadock ! (BTW, your nick has anything to do with the french 60’s show "Les Shadoks" ?)

                      Indeed Davidm, I use this nickname for years now, back to the amiga time when I was part of a coding group called ’shadocks’.
                      Don’t ask why shadock, I don’t remember, but it was a great show.. smiley