I'm using fetch API to access a REST API I developed and hosted online. But when retrieving data from the database (>60 rows) to be displayed in a section of the page, it takes about 3-5 seconds to display the data which I styled with HTML and CSS.
My question is how can i implement a css preloader to load before the actual data is displayed. And how do i know that the data has been displayed.
Below is a part of my code.
// Front end
frontend.html
<table>
<caption>User requests</caption>
<thead class="table-head">
<tr>
<th scope="col">Request Id</th>
<th scope="col">User ID</th>
<th scope="col">Brand</th>
<th scope="col">Type</th>
</tr>
</thead>
<tbody id="tablebody">
<div class="loader" id="loader"></div>
</tbody>
</table>
// file.js
fetch(url, {
method: 'GET',
headers: {'Authorization': 'Bearer ' +token}
}).then(response =>{
// Redirect the user to the login page
// If the user is not an admin
if(response.status === 401) {
window.location.replace('./Index.html');
}
return response.json()
})
.then((data) => {
let completedata = data.allRequests;
if(completedata) {
completedata.forEach((item) => {
timeStamp = new Date(item.createdon);
dateTime = timeStamp.toDateString();
theOutput +=`<tr id="listofrequests"><td data-
label="Request Id">${item.id}</td> </a>
<td data-label="Brand">${item.userid}</td>
<td data-label="Brand">${item.brand}</td>
<td data-label="Type">${item.other}</td>
<td data-label="Status">${item.name}</td>
<td data-label="Status"><a href="./Request-status.html" class="btn
view-detail" id="${item.id}" onClick="adminviewonerequest(this.id)">view</a>
</td>
<td data-label="Cancel"><button class="danger" id="${item.id}"
name="${item.name}" onClick="return cancelrequest(this.id, this.name)"><i
class="fa fa-trash"> Cancel Request</i></button></td>
</tr>`;
});
}
else {
toastr.warning(data.message);
}
document.getElementById('tablebody').innerHTML = theOutput;
})
.catch(err => console.log(err));
Use on of those already implemented load spinners How to make a loading spinner in html
Then , In your html code add <div id="loading" class="loader"></div> , Which make the loader displayed by default
and Using fetch :
fetch(YouUrl)
.then(res => {
if(res == 404){
// To hide the loader when the error is happen , There is no need to use loader
// Show some toaster notification for the user or sweet alert
document.getElementById("loading").style.display = 'none';
}
})
.then(json => {
// Here is your data so you need to hide the loader
document.getElementById("loading").style.display = 'none';
});
Related
I am creating a chat application using next js, node js, express js, and MongoDB. I used the next-auth for authentication. i am using google authentication. I am getting the session object by using the getSession() hook. from this session object, I get the user id which is the same id in the database. I use this "user-id" to post or get information from the database.
my question: is this a safe way because I am not sending any jwt token to verify users from the backend? as you can see I am not sending jwt token.
my concern: if I send or get data like this then anybody can access the data if the know the user-id.
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import axios from 'axios';
import { getSession } from 'next-auth/react';
import Modal from '../../components/popupchat/modal';
const PopupChat = ({ data }) => {
const [chatList, setChatList] = useState([]);
useEffect(() => {
const getChatList = async () => {
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API_URL}api/chat/admin/${data.user.id}`
);
setChatList(res.data);
};
getChatList();
}, []);
return (
<>
<Modal data={data} />
<div className="overflow-x-auto relative">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
Chat Name
</th>
<th scope="col" className="py-3 px-6">
Chat Title
</th>
<th scope="col" className="py-3 px-6">
Created AT
</th>
<th scope="col" className="py-3 px-6">
Open
</th>
</tr>
</thead>
{chatList &&
chatList.map((singleChat, index) => {
return (
<tbody key={index}>
<tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.chatName}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.chatTitle}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{singleChat.createdAt}
</td>
<td className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
<Link href={`/popupchat/${singleChat._id}`}>Open</Link>
</td>
</tr>
</tbody>
);
})}
</table>
</div>
</>
);
};
export default PopupChat;
export async function getServerSideProps({ req }) {
const session = await getSession({ req });
if (!session) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
return {
props: {
data: session,
},
};
}
It's not safe at all. "Security by obscurity" is not security, it's an illusion of making something somehow secure. You should always properly secure access to your backend resources. Authenticate users, then establish sessions or provide the frontend client with an access token.
You can include the user ID in the path to your backend endpoint, but the request should contain some credentials (session, access token, even a password) so that the backend can authorize the request. The backend must be able to tell if the caller is authorized to access that user's information. Just knowing the user ID is not enough.
I am facing the problem in redirecting to index page. Instead page refreshes to same create page perhaps due to large size images are still copying but why page refreshing instead of images waiting copying to finish and then redirecting.
module.exports.create_customModel_post = async (req, res) => {
const {images} = req.files
let myPromise = []
if (images) {
const dir = `./public/${req.body.slug}`
fs.mkdirSync(dir, { recursive: true });
for (let i = 0; i < images.length; i++) {
const uploadTo = `${dir}/${images[i].name}`
myPromise.push(new Promise(function(resolve, reject) {
images[i].mv(uploadTo, (err) => {
if(err){
reject(err);
}else{
resolve(uploadTo);
}
});
}));
}
}
Promise.all(myPromise).then(function(values) {
console.log(values),
// THIS REDIRECT IS NOT WORKING
res.redirect('/admin/custom-models')
}).catch(function (reasons) {
console.log(reasons);
});
}
Response from server
POST /admin/create-custom-model - - ms - -
new model is created & saved
[
'./public/testing/attachment_48549925.svg',
'./public/testing/brand-name.png',
'./public/testing/design.svg',
'./public/testing/model-name.png',
'./public/testing/path9080.png',
]
GET /admin/create-custom-model 200 12.375 ms - -
here is form I am using. Removed extra
<main>
<section class="">
<div class="container">
<h1>Create Custom Model</h1>
<table class="">
<form enctype="multipart/form-data" method="post">
<tr>
<td></td>
<td>
<input type="file" name="images" multiple>
</td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td>Cancel </td>
<td><button type="submit" >Save</button></td>
</tr>
</form>
</table>
</div>
</section>
</main>
I need map a array inside my page, and show the result in a table, but the content don't show up when I compiled the page.
Can anyone help me?
When I print in console the content of a var, this is here. But the info don't show up in the page
import Layout, { siteTitle } from '../components/layout'
const fetch = require('node-fetch');
export default function Home({ devices }) {
return (
<Layout >
{devices.map((device) => (
<table>
<thead>
<th>
{device.localname} / {device.localIP}
</th>
</thead>
{console.log('1')}
<tbody>
<tr>
<td>
{device.IPaddress[0][3].value} // I put this to test, and this works fine
</td>
</tr>
{device.IPaddress.map((port) =>{
<tr>
<td>
{console.log(port[3].value), port[3].value} // here I need to work, I want to put all results of port in a TD tag, the console.log shows up the info, but the page not.
</td>
</tr>
})}
</tbody>
</table>
))}
</Layout >
)
}
export async function getStaticProps() {
const res = await fetch('http://localhost:3000')
const devices = await res.json()
return {
props: {
devices
}
}
}
As commented by #evgenifotia, change the ( for { inside the second array map works fine.
here the final function:
export default function Home({ devices }) {
return (
<Layout >
{devices.map((device) => (
<table>
{console.log('1')}
<tbody>
<tr>
<th>
{device.localname} / {device.localIP}
</th>
</tr>
{device.IPaddress.map(port =>(
<tr>
<td>
{console.log(port[3].value), port[3].value}
</td>
</tr>
))}
</tbody>
</table>
))}
</Layout >
)
}
I'm trying to build a project in nodejs as server and firebase as my realtime db and having some problems with forwarding the data to my html.
I getting the error:
Cannot set headers after they are sent to the client
on change
I'm trying to pass the updated arr to html but can't find a way to do that.
server.js:
const locksRef = await firebase.firebase.database().ref('locks')
let arr = []
//get list of locks
const t = locksRef.on('value', (data) => {
tempResult3 = data.val()
result3 = []
const numOfKeys = Object.keys(tempResult3)
numOfKeys.forEach((x) => {
result3.push(tempResult3[x])
})
result3.forEach((k) => {
myLocks.forEach((my) => {
if (k.id == my) {
arr.push(k)
}
})
})
res.render('ListOfLocks', { arr })
})
html
<body>
<h1>ListOfHouses</h1>
<table border="1px solid black">
<thead>
<th>Name And Address</th>
</thead>
<tbody>
{{#each arr}}
<tr>
<td id="data"> {{name}} - {{address}}</td>
<td>
<form action="/seekKeys" method="post"><button name="{{locks}}" type="submit">LookForKey</button>
</form>
</td>
</tr>
{{/each}}
</tbody>
</table>
</body>
im learning create fullstack apps and i have a problem with delete the record from database backend request work however, I can't add a button that will trigger removal
const Todo = props => (
<tr>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_description}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_responsible}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_priority}</td>
<td className="TableTitle">
<Link to={"/edit/"+props.todo._id} className="a_edit"><img src={edit} alt="Edytuj" className="favicon"/></Link>
<button onSubmit={this.delete}>Usunięcie</button>
</td>
</tr>
)
constructor(props) {
super(props);
this.delete = this.delete.bind(this);
this.state = {todos: []};
}
delete(){
axios.get('http://localhost:4000/todos/delete'+this.props.obj._id)
.then(console.log('Deleted'))
.catch(err =>console.log(err))
}
there is a delete method:
constructor(props) {
super(props);
this.OnRemoveTodo = this.OnRemoveTodo.bind(this);
this.state = {todos: []};
}
OnRemoveTodo(){
axios.get('http://localhost:4000/todos/delete'+this.todo._id)
.then(console.log('Deleted'))
.catch(err =>console.log(err))
}
there is changed const Todo:
const Todo = props => (
<tr>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_description}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_responsible}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_priority}</td>
<td className="TableTitle">
<Link to={"/edit/"+props.todo._id} className="a_edit"><img src={edit} alt="Edytuj" className="favicon"/></Link>
<button onSubmit={props.OnRemoveTodo}><img src={trash} alt="Usuń" className="favicon"/></button>
</td>
</tr>
)
and here is the backend code to which I am trying to appeal
todoRoutes.route('/delete/:id').get(function (req, res) {
Todo.findByIdAndDelete(req.params.id, function(err, todo) {
if(err) res.json(err);
else res.json('Successfully removed');
});
});
there is no this.delete method.
you are using functional component.
i thing you forgot to use props.delete
const Todo = props => (
<tr>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_description}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_responsible}</td>
<td className={props.todo.todo_completed ? 'completed' : 'TableText'}>{props.todo.todo_priority}</td>
<td className="TableTitle">
<Link to={"/edit/"+props.todo._id} className="a_edit"><img src={edit} alt="Edytuj" className="favicon"/></Link>
<button onSubmit={props.delete}>Usunięcie</button>
</td>
</tr>