implement pagination and the loading spinner to append element (multiple tabs) - javascript

I am new to javascript and creating the 2 tab to display the data. It is using the handlebar template and pure javascript. I want to add the loading spinner before the data is loaded in each tabs. How can implement the loading spinner to the multiple tabs when the data is retrieved using append method. i try to add the loading spinner but it always show the loading spinner eventhough the data has been loaded and displayed.When i try to add loading spinner it got the error of 'Cannot read property 'appendChild' of null' Any help will be appreciate. Below is the code without implement the loading spinner
function reload_api(){
let source = document.getElementById("template").innerHTML;
let template = Handlebars.compile(source);
let html = template(data_api.data);
document.getElementById("contents").innerHTML = html;
render_tab_contents();
document.getElementById("index-0").click();
}
function tab_contents() {
//this part is to display the data (tab content)
data_api.data.dropdown.forEach((agoptions) => {
data_api.data.fyafyidropdown.forEach((dropOptions) => {
for (const [key, value] of Object.entries(data_api.data.listing)) {
let groupName = `dropdowngroup_${agoptions.ag_id}_${agoptions.ad_id}_${dropOptions.value}`;
if (key == groupName) { document.getElementById(`ag_${agoptions.ag_id}_${agoptions.ad_id}`);
for (const [key1, val1] of Object.entries(value)) {
if (key1 != 'more_url') {
let contents = document.createElement('div');
contents.innerHTML ='<div class="line text-gray-500 flex flex-col divide-black divide-y-2 divide-opacity-25"><div class="flex justify-between items-center cursor-pointer p-2 transition duration-200 ease-in-out hover:bg-gray-100 hover:shadow-xl" ><div class="flex flex-col items-start">' + '<p class="font-semibold pb-1">' +val1.mail_serial_no + '</p><p class="pb-1 text-sm">'+ val1.mail_subject + '</p><div class="flex items-center pb-1"></div></div>'+ '<div class="flex-none"><div class="flex flex-col text-sm"><p class="px-2 py-1 font-semibold ">' + val1.pending_count + '</p></div></div></div></div>'; document.getElementById(`ag_${agoptions.ag_id}_${agoptions.ad_id}`).appendChild(contents);
}
}
}
}
});
if(document.getElementById(`ag_${agoptions.ag_id}_${agoptions.ad_id}`).innerHTML == ''){
document.getElementById(`ag_${agoptions.ag_id}_${agoptions.ad_id}`).innerHTML = '<div class="flex justify-center mt-4">No Records</div>';
}
});
}
function open(evt, Name) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(Name).style.display = "block";
evt.currentTarget.className += " active";
}
<script type="text/x-handlebar-template" id="template">
<div class="tab">
<div class="mb-1">
<div class="flex text-center text-gray-400">
{{#each dropdown}}
<button class="tablinks flex-1 py-2 px-4 border-b-2 cursor-pointer " id="index-{{#index}}" onclick="open(event, 'ag_{{ag_id}}_{{ad_id}}')">{{full_name}}</button>
{{/each}}
</div>
</div></div>
{{#each dropdown}}
<div id="agency_{{ag_id}}_{{ad_id}}" data-scope="ag_{{ag_id}}_{{ad_id}}" class="tabcontent">
//here is the data displayed. the data is retrieved and displayed using the javascript in tab_contents() //
</div>
{{/each}}
</script>
<div id="contents"></div>
// Here is the sample data from api
//data: {,…}
//dropdown: [{ag_id: "60", ad_id: "1", agency_short_name: "HQ", agency_full_name: "HQ",…},…]
//fyafyidropdown: [{label: "FYA", value: "fya"}, {label: "FYI", value: "fyi"}]
//listing: {agadgroup_60_1_fya: {,…},…}
//group_60_1_fya: {,…}
//group_60_1_fyi: {0: {mail_serial_no: "(Filing)", mail_subject: "123", pending_count: 1,…},…}

Related

How do I make this caroussel slider mouse / touch draggable (Tailwind CSS and Alpine JS)

I am trying to build a website and have this carousel, that was made with Alpine JS and Tailwind CSS. I took the Alpine Javascript from a template and it works according to specifications. But I would want to make it mouse draggable as well.
Here is the carousel slider
<div class="mt-24">
<script>
window.carousel = function () {
return {
container: null,
prev: null,
next: null,
init() {
this.container = this.$refs.container
this.update();
this.container.addEventListener('scroll', this.update.bind(this), {passive: true});
},
update() {
const rect = this.container.getBoundingClientRect();
const visibleElements = Array.from(this.container.children).filter((child) => {
const childRect = child.getBoundingClientRect()
return childRect.left >= rect.left && childRect.right <= rect.right;
});
if (visibleElements.length > 0) {
this.prev = this.getPrevElement(visibleElements);
this.next = this.getNextElement(visibleElements);
}
},
getPrevElement(list) {
const sibling = list[0].previousElementSibling;
if (sibling instanceof HTMLElement) {
return sibling;
}
return null;
},
getNextElement(list) {
const sibling = list[list.length - 1].nextElementSibling;
if (sibling instanceof HTMLElement) {
return sibling;
}
return null;
},
scrollTo(element) {
const current = this.container;
if (!current || !element) return;
const nextScrollPosition =
element.offsetLeft +
element.getBoundingClientRect().width / 2 -
current.getBoundingClientRect().width / 2;
current.scroll({
left: nextScrollPosition,
behavior: 'smooth',
});
}
};
}
</script>
<style>
.scroll-snap-x {
scroll-snap-type: x mandatory;
}
.snap-center {
scroll-snap-align: center;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
</style>
<div class="flex mx-auto items-center">
<div x-data="carousel()" x-init="init()" class="relative overflow-hidden group">
<div x-ref="container"
class="ml-4 flex overflow-x-scroll scroll-snap-x space-x-4 no-scrollbar touch-pan-x cursor-pointer">
{% for origin in origins %}
<div class="group/item relative ml-4 flex-auto flex-grow-0 flex-shrink-0 w-4/5 sm:w-4/5 xl:w-2/5 rounded-lg bg-gray-100 items-center justify-center snap-center overflow-hidden shadow-md"><!-- items container -->
<div class="min-w-full h-full rounded-lg bg-gray-100 overflow-hidden shadow-md">
<div><img src="{{ origin.imgurl }}" alt="{{ origin.alt }}" class="object-cover h-96" /></div>
<div class="absolute bg-gray-800 bg-opacity-0 group-hover/item:bg-opacity-50 top-2/3 inset-x-0 text-center px-2 py-3">
<div class="text-2xl text-transparent group-hover/item:text-emerald-500 font-extrabold uppercase">{{ origin.name }}</div>
<div class="text-xl text-transparent group-hover/item:text-white font-bold">{{ origin.country }}</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div #click="scrollTo(prev)" x-show="prev !== null"
class="block absolute top-1/2 left-0 bg-white text-3xl p-2 rounded-full transition-transform ease-in-out transform -translate-x-full -translate-y-1/2 group-hover:translate-x-0 cursor-pointer">
<div><ion-icon name="chevron-back-outline"></ion-icon></div>
</div>
<div #click="scrollTo(next)" x-show="next !== null"
class="block absolute top-1/2 right-0 bg-white p-2 text-3xl rounded-full transition-transform ease-in-out transform translate-x-full -translate-y-1/2 group-hover:translate-x-0 cursor-pointer">
<div><ion-icon name="chevron-forward-outline"></ion-icon></div>
</div>
</div>
</div>
</div>
</div>
I tried adding Alpine script from a different carousel that has this function, but it does not do anything. My understanding of Javascript is rudimentary.

This code only allows the use of Carousel Post style one time

I recently learned about web development, and I want to build my own portfolio website using Github Pages. For the 'Portfolio' section, I want to use a slider using Javascript. Then, when I copy paste the code and change the title to 'Blog' section, this new section didn't apply the slider that seen in Portfolio.
I already seen multiple online sources to see where is my problem, and it shows that the getElementById only can be used one time. I try to modify the code to use querySelectorAll but it's still doesn't work.
This is the JS code that I used:
const sliderContainer = document.getElementById('sliderContainer');
const slider = document.getElementById('slider');
const cards = slider.getElementsByTagName('li');
var elementsToShow = 3;
if (document.body.clientWidth < 1000) {
elementsToShow = 1;
} else if (document.body.clientWidth < 1500) {
elementsToShow = 2;
}
var sliderContainerWidth = sliderContainer.clientWidth;
var cardWidth = sliderContainerWidth / elementsToShow;
slider.style.width = cards.length * cardWidth + 'px';
slider.style.transition = 'margin';
slider.style.transitionDuration = '1s';
for (var index = 0; index < cards.length; index++) {
const element = cards[index];
element.style.width = cardWidth + 'px';
}
function next() {
if (+slider.style.marginLeft.slice(0, -2) != -cardWidth * (cards.length - elementsToShow)) slider.style.marginLeft = +slider.style.marginLeft.slice(0, -2) - cardWidth + 'px';
}
function prev() {
if (+slider.style.marginLeft.slice(0, -2) != 0) slider.style.marginLeft = +slider.style.marginLeft.slice(0, -2) + cardWidth + 'px';
}
function autoPlay() {
prev();
if (+slider.style.marginLeft.slice(0, -2) === -cardWidth * (cards.length - elementsToShow)) {
slider.style.marginLeft = '0px';
}
setTimeout(() => {
autoPlay();
}, 3000);
}
and this is my HTML code. I use TailwindCSS for the CSS framework.
<div class="flex">
<div class="flex items-center">
<div class="w-full text-right">
<button class="bi bi-arrow-left-circle-fill mb-2 ml-2 flex h-9 w-9 items-center justify-center rounded-full border border-slate-300 text-slate-300 hover:border-primary hover:bg-primary hover:text-white"
onclick="prev()"
></button>
</div>
</div>
<div id="sliderContainer" class="overflow-hidden">
<ul id="slider" class="flex w-full">
<li>Slide 1</li>
<li>Slide 2</li>
<li>Slide 3</li>
</ul>
</div>
<div class="flex items-center">
<div class="w-full">
<button
onclick="next()"
class="bi bi-arrow-right-circle-fill mr-2 mb-2 ml-2 flex h-9 w-9 items-center justify-center rounded-full border border-slate-300 text-slate-300 hover:border-primary hover:bg-primary hover:text-white slider__btn--right"
></button>
</div>
</div>
</div>
Please help me modify the JS code so it can be use multiple times. thanks in advance!

Passing multiple variables into JavaScript function in Template Literals (DOM)

I am looping through an array of objects (rendering data coming from an API) via Vanilla JavaScript (DOM). And I want to pass more than one value (Product ID, Product Name .. etc) to a function triggered in the event of a click button. saveProduct(${proInfo}) as it shown below (proInfo is an object).
The problem is I have been able to pass ONLY ONE value to this function. I tried to pass the variable as an object but it didn't work and got the error (index):1 Uncaught SyntaxError: Unexpected end of input
var shopNcounter = 0;
const baseURL = "***";
const idsArray = [];
const divRow = document.querySelector(".row");
const buttonContainer = document.querySelector("#button-container")
//create column div
function createDiv() {
const div = document.createElement("div");
div.classList.add("col-xl-3");
div.classList.add("col-md-6");
div.classList.add("col-sm-12");
return div;
}
async function getData(id) {
shopNcounter ++;
console.log(shopNcounter);
if(shopNcounter > 5) {
getProInfo(id);
return;
} else if (shopNcounter > 4) {
getProducts(id);
return;
}
idsArray.push(id);
console.log(id);
console.log(idsArray);
if(idsArray.length > 10) {
idsArray.splice(0,6);
}
const api = `**shop=${shopNcounter}&id=${id}`;
try {
const response = await fetch(api);
const data = await response.json();
divRow.innerHTML = "";
if (shopNcounter > 1) {
buttonContainer.innerHTML = `
<button class="btn btn-lg btn-warning px-5" onclick="moveBack(${idsArray[idsArray.length-2]})">رجوع</button>
`
} else {
buttonContainer.innerHTML = "";
}
//mapping through data
data.map(item => {
const div = createDiv();
divRow.appendChild(div);
div.innerHTML+=`
<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<a onclick=handleClick(${item.id}) class="btn btn-outline-dark px-5 mt-4" id="goToItemButton">${item.name}</a>
</div>
</div>
`;
});
} catch(error) {console.log(error);}
}
getData(0);
async function getProducts(id) {
//shop > 4 = 5
console.log("Get Product is being executing");
const apiProducts = `**product?id=${id}`;
try {
const response = await fetch(apiProducts);
const data = await response.json();
console.log(data);
divRow.innerHTML = "";
//mapping through data
data.map((item, index) => {
var proInfo = {
pid: item.PID,
pname: item.PName
}
const div = createDiv();
divRow.appendChild(div);
div.innerHTML+=`
<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<h5>${item.PName}</h5>
<p class="product-price">Price: ${item.PSelPrice}</p>
<a onclick=saveProduct(${item.PID}) class="btn btn-danger px-5 mt-4"> Add to Card </a>
</div>
</div>
`;
});
} catch(error) {
console.log(error);
}
}
function moveBack(id) {
shopNcounter = shopNcounter -2;
getData(id);
}
function handleClick(id) {
let clickedButton = document.querySelector("#goToItemButton");
clickedButton.onclick = "";
getData(id);
}
function saveProduct(g) {
console.log(g);
}
your code should not result in the error you see
However you can make your life easier using delegation
do this
document.getElementById("container").innerHTML = data.map((item,i) => `<div class="card text-center h-100 mx-auto border-white shadow" style="width: 16rem;">
<img src="${baseURL + item.image}" class="card-img-top mx-auto" alt="...">
<div class="card-body">
<h5>${item.PName}</h5>
<p class="product-price">Price: ${item.PSelPrice}</p>
<a data-id="${i}" class="add btn btn-danger px-5 mt-4"> Add to Card </a>
</div>
</div>`).join("");
Have this
document.getElementById("container").addEventListener("click",function(e) {
const tgt = e.target.closest("a");
if (tgt && tgt.className.contains("add")) {
const item = data[tgt.dataset.id]
// here you can add the item
saveProduct({pid: item.PID,pname: item.PName })
}
})

I am having problems with CSS when I open my code in localhost

I saw this code in an article about discord Oauth2. As I have two HTML files so how do I connect both of them in this line: res.sendFile('index.html', { root: '.' });
And my both HTML files are not in a specific folder it's in the main file.
When I open my code with VS code live server it looks like this:
But when I open it with localhost:53134 it looks like this:
This is my index.html code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Montserrat Google Font -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght#900&display=swap" rel="stylesheet">
<!-- Changes this to your bot's name -->
<title>Discord Bot Website Template</title>
<!-- Change the content attribute's value to your bot's description -->
<meta name="description" content="An opensource discord bot website template that you can use to make your bot seem more professional!">
<!-- Change the content attribute's value to your name -->
<meta name="author" content="TrustedMercury">
<link rel="stylesheet" href="styles/theTrendingStyle.css">
<link rel="stylesheet" href="styles/index.css">
<link rel="stylesheet" href="styles/css/all.css" />
</head>
<body class="bg-shinyGray overflow-x-hidden">
<nav id="navigationBar" class="flex flex-row items-center justify-between p-6 bg-sweetBlack">
<div class="left flex flex-row items-center ml-10 md:ml-20 text-white">
<img src="images/botLogo.png" width="48px" height="48px" class="mr-2 hidden md:inline pointer-events-none noselect" />
Home
Pricing
</div>
<div class="right mr-10 md:mr-20">
<i class="fab fa-discord mr-1"></i> Invite
<div id="info">
Hoi!
</div>
</div>
</nav>
<div id="container" class="flex flex-col items-center justify-center">
<div class="flex flex-col items-center justify-center pt-40 text-center">
<span class="text-2xl md:text-5xl font-semibold text-white">Changing the way servers work</span>
<span class="text-gray-400 text-lg md:text-xl max-w-xl font-light">Helping servers grow exponentially with a simple solution. Make your server active and entertain your community with a simple solution - <b>a single discord bot</b>!</span>
<div class="flex flex-col md:flex-row mt-8">
Invite the bot now!
Join the Support Server
</div>
</div>
<svg class="bg-blurple" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="#1D1E23" fill-opacity="1" d="M0,160L48,138.7C96,117,192,75,288,74.7C384,75,480,117,576,160C672,203,768,245,864,261.3C960,277,1056,267,1152,240C1248,213,1344,171,1392,149.3L1440,128L1440,0L1392,0C1344,0,1248,0,1152,0C1056,0,960,0,864,0C768,0,672,0,576,0C480,0,384,0,288,0C192,0,96,0,48,0L0,0Z"></path></svg>
<div class="flex flex-col md:flex-row items-center justify-center w-full bg-blurple">
<img src="images/discordUI.png" class="max-w-xs md:max-w-5xl noselect pointer-events-none" />
<div class="flex flex-col items-center justify-center noselect">
<div class="flex flex-col items-center text-4xl mb-4">
<span class="font-montserrat font-black">200+</span>
<span class="font-montserrat font-black">SERVERS</span>
</div>
<div class="flex flex-col items-center text-4xl my-4">
<span class="font-montserrat font-black">14500+</span>
<span class="font-montserrat font-black">USERS</span>
</div>
<div class="flex flex-col items-center text-4xl mt-4">
<span class="font-montserrat font-black">2300+</span>
<span class="font-montserrat font-black">CHANNELS</span>
</div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="#7289DA" fill-opacity="1" d="M0,224L48,240C96,256,192,288,288,304C384,320,480,320,576,288C672,256,768,192,864,138.7C960,85,1056,43,1152,48C1248,53,1344,107,1392,133.3L1440,160L1440,0L1392,0C1344,0,1248,0,1152,0C1056,0,960,0,864,0C768,0,672,0,576,0C480,0,384,0,288,0C192,0,96,0,48,0L0,0Z"></path></svg>
<div class="flex flex-row items-center justify-center mb-10">
<span class="text-lg text-gray-400 font-semibold">Copyright © Kevin Thomas 2020</span>
</div>
</div>
<a id="login" style="display: none;" href="Oauth link here">Identify Yourself</a>
<script>
function generateRandomString() {
const rand = Math.floor(Math.random() * 10);
let randStr = '';
for (let i = 0; i < 20 + rand; i++) {
randStr += String.fromCharCode(33 + Math.floor(Math.random() * 94));
}
return randStr;
}
window.onload = function () {
const fragment = parseQuery(window.location.href);
if (fragment.access_token) {
const urlState = fragment.state;
const stateParameter = localStorage.getItem('stateParameter');
if (stateParameter !== atob(decodeURIComponent(urlState))) {
return console.log('You may have been clickjacked!');
}
const accessToken = fragment.access_token;
const tokenType = fragment.token_type;
fetch('https://discordapp.com/api/users/#me', {
headers: {
authorization: `${tokenType} ${accessToken}`
}
})
.then(res => res.json())
.then( (response) => {
console.log(response);
const { username, discriminator, avatar } = response;
document.getElementById('info').innerHTML = ` ${username}#${discriminator}`;
let user = provider.getResourceOwner(`${accessToken}`);
let avatar1 = 'https://cdn.discordapp.com/avatars/' + user.id + '/' + user.avatar + '.png ?size=225';
document.getElementsByClassName("avatar-img").src = avatar1;
})
.catch(console.error);
} else {
const randStr = generateRandomString();
localStorage.setItem('stateParameter', randStr);
document.getElementById('login').href += `&state=${encodeURIComponent(btoa(randStr))}`;
document.getElementById('login').style.display = 'block';
}
}
function parseQuery(queryString) {
var query = {};
var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
}
return query;
}
</script>
<script src="main.js"></script>
</body>
</html>
This is my javascript code:
const app = require('express')();
const fetch = require('node-fetch');
app.get('/', async (req, res) => {
let access_token;
let token_type;
if (req.query.code) {
const accessCode = req.query.code;
const data = {
client_id : 'client id here',
client_secret : 'client secret here',
grant_type : 'authorization_code',
redirect_uri : 'http://localhost:3000',
code : accessCode,
scope : 'identify'
};
const res = await fetch('https://discordapp.com/api/oauth2/token', {
method : 'POST',
body : new URLSearchParams(data),
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
}
});
const info = await res.json();
token_type = info.token_type;
access_token = info.access_token;
const post = await fetch('https://discordapp.com/api/users/#me', {
headers : {
authorization : `${token_type} ${access_token}`
}
});
const user = await post.json();
}
if (token_type && access_token && req.query.state) {
res
.status(200)
.redirect(
`http://localhost:3000/?code=${req.query.code}&state=${req.query
.state}&access_token=${access_token}&token_type=${token_type}`
);
} else {
res.sendFile('index.html', { root: '.' });
}
});
app.listen(3000);

Add style to specific multiple divs using Angular

sorry I am new in angular and StackOverflow
I have 3 divs and I want to add background-color: red to all divs which status is requesting payment. It should make background color to the second and the third div but it makes to only the third
html
<div class="col-md-4 mb-4" *ngFor="let invoice of Invoices let i=index">
<div id="{{'activeInvoice'+i}}" class=" d-flex justify-content-between align-items-center w-100 card-header ">
<strong class="text-gray-dark">{{langVar.Invoice}} {{invoice.invoiceNumber}}</strong>
<i class="fa fa-info-circle" title="show Details" aria-hidden="true" (click)="showInvoiceDetailsModal(invoice.id)"></i>
</div>
</div>
for (var i = 0; i <= this.Invoices.length-1; i++) {
console.log("invoice num", this.Invoices[i].invoiceNumber);
console.log("order", this.Invoices[i].order.length);
for (var j = 0; j <= this.Invoices[i].order.length - 1; j++) {
console.log("STATUS", this.Invoices[i].order[j].status);
if (this.Invoices[i].order[j].status == 'requestingPayment') {
var elementValue = 'activeInvoice'+i;
setTimeout(() => {
document.getElementById(elementValue).classList.add("cardBackGround");
}, 1000);
}
else {}
}
}
you can conditionally add CSS classes in angular using ngClass
<div [ngClass]={'cardBackGround': true }> </div>
// apply your condition instead of true

Categories