I have a WebSocket that adds people to a messaged list when they receive a message. I use a fetch to get information from the server to build the messaged list, but I cannot find an easy way to get the code to pause until the fetch completes. I cannot add await because the funciton is inside a websocket that isn't async. Does anyone have any suggestions on this?
socket.on('receive_message', function(data) {
let messaged_user_li = document.getElementById('messaged_user_li'+data['from_user']);
console.log('messaged_user_li: '+messaged_user_li)
if (messaged_user_li == null) {
console.log('if fired')
//THIS is the fetch I want to pause the function until complete. Note that the await here does not work since the funciton isn't async.
await fetch('/get_messaged_user/'+from_user).then((response) => {
response.json().then((data2) => {
loadMessagedUser(data2[0].id, data2[0].avatar, data2[0].username, data2[0].last_seen);
});
});
messaged_user_li = document.getElementById('messaged_user_li'+data['from_user']);
}
console.log('messaged_user_li: '+messaged_user_li)
let message_user = document.getElementById('message_user'+data['from_user']);
let message_target = document.getElementById("message_target"+data['from_user']);
if (messaged_user_li.classList.contains('active') == false) {
messaged_user_li.classList.add('flash-message');
}
if (message_user != null) {
data = `
<li class="clearfix">
<div class="message-data text-right">
<span class="message-data-time">just now</span>
</div>
<div class="message other-message float-right">`+data['message']+`</div>
</li>`;
message_target.innerHTML += data;
//Move scroller to bottom when message received
myDiv = message_user.querySelector(".chat-history");
myDiv.scrollTop = myDiv.scrollHeight;
}
});
Actually You can add async function in socket.on
socket.on('receive_message',async function(data) {
Related
I'm working in a net core app, i made a HttpPost function to know if an user marked like.
This is the function code:
var likesCancion = (from likesCanc in _context.table
where likesCanc.SongId == idCancion && likesCanc.UserId == idUser
select likesCanc.Likes).FirstOrDefault();
if (likesCancion == 1)
{
return 1;
}
else
{
return 0;
}
I have this:
<div class="col-3 col-sm-2 col-md-2">
<i class="far fa-heart" id="heart" data-idAudio = #song.Id>
<span class="badge" >#song.Likes</span>
</i>
</div>
This is the <div> that I want to change at the start of the page if the user liked it or not.
The #song.Likes its data filled from the database.
I made an ajax request inside a for loop and get the respond of my HttpPost function:
const iconosCorazon = document.querySelectorAll('#heart');
setTimeout(function () {
let idUser = $('#inputidUsuario').val();
function makeRequest(i)
{
$.ajax({
type: "POST",
url: "checkHeart",
data: { idCancion: i, idUser: idUser },
dataType: "text",
success: function (msg) {
console.log(msg);
**if (msg == 1) {
$('.fa-heart').removeClass("far text-dark");
$('.fa-heart').addClass("fa text-danger");
}
else
{
$('.fa-heart').removeClass("fa text-danger");
$('.fa-heart').addClass("far fa-heart");
}**
},
error: function (req, status, error) {
console.log(msg);
}
});
}
for (var i=0;i<iconosCorazon.length;i++) {
let idCancion = iconosCorazon[i].getAttribute('data-idAudio');
makeRequest(idCancion);
}
I want to assign the css class to the correct element coming from the function result.
The issue here its that ajax execute all the elements at once and change the classes only with the last lopped element. So the question is how can i assign the rigth class to each div element. eg: If result == 1 paint red, if result == 0 paint other color.
Sorry for my bad english
Im trying to make this code works
You should use $(".fa-heart:eq(index)") to locate the each element with same class name. Sample code below:
$(".div_test:eq(0)").css("border","2px solid yellow");
Test Result:
for example when i join room-1 then room-2 then room-3 and send message in room-3 that message will be emitted 3 times, when it should get sent just one time. i'm using vanilla JavaScript in the client side
server side
namespaces.forEach(namespace => {
// join namespace
io.of(namespace.endpoint).on('connection', socket => {
console.log(`${socket.id} has joined the ${namespace.endpoint}`)
socket.emit('nsRooms', {data: namespace.rooms})
// Join room
socket.on('joinRoom', async (payload, cb) => {
const room = Array.from(socket.rooms)[1]
room && socket.leave(room)
socket.join(payload.data.roomName)
const numOfMem = await io.of(payload.data.nsp).in(payload.data.roomName).allSockets()
cb(Array.from(numOfMem).length)
})
socket.on('sendMessage', payload => {
const room = Array.from(socket.rooms)[1]
const nsp = socket.nsp.name
io.of(nsp).to(room).emit('updateMessage', payload)
})
})
})
client side \
Here is when i join rooms and send messages
function joinRoom(roomName) {
form.removeEventListener('submit', e => submitMsg(e))
nsSocket.emit('joinRoom', {data: {nsp: nsSocket.nsp, roomName}}, numberOfMember => {
document.getElementById('current-room').innerHTML = `<span class="curr-room-text">${roomName}</span> <span class="curr-room-num-users">Users: ${numberOfMember}<span class="glyphicon glyphicon-user"></span></span>`
})
messages.innerHTML = ''
nsSocket.on('updateMessage', payload => {
messages.innerHTML +=
`
<li>
<div class="user-image">
<img src="https://via.placeholder.com/30" />
</div>
<div class="user-message">
<div class="user-name-time">rbunch <span>${new Date(Date.now()).toDateString()}</span></div>
<div class="message-text">${payload.data}</div>
</div>
</li>
`
})
}
form.addEventListener('submit', e => submitMsg(e))
function submitMsg(e) {
e.preventDefault()
const msg = userMessage.value
msg.length > 0 && nsSocket.emit('sendMessage', {data: msg})
userMessage.value = ''
}
This happens because removeEventListener needs to work with the exact same function reference that was registered, and (e) => submitMsg(e) creates a new lambda all the time. Which means that each time you join a room, a new event handler will be added, without removing the old one.
I created a quick sample app here with the following code that would fix your issue. If you click 'Join some room' three times and then click 'Send message', only one console.log will appear (expand the console on the right hand side to see the result).
const testBtn = document.getElementById('joinRoom');
const form = document.getElementById('chatForm');
testBtn.addEventListener('click', () => {
form.removeEventListener('submit', submitMsg);
// ... some other code
form.addEventListener('submit', submitMsg);
});
submitMsg = (e) => {
e.preventDefault();
console.log('submitMsg() called!');
return false;
}
I am pulling data with fetch api. but I could not retrieve the data in the todosApi section of the last data I pulled. how can i pull data?
const usersApi = () =>{
fetch("https://jsonplaceholder.typicode.com/users").
then(response=>response.json()).
then(girilenVeri).
catch(e=>console.log(e));
}
const todosApi = (element) =>{
fetch(`https://jsonplaceholder.typicode.com/todos/?userId=${element.id}`).
then(response=>veriOlusturucu(response.json(), element)).//I can't get the data in response.json
catch(e=>console.log(e));
}
const girilenVeri = (data) => {
let cumle = [];
document.getElementById('arama').addEventListener('keydown',function(e){
if(e.keyCode == 8){
cumle.pop();
veriEslestir(data, cumle);
}
});
document.getElementById('arama').addEventListener('keypress',function(e){
cumle.push(String.fromCharCode(e.keyCode));
veriEslestir(data, cumle);
});
}
const veriEslestir = (data,cumle) =>{
veri = cumle.toString().replace(/,/g,"");
data.forEach(element => {
if(element.username.toLowerCase() == veri.toLowerCase()){
todosApi(element);
}
});
}
const veriOlusturucu = (todo,element) => {
console.log(todo);
console.log(element);
let html = "";
html =`
<h5 class="card-title">İletişim</h5>
<ul class="list-group">
<li class="list-group-item">Kullanıcı Adı: ${element.username}</li>
<li class="list-group-item">E-Mail: ${element.email}</li>
<li class="list-group-item">Web Site: ${element.website}</li>
<li class="list-group-item">Şirket: ${element.company.name}</li>
<li class="list-group-item">Telefon No: ${element.phone}</li>
<li class="list-group-item">Adres: ${element.address.street} ${element.address.suite} ${element.address.city} ${element.address.zipcode}</li>
</ul>
<h5 class="card-title">Yapılacaklar Listesi</h5>
<ul class="list-group">
`;
todo.forEach(element=>{//I need to access the data here with loop
html+=`
<li class="list-group-item">Kullanıcı Adı: ${element.title}</li>
`;
});
html +=`</ul>`;
document.getElementById('veriListele').innerHTML=html;
}
document.addEventListener('DOMContentLoaded',usersApi());
How do I return the "response.json" part with a foreach?
There is no problem with user information. but there is a problem with todo information. sends it to me as a promise. I can't access the promise result
If I can get into the "PromiseResult" the problem will be solved. but i can't reach
You're not quite using the fetch api correctly with the todo list. If you notice, on your userApi method, you include an extra .then which is necessary to return the json data rather than the promise:
const usersApi = () =>{
fetch("https://jsonplaceholder.typicode.com/users").
then(response=>response.json()).
then(girilenVeri).
catch(e=>console.log(e));
}
const todosApi = (element) =>{
fetch(`https://jsonplaceholder.typicode.com/todos/?userId=${element.id}`)
.then(response=>response.json())
.then(data => veriOlusturucu(data, element))
catch(e=>console.log(e));
}
Try this out.
Now I save information on the SessionStorage and then I try to show it in my view, the problem is when I try to show it on the view, it seems like the rendering of the HTML is faster due to the saving on the storage its made by an asynchronous call, I know it's difficult to understand and that's why I will explain my code right below
Here you will see my ngOnInit that will call first the function getIfPersonWasAlreadyScanned that is the one who makes the asynchronous call, after that on this.specificParticipant I will save the data that was set to the sessionStorage and that is the one that will be show in the view
ngOnInit(): void {
this.user = JSON.parse(localStorage.getItem('userLogged'));
this.userSettings = JSON.parse(localStorage.getItem('userSettings'));
this.sub = this.route.params.subscribe(params => {
this.id = +params['id']; // (+) converts string 'id' to a number
this.getIfPersonWasAlreadyScanned(this.user.clientId,this.user.projectId,this.id);
this.specificParticipant = JSON.parse(sessionStorage.getItem('AllScanned'));
this.getParticipant(this.id);
});
}
This function is the one that set the data to the sessionStorage
getIfPersonWasAlreadyScanned(clientId,projectId,personId){
this.loadCompleted = false;
this.deviceService.getIfPersonWasAlreadyScanned(clientId,projectId,personId)
.subscribe(
res => {
this.participantScans = res;
sessionStorage.setItem('AllScanned', JSON.stringify(this.participantScans));
},
err => {
console.log(err);
}
);
}
This is the code inside of my HTML as you can see I use an ngFor for iterate inside of the array that is on the specificParticipant variable, the problem is when I display this HTML the information its already on the sessionStorage but not here I have to refresh the page to actually see it on the HTML, how can I solve this?
<ng-container *ngFor="let participant of specificParticipant">
<mat-card class="width-75 mb-20 mr-20 ml-20">
<mat-card-content class="width-75" fxLayout="column" fxLayoutAlign="center center">
<th class="w-320 shocklogic-font text-dark text-center">Delegate Scans</th>
<div fxLayout="column">
<mat-card-header>
<mat-card-title class="participants-card-title">
</mat-card-title>
<mat-card-subtitle class="participants-card-subtitle"><strong>Last Scanned:</strong>{{participant.Last_Scanned}}</mat-card-subtitle>
<mat-card-subtitle class="participants-card-subtitle"><strong>Scan Result:</strong>{{participant.Scan_Result}}</mat-card-subtitle>
<mat-card-subtitle class="participants-card-subtitle"><strong>Device Name:</strong>{{participant.Device_Name}}</mat-card-subtitle>
<mat-card-subtitle class="participants-card-subtitle"><strong>Activity Name:</strong>{{participant.Activity_Name}}</mat-card-subtitle>
</mat-card-header>
<div fxLayout="row" fxLayoutAlign="center center">
<button class="force-btn" (click)="deleteParticipantScan(participant.DeviceScan_Id)" mat-stroked-button>Delete</button>
</div>
</div>
</mat-card-content>
</mat-card>
</ng-container>
The issue is occurring because
this.specificParticipant = JSON.parse(sessionStorage.getItem('AllScanned'));
is getting called prior to the conclusion of
this.deviceService.getIfPersonWasAlreadyScanned(clientId,projectId,personId)
within getIfPersonWasAlreadyScanned().
You need to return an observable from getIfPersonWasAlreadyScanned() and subscribe to that.
this.getIfPersonWasAlreadyScanned(this.user.clientId,this.user.projectId,this.id).subscribe(() => {
// we now know that AllScanned has been successfully update.
this.specificParticipant = JSON.parse(sessionStorage.getItem('AllScanned'));
});
Pass a callback function to getIfPersonWasAlreadyScanned. Once the async process ends, initiate the callback.
ngOnInit(): void {
var self = this;
this.loading = true; // use this variable to show a loading screen
this.getIfPersonWasAlreadyScanned(this.user.clientId, this.user.projectId, this.id, function(){
self.specificParticipant = JSON.parse(sessionStorage.getItem('AllScanned'));
self.getParticipant(self.id);
self.loading = false;
});
}
getIfPersonWasAlreadyScanned(clientId,projectId,personId){
this.loadCompleted = false;
this.deviceService.getIfPersonWasAlreadyScanned(clientId, projectId, personId, cb)
.subscribe(
res => {
this.participantScans = res;
sessionStorage.setItem('AllScanned',
JSON.stringify(this.participantScans));
cb();
},
err => {
console.log(err);
cb();
}
);
}
I want to make a real-time count of the total function of the javascript that all user can see when he visit my site.
For example, there are 3 visitors now I want to total how many successful Javascript executed they do that the count don't reset when the page refresh and are all visible to all user who visit.
html:
<div class="row">
<div class="col">
<div class="card-profile-stats d-flex justify-content-center mt-md-5">
<div>
<span class="heading" id="count1">0</span>
<span class="badge badge-success">Count 1</span>
</div>
<div>
<span class="heading" id="count2">0</span>
<span class="badge badge-danger">Count 2</span>
</div>
<div>
<span class="heading" id="count3">0</span>
<span class="badge badge-info">Count 3</span>
</div>
<div>
<span class="heading" id="all">0</span>
<span class="badge badge-info">Total</span>
</div>
</div>
</div>
</div>
js:
function startfunc() {
var xs = 0;
var cb = 0;
var fp = 0;
$.ajax({
url: 'urlhere.php',
type: 'GET',
async: true,
success: //some of my code here
var total = parseInt(xs) + parseInt(cb) + parseInt(fp);
$('#count1').html(xs);
$('#count2').html(cb);
$('#count3').html(fp);
$('#all').html(total);
Assuming that you have a database that is storing the values (this would be the only way to store the total values) then you would create an interval timer that would perform the http request to get the results on frequency that is not too often.
The example I'm giving is in pure JavaScript, so it should work. You don't need jQuery for this.
Promise Method:
File: script.js
// Code to execute when window loaded
window.addEventListener('load', () => {
// Main function to retrieve results
const getResults = () => {
fetch('/url/to/getResults.php')
.then(response => {
const json = response.json();
if (response.ok) {
return json;
}
return json.then(data => Promise.reject(data));
})
.then(jsonData => {
const total = parseInt(jsonData.xs) + parseInt(jsonData.cb) + parseInt(jsonData.fp);
document.querySelector('#count1').innerHTML = jsonData.xs;
document.querySelector('#count2').innerHTML = jsonData.cb;
document.querySelector('#count3').innerHTML = jsonData.fp;
document.querySelector('#total').innerHTML = total;
})
.catch(error => {
console.log('ERROR', error);
});
};
// Get an update results every 60 seconds
const interval = setInterval(getResults, 60000);
});
Async/Await Method:
window.addEventListener('load', () => {
// Main function to retrieve results
const getResults = async () => {
try {
const response = await fetch('/url/to/getResults.php');
const responseJSON = await response.json();
const total = parseInt(jsonData.xs) + parseInt(jsonData.cb) + parseInt(jsonData.fp);
document.querySelector('#count1').innerHTML = jsonData.xs;
document.querySelector('#count2').innerHTML = jsonData.cb;
document.querySelector('#count3').innerHTML = jsonData.fp;
document.querySelector('#total').innerHTML = total;
} catch (error) {
console.log('ERROR', error);
}
};
// Get an update results every 60 seconds
const interval = setInterval(await getResults, 60000);
});