Catálogo de Produtos - Listar Produtos com AJAX
Como gerar listas de produtos diretamente da base de dados por ajax
DEMO
O carregamento por AJAX permite controlar a chamada dinâmica de listas de produtos. Pode ser usada por exemplo:
- eliminar paginação ao carregar mais itens durante rolagem;
- carregar produtos segundo interesse em locais específicos;
- carregar produtos em locais que não é necessariamente o catálogo;
🪑 Cuidado: Como a solicitação dos produtos é via data-driven direto para o banco, não é interessante utilizá-la sem necessidade;
📦 As listas de produtos podem ser estensas, já que geram páginas estáticas, ou seja, é melhor gerenciar via script o carregamento de 250 a 1000 produtos do que chamar dinâmicamente de 10 em 10, por exemplo;
🔎 Os recursos data-driven do catálogo são esses carregamentos assíncronos e as buscas, vale lembrar que se o site tem menos de 500 ou 1000 produtos, pode ser viável fazer a busca via script na lista do total de produtos.
Veja o exemplo na página inicial do catálogo dos componentes
Os carregamentos na página de exemplo:
Parâmetros utilizados no exemplo
A solicitação é por AJAX via API. Só funciona no domínio real do site.
Veja comentários das variáveis utilizadas na URL ($mainData é variável do PHP no contexto da home.php [template]);
URLs usadas acima:
//rolagem
var scrollDeep = 1;
xmlhttp.send("&categoryId=0&siteId='.$mainData['siteId'].'&scrollDeep="+scrollDeep+"&listQtd=4&req=listProducts&filters=83,84");
scrollDeep ++;
//produtos de uma caregoria
xmlhttpAjaxProduct.send("&categoryId=241&siteId='.$mainData['siteId'].'&scrollDeep=0&listQtd=1&req=listProducts&filters=83,84");
//produtos por id
xmlhttpAjaxProductByClick.send("&categoryId=0&siteId='.$mainData['siteId'].'&scrollDeep=0&listQtd=3&req=listProducts&filters=83,84&products=108018,108021,108022");
Exemplos de chamadas do script no contexto do template em PHP
Carregamento padrão para rolagem
Carregamento de produtos ao chegar no final da página. 83 e 84 são ids específicos de filtrosdo catálogo de componentes. A variável scrollDeep controla os limites das listas para não aparecem duplicados ou chegar no final.
Como este script foi utilizado na inicial, não usa-se categoria, mas pode adicionar o id da categoria dinamicamente em lists.php para listagens de categorias e categorias adicionais específicas.
<!-- load more products on scrolling -->
<script>
//scroll button to show more stuff
var scrollDeep = 1;
window.addEventListener("scroll", scrollF);
function scrollF(evt) {
//console.log("SCROLL:"+(window.innerHeight + window.scrollY+1));
//console.log("DOC:"+document.body.offsetHeight);
if ((window.innerHeight + window.scrollY + 1) >= document.body.offsetHeight) {
console.log("load more: "+scrollDeep);
if (navigator.onLine) {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
if(xmlhttp.status == 200){
let data = xmlhttp.responseText;
console.log(data);
if(data == 0) {
window.removeEventListener("scroll", scrollF);
}
else { //load additional list
let obj = JSON.parse(data);
console.log(obj);
var render = "";
for(var i = 0; i < obj.length; ++i) {
let product = JSON.parse(obj[i]);
console.log(product);
let productImg = "";
let productPrice = "";
if(product.img == "") {
productImg = "https://cdn.interago.com.br/img/png/w_0_q_8/1/mc/cdn//productGeneric";
}
else {
productImg = product.img;
}
productImg = productImg.replace("w_0_", "w_400_");
if(product.price != "0.00") {
productPrice = "<small>R$ </small>"+product.price;
productPrice = productPrice.replace(".", ",");
}
console.log(product[\'83\'][\'filterValue\']);
render += "<div class=\'col-6 col-sm-6 col-md-6 productItem\'>\
<a href=\'item/"+product.url+"\'>\
<div class=\'productImg\'>\
<img src=\'"+productImg+"\' alt=\'Imagem do produto "+product.title+"\' title=\'"+product.title+"\'/>\
</div>\
\
<h2 class=\'productTitle\' title=\'"+product.title+"\'>"+product.title+"</h2>\
<p class=\'productPrice\'>"+productPrice+"</p>\
\<p>"+product[\'83\'][\'filterKey\']+": "+product[\'83\'][\'filterValue\']+"</p>\
<p>"+product[\'84\'][\'filterKey\']+": "+product[\'84\'][\'filterValue\']+"</p>\
</a>\
</div>";
}
}
if(render != undefined) {
console.log(render); document.getElementById("listProductsContainer").insertAdjacentHTML("beforeend", render);
}
scrollDeep++;
}
}
}
let url = "https://www.interago.com.br/App/Extensions/5/compile/assets/loadProductList.php";
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.setTimeout = 6000; //6s
xmlhttp.ontimeout = function() {
console.log("🚨 tempo esgotado - impossível enviar");
}
xmlhttp.send("&categoryId=0&siteId='.$mainData['siteId'].'&scrollDeep="+scrollDeep+"&listQtd=4&req=listProducts&filters=83,84");
} else {
console.log("🚨 navegador offline");
}
}
}
</script>
Carregamento padrão de produtos por categoria
Neste exemplo os filtros 83 e 84 são exclusivos do exemplo. O carregamento no id específicos também.
<!-- load first product of a category -->
<script>
if(navigator.onLine) {
var xmlhttpAjaxProduct;
if (window.XMLHttpRequest) {
xmlhttpAjaxProduct = new XMLHttpRequest();
}
else {
xmlhttpAjaxProduct = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttpAjaxProduct.onreadystatechange = function() {
if (xmlhttpAjaxProduct.readyState == XMLHttpRequest.DONE ) {
if(xmlhttpAjaxProduct.status == 200){
let data = xmlhttpAjaxProduct.responseText;
console.log(data);
if(data == 0) {
window.removeEventListener("scroll", scrollF);
}
else { //load additional list
let obj = JSON.parse(data);
console.log(obj);
var render = "";
for(var i = 0; i < obj.length; ++i) {
let product = JSON.parse(obj[i]);
console.log(product);
let productImg = "";
let productPrice = "";
if(product.img == "") {
productImg = "https://cdn.interago.com.br/img/png/w_0_q_8/1/mc/cdn//productGeneric";
}
else {
productImg = product.img;
}
productImg = productImg.replace("w_0_", "w_400_");
if(product.price != "0.00") {
productPrice = "<small>R$ </small>"+product.price;
productPrice = productPrice.replace(".", ",");
}
render += "\
<div class=\'col-6 col-sm-6 col-md-6 productItem\'>\
<a href=\'item/"+product.url+"\'>\
<div class=\'productImg\'>\
<img src=\'"+productImg+"\' alt=\'Imagem do produto "+product.title+"\' title=\'"+product.title+"\'/>\
</div>\
\
<h2 class=\'productTitle\' title=\'"+product.title+"\'>"+product.title+"</h2>\
<p class=\'productPrice\'>"+productPrice+"</p>\
\<p>"+product[\'83\'][\'filterKey\']+": "+product[\'83\'][\'filterValue\']+"</p>\
<p>"+product[\'84\'][\'filterKey\']+": "+product[\'84\'][\'filterValue\']+"</p>\
</a>\
</div>";
}
}
if(render != undefined) {
console.log(render); document.getElementById("loadOneProductFromCategory").insertAdjacentHTML("afterbegin", render);
}
}
}
}
let url = "https://www.interago.com.br/App/Extensions/5/compile/assets/loadProductList.php";
xmlhttpAjaxProduct.open("POST", url, true);
xmlhttpAjaxProduct.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttpAjaxProduct.setTimeout = 6000; //6s
xmlhttpAjaxProduct.ontimeout = function() {
console.log("🚨 tempo esgotado - impossível enviar");
}
xmlhttpAjaxProduct.send("&categoryId=241&siteId='.$mainData['siteId'].'&scrollDeep=0&listQtd=1&req=listProducts&filters=83,84");
}
else {
console.log("🚨 navegador offline");
}
console.log("ending script...");
</script>
Carregamento de produtos por id
O id utilizado para imprimir e os filtros 83 e 84 só funcionam neste exemplo. Lembre-se que o total de produtos precisa estar na URL além dos ids separados por vírgula.
<!-- load one or any products by id on click a element -->
<script>
document.getElementById("loadProductsByDemandButton").addEventListener("click", loadProductsFunction, false);
function loadProductsFunction() {
if(navigator.onLine) {
var xmlhttpAjaxProductByClick;
if (window.XMLHttpRequest) {
xmlhttpAjaxProductByClick = new XMLHttpRequest();
}
else {
xmlhttpAjaxProductByClick = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttpAjaxProductByClick.onreadystatechange = function() {
if (xmlhttpAjaxProductByClick.readyState == XMLHttpRequest.DONE ) {
if(xmlhttpAjaxProductByClick.status == 200){
let data = xmlhttpAjaxProductByClick.responseText;
console.log(data);
if(data == 0) {
window.removeEventListener("scroll", scrollF);
}
else { //load additional list
let obj = JSON.parse(data);
console.log(obj);
var render = "";
for(var i = 0; i < obj.length; ++i) {
let product = JSON.parse(obj[i]);
console.log(product);
let productImg = "";
let productPrice = "";
if(product.img == "") {
productImg = "https://cdn.interago.com.br/img/png/w_0_q_8/1/mc/cdn//productGeneric";
}
else {
productImg = product.img;
}
productImg = productImg.replace("w_0_", "w_400_");
if(product.price != "0.00") {
productPrice = "<small>R$ </small>"+product.price;
productPrice = productPrice.replace(".", ",");
}
render += "\
<div class=\'col-6 col-sm-6 col-md-6 productItem\'>\
<a href=\'item/"+product.url+"\'>\
<div class=\'productImg\'>\
<img src=\'"+productImg+"\' alt=\'Imagem do produto "+product.title+"\' title=\'"+product.title+"\'/>\
</div>\
\
<h2 class=\'productTitle\' title=\'"+product.title+"\'>"+product.title+"</h2>\
<p class=\'productPrice\'>"+productPrice+"</p>\
\<p>"+product[\'83\'][\'filterKey\']+": "+product[\'83\'][\'filterValue\']+"</p>\
<p>"+product[\'84\'][\'filterKey\']+": "+product[\'84\'][\'filterValue\']+"</p>\
</a>\
</div>";
}
}
if(render != undefined) {
console.log(render); document.getElementById("loadProductsByDemand").insertAdjacentHTML("afterbegin", render);
}
}
}
}
let url = "https://www.interago.com.br/App/Extensions/5/compile/assets/loadProductList.php";
xmlhttpAjaxProductByClick.open("POST", url, true);
xmlhttpAjaxProductByClick.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttpAjaxProductByClick.setTimeout = 6000; //6s
xmlhttpAjaxProductByClick.ontimeout = function() {
console.log("🚨 tempo esgotado - impossível enviar");
}
xmlhttpAjaxProductByClick.send("&categoryId=0&siteId='.$mainData['siteId'].'&scrollDeep=0&listQtd=3&req=listProducts&filters=83,84&products=108018,108021,108022");
}
else {
console.log("🚨 navegador offline");
}
console.log("ending script...");
}
</script>