title: XPages typeahead: do like Google
body: <p>UPDATE</p>
  
  <p>This is now what I have in my xpage:</p>
  
  <pre><code>    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;xp:view xmlns:xp="http://www.ibm.com/xsp/core"&gt;
      &lt;xp:panel id="ContainerPanel"&gt;
      &lt;xp:inputText id="typeAhead"&gt;
          &lt;xp:eventHandler event="onchange" submit="true"
              refreshMode="norefresh"&gt;
              &lt;xp:this.action&gt;&lt;![CDATA[#{javascript://code here to trap the click in the list of values
  //displayed by the type ahead.  Code redirects to another page
  
  //the goal here would be to avoid the full/partial update and only use the CSJS
  //code to trigger the button's partial/full refresh so we can avoid having the onchange code
  //trigger a refresh when the user decides to click the button instead of clicking on a suggestion 
  //that is offered by the typeahead
  
  //I thought of using the temporary field and use it to store the value selected in the type ahead list,
  //so the code knows wheter we are running the CSJS from the type ahead list or from the button (the onchange
  //of the type ahead will fill this field so we know wether to trigger the CSJS partial refresh }]]&gt;&lt;/xp:this.action&gt;
              &lt;xp:this.script&gt;&lt;![CDATA[var selectedValue = document.getElementById("#{id:typeAhead}").value;
  var targetField = document.getElementById("#{id:temporaryField}");
  alert("typeAhead CSJS onchange: " + selectedValue);
  targetField.value = selectedValue;
  //init the partial refresh here!!!]]&gt;&lt;/xp:this.script&gt;
          &lt;/xp:eventHandler&gt;
          &lt;xp:typeAhead mode="partial" minChars="2"&gt;
              &lt;xp:this.valueList&gt;&lt;![CDATA[aaaa
  bbbb
  cccc
  dddd]]&gt;&lt;/xp:this.valueList&gt;
          &lt;/xp:typeAhead&gt;&lt;/xp:inputText&gt;
      &amp;#160;
      &lt;xp:button value="GO" id="button1"&gt;
          &lt;xp:eventHandler event="onclick" submit="true"
              refreshMode="complete"&gt;
              &lt;xp:this.action&gt;&lt;![CDATA[#{javascript://same call to the code called in the onchange event of the typeahead field
  mySSJSFunction();}]]&gt;&lt;/xp:this.action&gt;
          &lt;/xp:eventHandler&gt;&lt;/xp:button&gt;
      &lt;xp:br&gt;&lt;/xp:br&gt;
      &lt;xp:br&gt;&lt;/xp:br&gt;
      &lt;xp:inputText id="temporaryField"&gt;&lt;/xp:inputText&gt;
      &lt;/xp:panel&gt;
  &lt;/xp:view&gt;
  </code></pre>
  
  <p>Because the problem comes from the fact that the typeahead's onchange event is triggered even though the user just wants to type in something and go click on the button (therefore triggering the partial update of the event, so the code can call a SSJS function), I thought I'd get rid of the type ahead field's partial update and try to trigger it manually from CSJS.</p>
  
  <p>I am trying to use a temporary field to store the value selected in the type ahead so I can figure out if I need to run the SSJS function right away (the user selected a value in the list) or just don't do nothing as the user just wants to go and click on the button.</p>
  
  <p>Unfortunately, the code is at the office and I'm home right now, but the comments in the above code should give an idea of what I'm trying to achieve.  </p>
  
  <p>Not sure either if I should use XSP._partialRefresh(), XSP.PartialRefreshGet() and which control ID should I use (if it has any importance).</p>
  
  <p>Hope it all makes sense...   Just trying to give the user the possibility to select a value in the type ahead list, or type something in the field and click the search button, both cases calling the same SSJS function (using either the value selected in the type ahead list or what has been typed in the field).</p>
  
  <hr>
  
  <p>FIRST POST</p>
  
  <p>I have a page with a field and a button, just like the Google page.  I have type ahead set up so it returns a list of documents title that correspond to the "search" term entered.  Because I want the application to load a page when the user clicks on an item from the type ahead list, I added some code to the onChange event of the type ahead field.  That works great, but...  </p>
  
  <p>Let's say a user wants to go ahead and click on the button anyways, because the list displayed by the type ahead field only show the top 10 search results, and the document he is looking for is not in that list, so he wants to trigger a "full search" by clicking on the search button.  What happens is that the onchange code of the field is triggered before the onclick code of the button, and due to a fullrefresh on the type ahead field, this triggers a page refreshand the user needs to click a second time on the button to actually open the search page.</p>
  
  <p>The question is quit esimple: how can I get the same behaviour as the Google page, opening up the page if I click on one of the suggestions, but also opening up a search page/search results page when clicking on the button?</p>
  
  <p>Here is the code so far:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;xp:view xmlns:xp="http://www.ibm.com/xsp/core"
      xmlns:xc="http://www.ibm.com/xsp/custom"
      xmlns:xp_1="http://www.ibm.com/xsp/coreex" dojoParseOnLoad="true"&gt;
  
  
      &lt;xp:this.resources&gt;
          &lt;xp:script src="/xpSortedSearches.jss" clientSide="false"&gt;&lt;/xp:script&gt;
          &lt;xp:script src="/xpadSearch.jss" clientSide="false"&gt;&lt;/xp:script&gt;
          &lt;xp:dojoModulePath loaded="true"
              url="/xsp/.ibmxspres/dojoroot/dojo/dojo.js"&gt;
          &lt;/xp:dojoModulePath&gt;
  
  
  
      &lt;/xp:this.resources&gt;
      &lt;xp:panel id="PanelSearch" style="text-align:right;"&gt;
  
          &lt;xp:inputText id="inputSearch"
              style="width:225px;height:20px;font-size:10pt;font-family:sans-serif;padding-left:5.0px;padding-top:5.0px;padding-bottom:2.0px; border:1px solid gray;"
              tabindex="0" disableClientSideValidation="false"
              disableModifiedFlag="true"&gt;
              &lt;xp:this.attrs&gt;
                  &lt;xp:attr name="placeholder"&gt;
                      &lt;xp:this.value&gt;&lt;![CDATA[#{javascript:if(sessionScope.lang=="fr") {
      "Entrez votre recherche ici ...";
  } else {
      "Enter your search query here...";
  }}]]&gt;&lt;/xp:this.value&gt;
                  &lt;/xp:attr&gt;
              &lt;/xp:this.attrs&gt;
  
  
              &lt;xp:typeAhead mode="full" minChars="3" valueMarkup="true"
                  var="searchQuery" ignoreCase="true"&gt;
                  &lt;xp:this.valueList&gt;&lt;![CDATA[#{javascript://TODO Memory management???
  getTypeAheadValuesFromSearchBar(getComponent("inputSearch").getValue());}]]&gt;&lt;/xp:this.valueList&gt;
              &lt;/xp:typeAhead&gt;
  
  
  
  
  
              &lt;xp:eventHandler event="onchange" submit="true"
                  refreshMode="complete"&gt;
                  &lt;xp:this.action&gt;&lt;![CDATA[#{javascript:var key:String = getComponent("inputSearch").getValue();
  if(!!key) {
      getDocFromSubject(key);
  }
  }]]&gt;&lt;/xp:this.action&gt;
                  &lt;xp:this.script&gt;&lt;![CDATA[showStandBy();
  return true;]]&gt;&lt;/xp:this.script&gt;
              &lt;/xp:eventHandler&gt;
              &lt;xp:eventHandler event="onkeypress" submit="true"
                  refreshMode="complete"&gt;
                  &lt;xp:this.script&gt;&lt;![CDATA[//if we have a enter, launch the search
  if (thisEvent.keyCode==13) {
        var qryField = document.getElementById("#{id:inputSearch}");
        if(doSearch(qryField)) {
            showStandBy();
            return true;
        } else {
            return false;
        }
  }else{
        return false;
  }]]&gt;&lt;/xp:this.script&gt;
                  &lt;xp:this.action&gt;&lt;![CDATA[#{javascript:launchSearch();}]]&gt;&lt;/xp:this.action&gt;
              &lt;/xp:eventHandler&gt;
  
          &lt;/xp:inputText&gt;
  
          &lt;xp:button id="button1" icon="/search.png"
              styleClass="searchButtonSmall"&gt;
              &lt;xp:eventHandler event="onclick" submit="true"
                  refreshMode="complete"&gt;
                  &lt;xp:this.onStart&gt;
                      StandbyDialog_Started();
                  &lt;/xp:this.onStart&gt;
                  &lt;xp:this.action&gt;&lt;![CDATA[#{javascript:launchSearch()}]]&gt;
                  &lt;/xp:this.action&gt;
  
                  &lt;xp:this.script&gt;&lt;![CDATA[  var qryField = document.getElementById("#{id:inputSearch}");
    if(doSearch(qryField)) {
        showStandBy();
        return true;
    } else {
        return false;
    }]]&gt;&lt;/xp:this.script&gt;
              &lt;/xp:eventHandler&gt;
          &lt;/xp:button&gt;
          &lt;xp:br /&gt;
          &lt;/xp:panel&gt;
  
      &lt;!--
          This event handler makes sure the search box has the focus once the
          page is loaded
  
          &lt;xp:eventHandler event="onClientLoad" submit="false"&gt;
          &lt;xp:this.onStart&gt;
          StandbyDialog_Started();
          &lt;/xp:this.onStart&gt;
          &lt;xp:this.script&gt;&lt;![CDATA[var edit = dojo.byId("#{id:inputSearch}");
          if (edit) {
          edit.focus();
          }]]&gt;
          &lt;/xp:this.script&gt;
          &lt;/xp:eventHandler&gt;
      --&gt;
  
  
      &lt;xp:eventHandler event="onClientLoad" submit="false"&gt;
          &lt;xp:this.script&gt;&lt;![CDATA[var edit = dojo.byId("#{id:inputSearch}");
  if (edit) {
      edit.focus();
  }]]&gt;&lt;/xp:this.script&gt;
      &lt;/xp:eventHandler&gt;&lt;/xp:view&gt;
  </code></pre>