Objective:
I have a button that runs a function to load more items from my Mongoose DataBase and add them to a table row. I use get to get and return data from my server side. And am following pointers from this post, but I am still unable to render what I need.
Client side code:
<main role="main">
<div class="container-fluid ">
<div class="card-columns" id="test" value="<%=deals%>">
<tbody>
<tr id="content"><% include partials/row.html %></tr>
</tbody>
</div>
</div>
<div class="container" style="max-width: 25rem; text-align: center;">
<a id="8-reload" class="btn more" onclick="loadMore(8)"></a>
</div>
<script >
const loadMore = async function(x){
const response = await fetch(`/${x}`);
if (!response.ok)
throw oops;
const data =await response.text();
console.log(data);
console.log($("#content"));
await document.getElementById('content').insertAdjacentHTML('beforeend',data);
}
</script>
Server JS request:
app.get(`/:count`, (req, res) => {
const count = parseInt(req.params.count);
database.find({}, (err, found) => {
if (!err){
res.render("more",{items:found},(err,html)=>{
if(!err){
res.send(html);
}else{
console.log(err);
}
});
} else {
console.log(err);
}
}).skip(count).limit(25);
});
when running the function nothing happens and browser console log reads the long string of html. and this for the place I want to append to:
jQuery.fn.init {}
proto: Object(0)
No errors on server console log. What am I missing?
UPDATE I tried Appending instead of to content to test and lo and behold I AM appending html, just not all of my content. int only inserts the opening and closing of the entire html template none of the content between it. Weird.
Okay looks like the big problem was two things. The first issue was I was appending to a place that the content couldn't append to. The second issue was My template started with Table rows with more content in them which would not allow other stuff to render. Once I moved my jquery to a parent id and removed the table rows everything came in fine!
Related
I want to make a system that limits the number of posts that get displayed and a load more button that loads them from where the limit stoped previously WITH the capability to change the ordering of those same posts.
Right now I have:
html/ejs:
<main>
<div class="container">
<%
if(results.lenght != 0){
var i = 1;
results.forEach(function(results){
%>
<div class="post">
<div class="op"><%= results.username %></div>
<h2 class="post-title"><%= results.title %></h2>
<div class="content"><p class="post-content"><%= results.content %></p></div>
</div>
<% i++; }) %>
<% } else { %>
locals.message1 = 'No posts found :(';
<% } %>
</div>
<div class="load-container"><a class="load" href="">Load more</a></div>
</main>
dropdown to select sorting:
<div class="drop">
<button onclick="drop()" class="drop-btn">Sort by</button>
<form id="dropdown-content" class="dropdown-content" method="POST">
<button type="submit" formaction="/" value="1">Newest</button>
<button type="submit" formaction="/" value="2">Oldest</button>
<button type="submit" formaction="/" value="3">Popular</button>
</form>
</div>
routes:
router.get('/', authController.isLoggedIn, (req, res, next) => {
sql = 'SELECT posts.username, time, title, content, user_file, audio FROM posts JOIN user on posts.user_id = user.id';
db.query(sql, function(err, results, fields){
if(err) throw err;
else if(results.length!=0){
res.render('index', {
user: results: results, time: moment.utc(new Date(results.time)).fromNow()
});
}
else {
res.render('index', {
user: message: 'Sorry, we don\'t have any posts :(', message1: 'Very sad...', results: results
});
}
})
});
I was thinking of having two variables in the route that would store the limit. Sort of like this:
var limit1: 0; // where to start displaying posts
var limit2: 8; // how many to display before stopping
// ADD 8 to both when button is clicked
var limit = 'LIMIT ' + limit1 + ', ' + limit2 + ';' //combining it for LIMIT in MySQL
db.query(sql + limit, function(err, results, fields)...
The problem is that I don't know how to keep track of how many I've already loaded and how to pass that data from the load more button in the EJS file to the router. The only way I currently know how to do is with a post form but I'm guessing that wouldn't be good at all.
For the sorting I would want to do basically the same thing:
// when new sorting is selected
var sorting = sorting; //selecting a sorting algorithm based on the button clicked
// reset the limits when new sorting is selected
limit1 = 0; limit 2 = 8;
db.query(sql + sorting + limit, function(err, results, fields)...
But again I don't know how I would tell the route about the changes and how I would store the limits... I've tried some things but I couldn't get the variable from the EJS on button click to the route('/'... So if I only got one thing out of this I would want it to be the variable passing.
I'm assuming you are brining back some results with the page load first correct?
With that assumption you have your main loop to display the posts
<main>
<div class="container">
<%
if(results.lenght !== 0){
results.forEach(results =>{
%>
<div class="post">
<div class="op"><%= results.username %></div>
<h2 class="post-title"><%= results.title %></h2>
<div class="content"><p class="post-content"><%= results.content%>
</p></div>
</div>
<%}) %>
<% } else { %>
No posts found :(
<% } %>
</div>
<input type="hidden" id="postCount" value="<%=results.length%>">
<div class="load-container"><a class="load" href="">Load more</a></div>
</main>
(slight edits made to use arrow function, also not sure what the count was for? But its not really needed from what I can tell, if you needed the count you could always just use the length of the results as they would be the same.)
Now, you need an api route of some kind to pass the update variables to so you can make the request. It will be similar to the original route, so in the same route file you would have something like
router.get('/update/:sort/:start', authController.isLoggedIn, (req, res, next) => {
// place relevent SQL code here that uses the passed params
// then send back JSON object back to the browser
res.json(jsonresponse)
});
So, in this sample, you would be passing the sort and start argument as part of an XHR/Fetch request, as you can see above, we have placed a hidden variable with the length of the original request so we know how many were returned, we will pass that as the 'start' value to the update endpoint and tell SQL to start at that record
(Note, you could extend that route to have other limits passed etc, Also doing dynamic queries like this can open you up for a SQLinjection so you will need to sanities those before passing them to the SQL Query)
From here you will have a change event handler on your page, that will listen for change events on the dropdown, from there you will take the value of that and pass that to an XHR request that hits the api endpoint with the passed variables, ones it returns the JSON object you will simply loop over it and append to the screen, once the loop is done, grab the total from the hidden object and add the total from the returned object so the next request knows where you left off (more for the load more option assuming)
I'm trying to change the page number of an API's endpoint using a variable instead of the actual number. It's a list of products, in each page it displays 8 itens. I was able to render it in the HTML, but I also need to make an expansive product list (which I'm having trouble with aswell).
But I cant make it work. The number is changing in the console.log, but not on the URL I'm fetching. Weirdly, it does use the variable number I placed.
Here is the full JS code:
let page = 1
const btnPage = document.querySelector('#nextPage')
btnPage.addEventListener('click', () => {
page++
console.log(page)
})
function fetchData() {
fetch(`https://frontend-intern-challenge-api.iurykrieger.vercel.app/products?page=${page}`)
.then(response => {
if(!response.ok) {
throw Error('ERROR');
}
return response.json();
}).then(data => {
console.log(data.products);
const html = data.products
.map(product => {
return `
<div class="products-item">
<img src="https:${product.image}" alt="Imagem" class="products-item-img"/>
<div class="products-item--info">
<h4>${product.name}</h4>
<p id="product-description">${product.description}</p>
<p>De: R$${product.oldPrice}</p>
<h3>Por: R$${product.price}</h3>
<p>ou 2x de R$${parseFloat((product.price) / 2)}</p>
<button>Comprar</button>
</div>
</div>
`;
//HTML generated inside the div class "products-wraper"
})
.join("");
document.getElementById('products').insertAdjacentHTML('afterbegin', html);
//.insertAdjacentHTML ratter than .innerHTML to avoid corrupting references
}).catch(error => {
console.log(error);
});
}
fetchData()
And the HTML linked that is been rendered:
<main>
<div class="products">
<div class="products-wraper" id="products"></div>
<button class="products-plus" id="nextPage">Ainda mais produtos aqui!</button>
</div>
</main>
I'm using that button to try and change the page number.
Can anyone help?
Looking at the code that has been posted, I don't see how fetchData() is called, aside from on page load.. On page load, page will always be 1, as a user hasn't had a chance to hit the button yet..
Should fetchData() be called within the event listener callback for clicking on the button?
So what im trying to do is query a Minecraft server with javascript, and with the response i get back with the api, i want to grab the .playerlist and put the response in this url (https://cravatar.eu/avatar/ {name} /100.png) for each person connected
If someone knows a better way to achieve this, i would very much appreciate your input!
Im also pretty new to javascript, so not fully know what im doing :/
Heres the HTML that i have (i know it may be messy, its also not fully my code)
<div class="card"> <div class="icon"><img src="https://cdn.worldvectorlogo.com/logos/minecraft-1.svg"></div><div class="header">
<div class="image"> <img src="https://res.cloudinary.com/lmn/image/upload/e_sharpen:100/f_auto,fl_lossy,q_auto/v1/gameskinnyc/u/n/t/untitled-a5150.jpg" alt="" /> </div>
<h2>Server Status</h2>
</div>
<div id="rest">Loading...</div>
<img src="https://cravatar.eu/avatar/" $face "/>
</div>
And here is the javascript
//Query api at this address
var url = "https://api.minetools.eu/query/play.aydaacraft.online/25565";
$.getJSON(url, function(r) {
//data is the JSON string
if(r.error){
$('#rest').html('Server Offline.');
return false;
}
var p1 = '';
if(r.Players > 0 ){ p1 = '<br>'+r.Playerlist; }
// Text to display below
$('#rest').html('Total Online: '+r.Players+p1);
// Trying to add playerlist to html url
$('#face').html+p1;
});
Since you've pasted jQuery code, I'll submit my answer in jQuery. However, I do recommend you learn primitive JavaScript and not focus your attention just on jQuery... it's become something of a meme on StackOverflow.
Starting off, you really should be wrapping your code in $(document).ready this'll only run the code when the page has loaded.
$(document).ready(() => {
// The document is ready, let's run some code!
});
Then add your AJAX request as normal inside this bracket.
$(document).ready(() => {
let url = "https://api.minetools.eu/query/play.aydaacraft.online/25565";
$.getJSON(url, response => {
});
});
Okay, whilst writing this, I checked the URL provided by OP and saw that it was timing out so I've grabbed a sample response from the Minetools' documentation.
{
"MaxPlayers": 200,
"Motd": "A Minecraft Server",
"Playerlist": [
"Connor",
"Kamil",
"David"
],
"Players": 3,
"Plugins": [],
"Software": "CraftBukkit on Bukkit 1.8.8-R0.2-SNAPSHOT",
"Version": "1.8.8",
"status": "OK"
}
So in your JSON response, you can see that Playerlist is a array which can contain multiple things in one variable. You can also iterate through an array, which is what we'll be doing to build the image URLs.
We iterate through an array using forEach.
$(document).ready(() => {
let url = "https://api.minetools.eu/query/play.aydaacraft.online/25565";
$.getJSON(url, response => {
response.Playerlist.forEach(playerName => {
console.log(playerName);
});
});
});
//Console:
//Connor
//Kamil
//David
Now that we're iterating through the player list we can start assembling the URLs for these images and adding them to your document's body.
I've cleaned up your HTML, take note of the new div#user-images I've added. This'll be the place where jQuery will add your images from the forEach loop.
<div class="card">
<div class="icon">
<img src="https://cdn.worldvectorlogo.com/logos/minecraft-1.svg">
</div>
<div class="header">
<div class="image">
<img src="https://res.cloudinary.com/lmn/image/upload/e_sharpen:100/f_auto,fl_lossy,q_auto/v1/gameskinnyc/u/n/t/untitled-a5150.jpg" alt="" />
</div>
<h2>Server Status</h2>
</div>
<!-- This div tag will need to hide when there is no error, or say when there is. -->
<div id="rest">Loading...</div>
<!-- The user images will be added inside this div. -->
<div id="user-images"></div>
</div>
Now we have our HTML ready we can start using the jQuery function appendTo to add elements into our div#user-images.
$(document).ready(() => {
let url = "https://api.minetools.eu/query/play.aydaacraft.online/25565";
$.getJSON(url, response => {
response.Playerlist.forEach(playerName => {
$(`<img src="https://cravatar.eu/avatar/${playerName}" />`).appendTo("#user-images");
});
});
});
Your div#user-images should start filling up with the images of players from the Playerlist array.
I noticed you added a simple way of showing whether or not there's an error with the API. We can interact with div#rest to show/hide or change text depending on the success of the response.
$(document).ready(() => {
let url = "https://api.minetools.eu/query/play.aydaacraft.online/25565";
$.getJSON(url, response => {
if(response.error){
$("#rest").html("The server is offline!");
}else{
//There is no error, hide the div#rest
$("#rest").hide();
response.Playerlist.forEach(playerName => {
$(`<img src="https://cravatar.eu/avatar/${playerName}" />`).appendTo("#user-images");
});
}
});
});
And that's it really. I hope this gives you some understanding of arrays, and iterating through them, as well as some DOM functions from jQuery.
I have the following JavaScript method for loading the messages in a mini chat app. The idea is that I have two HTML classes to position the message either on left or right depending on who sent it. The HTML and CSS are fine and work properly. My question is when it comes down to getting the messages from Firestore.
I have the following messages in order from first sent to last: Hello, hyd?, Good, Hello Sir, hey
But somehow strangely they are not ordered properly when displayed on the screen, I get first the messages sent from other user then it displays my messages. I am not sure where I messed up the code for this behavior but I somehow believe it has to do with the if statement where I check who sent the message. The document of a message in Firestore has the following structure:
{
createdAt: ....,
message: ....,
from: ....,
to: ....
}
let divMessagesLeft = document.getElementById("firstmessages--main-div-id");
let devMessagesRight = document.getElementById("firstmessages--main-div-id-2");
async function loadMessages() {
firebase.auth().onAuthStateChanged(async function (user) {
if (user) {
let messagesReference = firebase
.firestore()
.doc(`/chats/${user.displayName}`)
.collection(`/chats/${userChat.username}/messages`)
.orderBy("createdAt");
await messagesReference
.get()
.then(function (snapshot) {
snapshot.forEach(function (doc) {
console.log(doc.data().message);
if (doc.data().from === userChat.username || doc.data().to === user.displayName) {
const message = `<div class="messagee">${doc.data().message}</div>`;
divMessagesLeft.innerHTML += message;
} else {
const message = `<div class="messagee messagee-right">${doc.data().message}</div>`;
devMessagesRight.innerHTML += message;
}
});
});
} else {
console.log("Not logged in");
}
});
}
loadMessages();
<div id="chat-messages-main-div-id" class="chat-messages-main-div">
<div id="first-message-div-id" class="first-message-div">
<div id="firstmessages--main-div-id" class="firstmessages--main-div">
<!-- <div class="messagee">Hello</div> -->
</div>
</div>
<div id="first-message-right-id-2" class="first-message-right">
<div id="firstmessages--main-div-id-2" class="firstmessages--main-div">
<!-- <div class="messagee messagee-right">Hi</div> -->
</div>
</div>
</div>
I would try to replace the "||" operator with "&&", which is a more correct check to do.
(it will fail if you'll try messaging yourself, and you should think how you want to implement this scenario).
Also I think you need to add "desc" to the "order by" method.
I am trying to remove a single document from the collection in over server side with Meteor.methods by passing _id of object ,but it is not removing object , also tried other fields in that document but no go.
I have also tried FoodCategory.remove(removeID) ; that is also not working.
File 1 - displayCategorySection.html
<template name="categoryDisplaySection">
<div class="row categoryDisplay">
<div class="col-md-10 col-lg-10 ">
{{Category}}
</div>
<div class="col-md-2 col-lg-2 pull-right">
<i class="fa fa-minus-square"></i>
</div>
</div>
<div class="row ">
<div class="col-md-12 col-lg-12 identity">
{{_id}}
</div>
</div>
</template>
In the .JS file I am passing this _id to Meteor method deleteFoodCategory
File 2 - categoryDisplaySection.js
Template.categoryDisplaySection.events({
'click .fa-minus-square':function(evt,tmpl)
{
var remove_id = tmpl.$(".identity").text();
alert(remove_id);
/*****Server side call for document remove *****/
Meteor.call("deleteFoodCategory",remove_id,
function(error,result)
{ alert(result); });
}
});
Server Side File 3 - FoodCategorySection.js contain deleteFoodCategory method
Meteor.methods({
deleteFoodCategory: function(removeID)
{
return FoodCategory.remove({
'_id' : removeID
},
function(error,id)
{
if(id) { return id;} else { return error; }
});
}
});
Code is working correctly if I put _id like "RAEnLfomeqctuonnE" in place of variable removeID. I tried various options like '_id' or just _id without quotes , unable to figure out problem.Please take a look
Fetching the document _id from a div text is overkill, you could use the current data context instead :
Template.categoryDisplaySection.events({
"click .fa-minus-square": function(evt,tmpl){
var removeId = this._id;
alert(removeId);
Meteor.call("deleteFoodCategory", removeId);
});
In your Meteor method, you can simply pass the _id to Collection.remove :
Meteor.methods({
deleteFoodCategory: function(removeId){
return FoodCategory.remove(removeId);
}
});
Answer provided by saimeunt is also working correctly as far as original problem is concern , there is need to use .trim function with remove_id variable
File 2 - categoryDisplaySection.js
Template.categoryDisplaySection.events({
"click .fa-minus-square": function(evt,tmpl){
var remove_id = tmpl.$(".identity").text();
/**This line needed to be added**/
removeId = remove_id.trim();
alert(removeId);
/*****Server side call for data insert *****/
Meteor.call("deleteFoodCategory",removeId);
})
but as #saimeunt has said fetching the document _id from a div text is overkill,so using this_id from now on