Hello guys I wanted to create my own “my orders” page with custom elements and repeaters. To create this:
I needed to insert an custom element into repeater and I did it I also made the custom element dynamic. I’m sending JSON string array via Velo setAttribute then I’m making the String array back to normal array via JSON.parse and it gets the data but the problem is custom elements is showing the
last data
on each repeater item even if I use $item selector inside repeater. Here is my codes:
Frontend Orders Page:
import wixMembers from 'wix-members';
import { getOrders } from 'backend/Wix-Data/orders.jsw'
$w.onReady(function () {
initPage()
});
let memberId;
let memberOrders;
async function initPage() {
memberId = await getMemberId();
await getOrderData()
await ordersRepeater()
}
function getMemberId() {
return wixMembers.currentMember.getMember()
.then((memberData) => {
return memberData._id;
})
.catch((err) => {
console.error(err)
})
}
function getOrderData() {
return getOrders(memberId)
.then((orderDatas) => {
return memberOrders = orderDatas;
})
.catch((err) => {
console.error(err)
})
}
function ordersRepeater() {
$w("#myOrdersRepeater").data = memberOrders;
$w("#myOrdersRepeater").onItemReady(($item, itemData, index) => {
$item("#orderDate").text = itemData.orderDate.toLocaleDateString();
$item("#orderId").text = itemData.orderNo.toString();
$item("#orderTotal").text = itemData.totals.total.toString();
$item("#expandDetails").onClick((event) => {
if ($item("#orderDetailsBox").collapsed === true) {
$item("#orderDetailsBox").expand()
} else {
$item("#orderDetailsBox").collapse()
}
})
console.log(itemData.lineItems)
$item("#orderLineItems").setAttribute('data', JSON.stringify(itemData.lineItems));
})
}
Backend getOrders function:
import wixData from 'wix-data'
export function getOrders(memberId) {
let options = {
"suppressAuth": true,
};
return wixData.query("Stores/Orders")
.eq("buyerInfo.id", memberId)
.find(options)
.then((orders) => {
if (orders.items.length > 0) {
let items = orders.items;
let frontendData = items.map((order, index) => {
if (order.billingInfo.address != undefined) {
return {
"_id": order._id,
"formattedAddress": order.billingInfo.address.formatted,
"memberEmail": order.buyerInfo.email,
"memberLastName": order.buyerInfo.lastName,
"memberFirstName": order.buyerInfo.firstName,
"memberId": order.buyerInfo.id,
"memberPhone": order.buyerInfo.phone,
"orderDate": order._dateCreated,
"orderNo": order.number,
"lineItems": order.lineItems.map((product) => {
return {
"productName": product.name,
"productQuantity": product.quantity,
"productSku": product.sku,
"tax": product.tax,
"productPrice": product.priceData.price,
"totalPrice": product.priceData.totalPrice,
"options": product.options,
"customTextFields": product.customTextFields,
"productImage": product.mediaItem.id,
"discount": product.discount
}
}),
"paymentStatus": order.paymentStatus,
"totals": order.totals
}
} else {
return {
"_id": order._id,
"formattedAddress": "Adres bulunamadı!",
"memberEmail": order.buyerInfo.email,
"memberLastName": order.buyerInfo.lastName,
"memberFirstName": order.buyerInfo.firstName,
"memberId": order.buyerInfo.id,
"memberPhone": order.buyerInfo.phone,
"orderDate": order._createdDate,
"orderNo": order.number,
"lineItems": order.lineItems.map((product) => {
return {
"productName": product.name,
"quantity": product.quantity,
"sku": product.sku,
"tax": product.tax,
"productPrice": product.priceData.price,
"totalPrice": product.priceData.totalPrice,
"options": product.options,
"customTextFields": product.customTextFields,
"productImage": product.mediaItem.src,
"discount": product.discount
}
}),
"paymentStatus": order.paymentStatus,
"totals": order.totals
}
}
})
console.log("Calisti")
return frontendData;
}
})
.catch((err) => {
console.error(err)
})
}
Custom element JS code:
const createStyle = () => {
const styleElement = document.createElement('style');
styleElement.innerHTML = `
* {
font-family: Poppins;
}
p {
padding: 0;
margin: 0;
font-size: 16px;
}
.grid {
display: grid;
width: 875px;
grid-template-columns: 1fr;
grid-row-gap: 2em;
justify-items: center;
align-items: center;
}
.orderTab {
display: grid;
grid-template-columns: 3fr 1fr;
grid-auto-rows: minmax(100px, auto);
}
.productDetails {
display: grid;
grid-template-columns: 1fr 8fr;
align-items: center;
justify-items: start;
}
.productImage {
margin-right: 20px;
align-items: center;
}
.productTexts {
display: grid;
grid-template-columns: 1fr;
grid-gap: 5px;
align-self: start;
}
.greyText {
color: #828282;
}
.productName {
margin-bottom: 10px;
}
.productDownload {
display: grid;
grid-template-columns: 1fr;
}
.productQuantity {
display: grid;
grid-template-columns: 1fr 1fr;
}
.price {
justify-self: end;
}
.downloadProduct {
justify-self: right;
align-self: end;
margin-bottom: 10px;
}
.downloadButton {
width: 220px;
height: 40px;
border: 0px;
background: #ec0038;
border-radius: 999px;
color: white;
font-size: 16px;
transition: 0.3s;
}
.downloadButton:hover {
cursor: pointer;
opacity: 70%;
}
`;
return styleElement;
};
let number = 0;
let innerHtml = (index) => {
let html = `
<div class="orderTab">
<div class="productDetails">
<div class="productImage">
<img id="productImage${index.toString()}" src="./normal.jpg" width="160px" height="100px" alt="">
</div>
<div class="productTexts">
<p id="productName${index.toString()}" class="productName">Yayıncı Paketi</p>
<p id="productSku${index.toString()}" class="greyText">Ürün Kodu: yayıncı-paketi-v1.09</p>
<p id="productPrice${index.toString()}" class="greyText">Fiyatı: 174.99₺</p>
</div>
</div>
<div class="productDownload">
<div class="productQuantity">
<p id="productQuantity${index.toString()}">Adet: 1</p>
<p id="productPriceTwo${index.toString()}" class="price">Fiyat: 174.99₺</p>
</div>
<div class="downloadProduct">
<a target="_blank" id="downloadProduct${index.toString()}"><button class="downloadButton">Son Sürümü İndir</button></a>
</div>
</div>
</div>
`;
return html;
}
const createGrid = () => {
const grid = document.createElement('div')
grid.className = "grid";
return grid;
}
const createOrderTab = (data, index) => {
const orderTab = document.createElement('div');
orderTab.innerHTML = innerHtml(index);
orderTab.querySelector(`#productImage${index.toString()}`).src = `https://static.wixstatic.com/media/${data.productImage}`;
orderTab.querySelector(`#productName${index.toString()}`).innerText = data.productName;
orderTab.querySelector(`#productSku${index.toString()}`).innerText = `Ürün Kodu: ${data.productSku}`;
orderTab.querySelector(`#productPrice${index.toString()}`).innerText = "Fiyat:" + data.productPrice + "₺";
orderTab.querySelector(`#productQuantity${index.toString()}`).innerText = `Adet: ${data.productQuantity}`;
orderTab.querySelector(`#productPriceTwo${index.toString()}`).innerText = data.productPrice + "₺";
orderTab.querySelector(`#downloadProduct${index.toString()}`).href = data.downloadProduct;
console.log(`Deneme${index}`)
console.log(orderTab.querySelector(`#productImage${index.toString()}`))
return orderTab;
}
let data;
class OrderTab extends HTMLElement {
constructor() {
super();
this.showInfo = true;
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(createStyle());
this.shadowRoot.appendChild(createGrid())
}
getData() {
return data = JSON.parse(this.getAttribute('data'))
}
setupRepeater() {
data.forEach((element) => {
console.log(number)
console.log(element)
this.shadowRoot.querySelector('.grid').appendChild(createOrderTab(element, number))
number++;
})
}
async connectedCallback() {
await this.getData()
this.setupRepeater()
}
disconnectedCallback() {
//
}
}
window.customElements.define('order-tab', OrderTab);
I tried to created different ID each time I create the HTML and it works every custom element has their own IDs. But like I said problem is every custom element shows the same data.
My questions:
Can I create this logic with custom element or setAttribute API will refresh the data each time I pass the data? Even if I use $item to pass the data via attribute. Or is there any other way to create this logic?
Thanks!