Aula 75 – Loja Online – Auto Search
Aula 75 – Loja Online – Auto Search
Voltar para página principal do blog
Todas as aulas desse curso
Aula 74 Aula 76
Redes Sociais:
Meus links de afiliados:
Hostinger
Digital Ocean
One.com
Melhore seu NETWORKING
https://digitalinnovation.one/
Participe de comunidades de desenvolvedores:
Fiquem a vontade para me adicionar ao linkedin.
E também para me seguir no https://github.com/toticavalcanti.
Código final da aula:
https://github.com/toticavalcanti
Quer aprender python3 de graça e com certificado? Acesse então:
https://workover.com.br/python-codigo-fluente
Canais do Youtube
Toti
Backing Track / Play-Along
Código Fluente
Putz!
Vocal Techniques and Exercises
PIX para doações
Aula 75 – Loja Online – Auto Search
Vamos implementar o auto search, para quando o usuário digitar alguma coisa na barra de pesquisa, o app já faça a busca automaticamente, depois de um certo tempo de parar a digitação.
Para começar vamos abrir o e_commerce/templates/base.html.
e_commerce/templates/base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Base Template</title>
{% include 'base/css.html' %}
{% block base_head %}{% endblock base_head %}
</head>
<body>
{% include 'base/navbar.html' with nome_da_marca='Loja virtual' %}
<div class='container'>
{% block content %} {% endblock %}
</div>
{% include 'base/js.html' %}
<script>
$(document).ready(function(){
// Auto Search
const searchForm = $(".search-form")
const searchInput = searchForm.find("[name='q']")
const typingTimer = 0;
const typingInterval = 1500 // 1.5 seconds
searchInput.keyup(function(event){
console.log(event)
})
//Cart + Add Product
const productForm = $(".form-product-ajax")
productForm.submit(function(event){
event.preventDefault();
// console.log("O formulário não foi enviado!");
// o this pega os dados relacionados a esse form
const thisForm = $(this);
//const actionEndpoint = thisForm.attr("action");
const actionEndpoint = thisForm.attr("data-endpoint");
const httpMethod = thisForm.attr("method");
const formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
// console.log("Sucesso")
// console.log(data)
// console.log("Adicionado", data.added)
// console.log("Removido", data.removed)
const submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html("No carrinho <button type='submit' class='btn btn-link'>Excluir</button>")
} else {
submitSpan.html("<button type='submit' class='btn btn-success'>Adicionar</button>")
}
const navbarCount = $(".navbar-cart-count")
navbarCount.text(data.cartItemCount)
const currentPath = window.location.href
if(currentPath.indexOf("cart") != -1){
refreshCart()
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
})
function refreshCart(){
//console.log("Excluído do carrinho atual!")
const cartTable = $(".cart-table")
const cartBody = cartTable.find(".cart-body")
//cartBody.html("<h1>Mudou!</h1>")
const productsRow = cartBody.find(".cart-product")
const currentUrl = window.location.href
const refreshCartUrl = '/api/cart/';
const refreshCartMethod = "GET";
const data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data){
console.log(data)
const hiddenCartItemRemoveForm = $(".cart-item-remove-form")
if(data.products.length > 0){
productsRow.html(" ")
let i = data.products.length
$.each(data.products, function(index, value){
const newCartItemRemove = hiddenCartItemRemoveForm.clone()
newCartItemRemove.css("display", "block")
newCartItemRemove.find(".cart-item-product-id").val(value.id)
cartBody.prepend("<tr><th scope=\"row\">" + i +
"</th><td><a href='" + value.url + "'>" +
value.name + "</a>" + newCartItemRemove.html() + "</td><td>" + value.price + "</td></tr>")
i--
})
cartBody.find(".cart-subtotal").text(data.subtotal)
cartBody.find(".cart-total").text(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
}
})
</script>
</body>
</html>
Vamos colocar a classe search-form no form.
Com essa classe, poderemos fazer o update da pesquisa do usuário, a medida que ele vai digitando.
e_commerce/search/templates/search/snippets/search-form.html
<form method='GET' action='{% url "search:query" %}' class="form my-2 my-lg-0 search-form">
<div class="input-group">
<input class="form-control" type="search" placeholder="Search" name='q' aria-label="Search" value='{{ request.GET.q }}'>
<span class="input-group-btn">
<button class="btn btn-outline-success" type="submit">Search</button>
</span>
</div>
</form>
O que vimos no console.log() foi só o evento.
Vamos acessar o valor digitado pelo usuário, dentro desse evento.
e_commerce/templates/base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Base Template</title>
{% include 'base/css.html' %}
{% block base_head %}{% endblock base_head %}
</head>
<body>
{% include 'base/navbar.html' with nome_da_marca='Loja virtual' %}
<div class='container'>
{% block content %} {% endblock %}
</div>
{% include 'base/js.html' %}
<script>
$(document).ready(function(){
// Auto Search
const searchForm = $(".search-form")
const searchInput = searchForm.find("[name='q']")
const typingTimer = 0;
const typingInterval = 1500 // 1.5 seconds
searchInput.keyup(function(event){
console.log(searchInput.val())
})
//Cart + Add Product
const productForm = $(".form-product-ajax")
productForm.submit(function(event){
event.preventDefault();
// console.log("O formulário não foi enviado!");
// o this pega os dados relacionados a esse form
const thisForm = $(this);
//const actionEndpoint = thisForm.attr("action");
const actionEndpoint = thisForm.attr("data-endpoint");
const httpMethod = thisForm.attr("method");
const formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
// console.log("Sucesso")
// console.log(data)
// console.log("Adicionado", data.added)
// console.log("Removido", data.removed)
const submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html("No carrinho <button type='submit' class='btn btn-link'>Excluir</button>")
} else {
submitSpan.html("<button type='submit' class='btn btn-success'>Adicionar</button>")
}
const navbarCount = $(".navbar-cart-count")
navbarCount.text(data.cartItemCount)
const currentPath = window.location.href
if(currentPath.indexOf("cart") != -1){
refreshCart()
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
})
function refreshCart(){
//console.log("Excluído do carrinho atual!")
const cartTable = $(".cart-table")
const cartBody = cartTable.find(".cart-body")
//cartBody.html("<h1>Mudou!</h1>")
const productsRow = cartBody.find(".cart-product")
const currentUrl = window.location.href
const refreshCartUrl = '/api/cart/';
const refreshCartMethod = "GET";
const data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data){
console.log(data)
const hiddenCartItemRemoveForm = $(".cart-item-remove-form")
if(data.products.length > 0){
productsRow.html(" ")
let i = data.products.length
$.each(data.products, function(index, value){
const newCartItemRemove = hiddenCartItemRemoveForm.clone()
newCartItemRemove.css("display", "block")
newCartItemRemove.find(".cart-item-product-id").val(value.id)
cartBody.prepend("<tr><th scope=\"row\">" + i +
"</th><td><a href='" + value.url + "'>" +
value.name + "</a>" + newCartItemRemove.html() + "</td><td>" + value.price + "</td></tr>")
i--
})
cartBody.find(".cart-subtotal").text(data.subtotal)
cartBody.find(".cart-total").text(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
}
})
</script>
</body>
</html>
Agora vamos pegar o valor digitado e usar no auto search.
e_commerce/templates/base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Base Template</title>
{% include 'base/css.html' %}
{% block base_head %}{% endblock base_head %}
</head>
<body>
{% include 'base/navbar.html' with nome_da_marca='Loja virtual' %}
<div class='container'>
{% block content %} {% endblock %}
</div>
{% include 'base/js.html' %}
<script>
$(document).ready(function(){
// Auto Search
const searchForm = $(".search-form")
const searchInput = searchForm.find("[name='q']")
const typingTimer = 0;
const typingInterval = 1500 // 1.5 seconds
searchInput.keyup(function(event){
clearTimeout(typingTimer)
const typingTimer = setTimeout(peformSearch, typingInterval)
})
//Cart + Add Product
const productForm = $(".form-product-ajax")
productForm.submit(function(event){
event.preventDefault();
// console.log("O formulário não foi enviado!");
// o this pega os dados relacionados a esse form
const thisForm = $(this);
//const actionEndpoint = thisForm.attr("action");
const actionEndpoint = thisForm.attr("data-endpoint");
const httpMethod = thisForm.attr("method");
const formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
// console.log("Sucesso")
// console.log(data)
// console.log("Adicionado", data.added)
// console.log("Removido", data.removed)
const submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html("No carrinho <button type='submit' class='btn btn-link'>Excluir</button>")
} else {
submitSpan.html("<button type='submit' class='btn btn-success'>Adicionar</button>")
}
const navbarCount = $(".navbar-cart-count")
navbarCount.text(data.cartItemCount)
const currentPath = window.location.href
if(currentPath.indexOf("cart") != -1){
refreshCart()
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
})
function refreshCart(){
//console.log("Excluído do carrinho atual!")
const cartTable = $(".cart-table")
const cartBody = cartTable.find(".cart-body")
//cartBody.html("<h1>Mudou!</h1>")
const productsRow = cartBody.find(".cart-product")
const currentUrl = window.location.href
const refreshCartUrl = '/api/cart/';
const refreshCartMethod = "GET";
const data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data){
console.log(data)
const hiddenCartItemRemoveForm = $(".cart-item-remove-form")
if(data.products.length > 0){
productsRow.html(" ")
let i = data.products.length
$.each(data.products, function(index, value){
const newCartItemRemove = hiddenCartItemRemoveForm.clone()
newCartItemRemove.css("display", "block")
newCartItemRemove.find(".cart-item-product-id").val(value.id)
cartBody.prepend("<tr><th scope=\"row\">" + i +
"</th><td><a href='" + value.url + "'>" +
value.name + "</a>" + newCartItemRemove.html() + "</td><td>" + value.price + "</td></tr>")
i--
})
cartBody.find(".cart-subtotal").text(data.subtotal)
cartBody.find(".cart-total").text(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
}
})
</script>
</body>
</html>
Veja que estamos usando no django_ecommerce/e_commerce/templates/base/css.html o font-awesome.min.css.
Vamos usar ele para colocar uma animação de loading.
e_commerce/templates/base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Base Template</title>
{% include 'base/css.html' %}
{% block base_head %}{% endblock base_head %}
</head>
<body>
{% include 'base/navbar.html' with nome_da_marca='Loja virtual' %}
<div class='container'>
{% block content %} {% endblock %}
</div>
{% include 'base/js.html' %}
<script>
$(document).ready(function(){
// Auto Search
const searchForm = $(".search-form")
const searchInput = searchForm.find("[name='q']")
const typingTimer;
const typingInterval = 1500 // 1.5 seconds
const searchBtn = searchForm.find("[type='submit']")
searchInput.keyup(function(event){
clearTimeout(typingTimer)
const typingTimer = setTimeout(peformSearch, typingInterval)
})
function displaySearching(){
searchBtn.addClass("disabled")
searchBtn.html("<i class='fa fa-spin fa-spinner'></i> Searching...")
}
function peformSearch(){
displaySearching()
const query = searchInput.val()
window.location.href = '/search/?q=' + query
}
//Cart + Add Product
const productForm = $(".form-product-ajax")
productForm.submit(function(event){
event.preventDefault();
// console.log("O formulário não foi enviado!");
// o this pega os dados relacionados a esse form
const thisForm = $(this);
//const actionEndpoint = thisForm.attr("action");
const actionEndpoint = thisForm.attr("data-endpoint");
const httpMethod = thisForm.attr("method");
const formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
// console.log("Sucesso")
// console.log(data)
// console.log("Adicionado", data.added)
// console.log("Removido", data.removed)
const submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html("No carrinho <button type='submit' class='btn btn-link'>Excluir</button>")
} else {
submitSpan.html("<button type='submit' class='btn btn-success'>Adicionar</button>")
}
const navbarCount = $(".navbar-cart-count")
navbarCount.text(data.cartItemCount)
const currentPath = window.location.href
if(currentPath.indexOf("cart") != -1){
refreshCart()
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
})
function refreshCart(){
//console.log("Excluído do carrinho atual!")
const cartTable = $(".cart-table")
const cartBody = cartTable.find(".cart-body")
//cartBody.html("<h1>Mudou!</h1>")
const productsRow = cartBody.find(".cart-product")
const currentUrl = window.location.href
const refreshCartUrl = '/api/cart/';
const refreshCartMethod = "GET";
const data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data){
console.log(data)
const hiddenCartItemRemoveForm = $(".cart-item-remove-form")
if(data.products.length > 0){
productsRow.html(" ")
let i = data.products.length
$.each(data.products, function(index, value){
const newCartItemRemove = hiddenCartItemRemoveForm.clone()
newCartItemRemove.css("display", "block")
newCartItemRemove.find(".cart-item-product-id").val(value.id)
cartBody.prepend("<tr><th scope=\"row\">" + i +
"</th><td><a href='" + value.url + "'>" +
value.name + "</a>" + newCartItemRemove.html() + "</td><td>" + value.price + "</td></tr>")
i--
})
cartBody.find(".cart-subtotal").text(data.subtotal)
cartBody.find(".cart-total").text(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
}
})
</script>
</body>
</html>
Pra gente ver melhor o efeito da animação do search, vou colocar o window.location.href = ‘/search/?q=’ + query dentro de um setTimeout().
E reduzir o intervalo de digitação, o typingInterval para meio segundo.
e_commerce/templates/base.html
{% load static %}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Base Template</title>
{% include 'base/css.html' %}
{% block base_head %}{% endblock base_head %}
</head>
<body>
{% include 'base/navbar.html' with nome_da_marca='Loja virtual' %}
<div class='container'>
{% block content %} {% endblock %}
</div>
{% include 'base/js.html' %}
<script>
$(document).ready(function(){
// Auto Search
const searchForm = $(".search-form")
const searchInput = searchForm.find("[name='q']") // input name='q'
const typingTimer = 0;
const typingInterval = 500 // .5 seconds
const searchBtn = searchForm.find("[type='submit']")
searchInput.keyup(function(event){
// key released
clearTimeout(typingTimer)
typingTimer = setTimeout(performSearch, typingInterval)
})
searchInput.keydown(function(event){
// key pressed
clearTimeout(typingTimer)
})
function displaySearching(){
searchBtn.addClass("disabled")
searchBtn.html("<i class='fa fa-spin fa-spinner'></i> Searching...")
}
function performSearch(){
displaySearching()
var query = searchInput.val()
setTimeout(function(){
window.location.href='/search/?q=' + query
}, 1000)
}
//Cart + Add Product
const productForm = $(".form-product-ajax")
productForm.submit(function(event){
event.preventDefault();
// console.log("O formulário não foi enviado!");
// o this pega os dados relacionados a esse form
const thisForm = $(this);
//const actionEndpoint = thisForm.attr("action");
const actionEndpoint = thisForm.attr("data-endpoint");
const httpMethod = thisForm.attr("method");
const formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
// console.log("Sucesso")
// console.log(data)
// console.log("Adicionado", data.added)
// console.log("Removido", data.removed)
const submitSpan = thisForm.find(".submit-span")
if(data.added){
submitSpan.html("No carrinho <button type='submit' class='btn btn-link'>Excluir</button>")
} else {
submitSpan.html("<button type='submit' class='btn btn-success'>Adicionar</button>")
}
const navbarCount = $(".navbar-cart-count")
navbarCount.text(data.cartItemCount)
const currentPath = window.location.href
if(currentPath.indexOf("cart") != -1){
refreshCart()
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
})
function refreshCart(){
//console.log("Excluído do carrinho atual!")
const cartTable = $(".cart-table")
const cartBody = cartTable.find(".cart-body")
//cartBody.html("<h1>Mudou!</h1>")
const productsRow = cartBody.find(".cart-product")
const currentUrl = window.location.href
const refreshCartUrl = '/api/cart/';
const refreshCartMethod = "GET";
const data = {};
$.ajax({
url: refreshCartUrl,
method: refreshCartMethod,
data: data,
success: function(data){
console.log(data)
const hiddenCartItemRemoveForm = $(".cart-item-remove-form")
if(data.products.length > 0){
productsRow.html(" ")
let i = data.products.length
$.each(data.products, function(index, value){
const newCartItemRemove = hiddenCartItemRemoveForm.clone()
newCartItemRemove.css("display", "block")
newCartItemRemove.find(".cart-item-product-id").val(value.id)
cartBody.prepend("<tr><th scope=\"row\">" + i +
"</th><td><a href='" + value.url + "'>" +
value.name + "</a>" + newCartItemRemove.html() + "</td><td>" + value.price + "</td></tr>")
i--
})
cartBody.find(".cart-subtotal").text(data.subtotal)
cartBody.find(".cart-total").text(data.total)
} else {
window.location.href = currentUrl
}
},
error: function(errorData){
console.log("Erro")
console.log(errorData)
}
})
}
})
</script>
</body>
</html>
Essa mesma coisa pode ser usada para o auto save, da mesma forma que fizemos o auto search, alterando só os parâmetros.