a searchban is probably one of the most important widgets for a website, that's where the user will search for all the information it wants...
So it's important to learn how to create a good searchbar as well...
But what I mean with "good searchbar"? what does a searchbar requires to be a good one?
1- the simplest as possible. All the user gotta do is type some information and get what he is looking for...
2- the less freezing, the better. Async requests are the way to avoid freezing the UI, so I suggest you to take a look at this topic I created, it will be extremely worth it:
viewtopic.php?f=5&p=831#p831
3- the less requests, the better. We gotta prevent the application to search for EVERY SINGLE THING the user types... if the user typing a word, there's no need to send a request for every single letter of that word.
Before we start to create a simple example...
I suggest you, once again, to take a look at this topic:
viewtopic.php?f=5&p=831#p831
It will help you to understand the async requests that are crucial to get where we want in this example.
So let's go...
STEP 1: create our searchbar
let's create our searchbar inside our navbar.
this is a very basic searchbar, I'm using some custom-made classes to style it but basically you can create it the way you desire...
But I want you to pay attention at:
1- the #searchbar input element. that's where the user will insert the some data
2- the #ModalSearch element. that's where the result of our async search (async request) will be displayed.
Código: Seleccionar todo
<nav class="navbar navbar-expand-lg navbar-light bg-white p-2">
<div class="container">
<a class="navbar-brand" href="{{Route('root')}}">
<img src="/vfatec/img/logo/icone_medio.png">
</a>
</div>
</nav>
<div class="navbar navbar-boxed navbar-expand-md navbar-dark mb-3 navbar-fixed-top">
<div class="container">
<div class="dropdown flex-grow-1 flex-md-grow-0">
<div class="flex-grow-1 position-relative">
<form class="navbar-form" action="{{ Route( 'pesquisa' ) }}" method="get">
<div class="input-group">
<input type="search" class="form-control form-control-lg" name="param" placeholder="Search" id="searchbar">
<div class="input-group-append">
<button class="btn btn-outline-border btn-lg">
<i class="fe fe-search"></i>
</button>
</div>
</div>
</form>
<div class="dropdown-menu dropdown-menu-lg w-100" id="ModalSearch" data-parent="#searchbar">
<div class="card card-lg shadow-border dropdown-item" data-toggle="collapse">
<div class="col-12" id="searchResult">
<div class="loader mx-auto"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
now, let's create the routes of our application...
the root route, basically is the one that will redirect us to the home page
the search route is the one that will act as a webservice processing and retrieving data
Código: Seleccionar todo
DEFINE APP oApp TITLE 'vfatec';
ON INIT Config() ;
CREDENTIALS 'teste' COOKIE 'teste'
DEFINE ROUTE 'root' URL '/' CONTROLLER 'home@controller.prg' METHOD 'GET' OF oApp
DEFINE ROUTE 'search' URL 'search' CONTROLLER 'search@ws.prg' METHOD 'GET' OF oApp
//Inicialização da aplicação
INIT APP oApp
this controller is responsible for the navigation
Código: Seleccionar todo
CLASS controller
METHOD New(oController) CONSTRUCTOR
METHOD home(oController)
ENDCLASS
METHOD New(oController) CLASS controller
RETURN Self
METHOD home(oController) CLASS controller
oController:View("/home.view")
RETURN NIL
this controller will act as a webservice, it will recieve the async requests that we are about to send, process e retrieve data right back to the application
Código: Seleccionar todo
CLASS WS
METHOD New(oController) CONSTRUCTOR
METHOD search(oController)
ENDCLASS
METHOD New(oController) CLASS WS
RETURN Self
METHOD search(oController) CLASS WS
LOCAL oTable,hResponse:={=>},aParam:={},hData:={=>}
hData:=oController:oRequest:GetAll()
Aadd(aParam,hData['param'])
cQuery := "SELECT * FROM content WHERE field1 LIKE '%PARAM01%' "
oTable := App():oBD:QueryJson(cQuery,aParam)
oController:oResponse:SendJson(oTable)
RETURN NIL
now, let's get back to our view from the step one and add this script.
the first event listener inside this script is responsible for closing the modal (where the results from the search will be located) when we cancel the searching process.
the keyup function is responsible for identifying when the user is typing. In this case, if the user takes more than 0,5secs to type, the application will send a request to search for the application that the user typed.
notice that there are two variables that are extremely important for the whole process to work properly: pesqseq and pesqsend.
these variables are in charge of granting that the results from the right sequence of requests will be displayed to the user. We are talking about async requests, so it's important to understand that if these variables didn't exist, the results from a previous request could be displayed as the final result to the user...
Código: Seleccionar todo
<script>
var npag=0
var pesqseq=0
document.getElementById("searchbar").addEventListener("search", function(event) {
var div = document.querySelector('#searchResult');
$("#ModalSearch").hide()
div.innerHTML='<div class="loader mx-auto"></div>';
});
$("#searchbar").keyup(function(e){
var div = document.querySelector('#searchResult');
var pesqsend;
pesqseq++;
pesqsend=pesqseq;
if($("#searchbar").val().length >= 1 )
{
$("#ModalSearch").show()
}
else
{
if($("#searchbar").val().length==0)
{
$("#ModalSearch").hide()
}
}
div.innerHTML='<div class="loader mx-auto"></div>';
setTimeout(function(){
if(pesqseq==pesqsend && $("#searchbar").val().length > 0)
{
$.ajax({
type: "GET",
url: "http://localhost/teste/search?param="+$("#searchbar").val(),
}).done(function(data,status) {
if(pesqseq==pesqsend)
{
var prodhtml='<div class="card">'+
'<div class="card-body">'+
'<div class="form-group-overflow">'
for(var i = 0; i < data.length; i++)
{
var obj = data[i];
prodhtml+= '<div class="custom-control custom-control-text m-2">'+
'<a class="custom-control-label" href="#">'+obj.field1+'</a>'+
'</div>'
}
prodhtml+='</div>'+
'</div>'+
'</div>'
div.innerHTML=prodhtml
}
}).fail(function(xhr, status, error) {
});
}
},500);
});
</script>
Hope it helps you!
Video of an example: