everyone. Hope everyone is safe. I have a question.
I'm building this email-like application with javascript as a project for CS50 Web.
Everything is working smoothly, but I have this "archive" button that should update the database, return to the "inbox" page and show the emails that are unarchived, and hide it otherwise.
However, after I click this archive button, it updates the database, returns to the inbox but it doesn't update the page. Once I refresh, it works.
I have a feeling this error has something to do with the fetch methods.
Can someone help me?
Any advice on how to improve my code would be highly appreciated as well.
function load_mailbox(mailbox) {
// Show the mailbox and hide other views
document.querySelector('#emails-view').style.display = 'flex';
document.querySelector('#compose-view').style.display = 'none';
document.querySelector('#emails-page').style.display = 'none';
document.querySelector('#emails-page').innerHTML = '';
// Show the mailbox name
document.querySelector('#emails-view').innerHTML = `<h3>${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`;
// Fetch all emails
fetch('/emails/' + mailbox)
.then(response => response.json())
.then(emails => {
// Loop through all emails
emails.forEach(email => {
// Create elements and set the html content
const sender = document.createElement('p');
sender.innerHTML = `<strong>From:</strong> ${email.sender}`;
const subject = document.createElement('p');
subject.innerHTML = `<strong>Subject:</strong> ${email.subject}`;
const timestamp = document.createElement('p');
timestamp.innerHTML = email.timestamp;
const body = document.createElement('p');
body.innerHTML = email.body;
const recipient = document.createElement('p');
recipient.innerHTML = `<strong>To:</strong> ${email.recipients}`;
// Create archive button
const archive = document.createElement('button');
archive.className = "btn btn-light"
// Check if email is arquived or not, set the inner html for the button and change status if clicked.
if (email.archived === true) {
archive.innerHTML = "Unarchive"
archive.addEventListener('click', function () {
fetch('/emails/' + email.id, {
method: 'PUT',
body: JSON.stringify(
{ archived: false })
})
load_mailbox('inbox')
});
}
else {
archive.innerHTML = "Archive"
archive.addEventListener('click', function () {
fetch('/emails/' + email.id, {
method: 'PUT',
body: JSON.stringify(
{ archived: true })
})
load_mailbox('inbox')
});
}
// Create main div to hold all elements in the DOM
const element = document.createElement('div');
element.className = "div_email_view";
// Append elements fetch function returned.
element.appendChild(sender);
element.appendChild(subject);
element.appendChild(timestamp);
// Redirect to email page if div is clicked
element.addEventListener('click', function () {
// Hide other divs and show email page one.
document.querySelector('#emails-view').style.display = 'none';
document.querySelector('#compose-view').style.display = 'none';
document.querySelector('#emails-page').style.display = 'flex';
// Create reply button
const reply = document.createElement('button');
reply.innerHTML = "Reply Email"
reply.className = "btn btn-light"
// If reply is clicked, redirect to form in order to compose another email
reply.addEventListener('click', function () {
compose_email();
// Hide other divs
document.querySelector('#emails-page').style.display = 'none';
// Pre-fill form inputs with original email content
document.querySelector('#compose-recipients').value = `${email.sender}`;
if (email.subject.includes("Re:")) {
document.querySelector('#compose-subject').value = `${email.subject}`;
}
else {
document.querySelector('#compose-subject').value = `Re: ${email.subject}`;
}
document.querySelector('#compose-body').placeholder = `On ${email.timestamp}, ${email.sender} wrote: ${email.body}`;
})
// Fetch email that was clicked and and display its content
fetch('/emails/' + email.id)
.then(response => response.json())
.then(() => {
// Append all info related to that email
email_page = document.querySelector("#emails-page")
email_page.appendChild(sender);
email_page.appendChild(recipient);
email_page.appendChild(subject);
email_page.appendChild(body);
email_page.appendChild(timestamp);
// Get user email who's logged in
let user = localStorage.getItem('user')
// Append archive and reply buttons
if (user !== email.sender) {
email_page.appendChild(archive);
}
email_page.appendChild(reply);
// Set the "read" property to true if user has clicked on it to open.
if (email.read === false) {
fetch('/emails/' + email.id, {
method: 'PUT',
body: JSON.stringify({
read: true
})
})
}
})
});
// Append elements to inbox page
document.querySelector('#emails-view').append(element);
if (email.read === false) {
element.style.background = "#FAFAFA";
}
else {
element.style.background = "#E6E6E6";
}
});
});
}
Related
I am making a fake tweet prediction app in which i want to connect my front end with my back end using fast api but I am getting an error 405 i am new to java script as a student and this is my first front end app so please guide me through it
this is the back end
class model_input(BaseModel):
tweet : str
#app.post("/predict")
def predict(input_parameter: model_input):
input_data = input_parameter.json()
dict_parameter = json.loads(input_data)
tweet = dict_parameter["tweet"]
encoded_input = tokenizer.encode_plus(tweet, add_special_tokens=True, return_attention_mask=True)
input_ids, attention_mask = encoded_input["input_ids"], encoded_input["attention_mask"]
input_tensor: Tensor = torch.tensor([input_ids])
attention_tensor = torch.tensor([attention_mask])
model.eval()
with torch.no_grad():
outputs = model(input_tensor, attention_mask=attention_tensor)
logits = outputs[0]
predictions = torch.softmax(logits, dim=1)
y
predicted_class = torch.argmax(predictions).item()
predicted_probability = predictions[0][predicted_class].item()
if predicted_class == 1:
response_text = 0
else:
response_text = 1
response_data = {"prediction": response_text, "probability": predicted_probability}
print(response_data)
return response_data
and this is the front end
<!DOCTYPE html>
<html>
<head>
<title>Text Classification</title>
</head>
<body>
<h1>Text Classification</h1>
<form>
<label for="input-text">Enter text to classify:</label>
<br>
<textarea id="input-text" rows="4" cols="50"></textarea>
<br>
<button id="submit-button">Classify</button>
</form>
<div id="results"></div>
<script>
const inputText = document.getElementById('input-text');
const submitButton = document.getElementById('submit-button');
// Add an event listener to the submit button
submitButton.addEventListener('click', function (event) {
event.preventDefault();
// Get the input text
const text = inputText.value;
// Send the text to the BERT-based model for classification
classifyText(text);
});
function classifyText(text) {
// Send a request to the server with the input text
fetch('http://127.0.0.1:8000/predict', {
method: 'POST',
body: JSON.stringify({ tweet: text }),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
// Get the results element
const results = document.getElementById('results');
// Clear any previous results
results.innerHTML = '';
// Display the results on the web page
if (data.prediction === 1) {
results.innerHTML = 'The text is Real';
}
else if (data.prediction === 0) {
results.innerHTML = 'The text is Fake';
}
else {
results.innerHTML = 'Error: Could not classify the text';
}
})
.catch(error => {
console.error(error);
results.innerHTML = 'Error: ' + error;
});
}
</script>
</body>
</html>
i tried to convert it to get method
I am creating a form that asks for email and password and validates it. If it has any error, it pops on the same line. Below is my javascript code for it. When I fill the form and hit submit, the values get reset. Moreover, I do not see anything in the console. I tried using a random code console.log('Hanee') to test my code but nothing gets generated in the console tab. Could anyone tell me what's the issue here?
Also, here's the link to my login form: http://www2.cs.uregina.ca/~hsb833/215a/login.html
document.getElementById("login-form").addEventListener("submit",validateLogin,false);
function validateLogin(event){
var elements = event.currentTarget;
var emailValue = elements[0].value;
var passValue = elements[1].value;
checkEmail(emailValue);
checkPass(passValue);
}
function checkEmail(emailValue){
var regex_email = /^[/w]+#[a-zA-Z]+?\.[a-zA-Z]{2,3}$/;
var index = emailValue.search(regex_email);
var errorEmail = document.getElementById("errorEmail");
var valid = true;
console.log('Hanee');
if(index != 0){
errorEmail.style.display = 'inline';
}
}
function checkPass(passValue){
var password = document.getElementById("password");
var regex_pass = /[\w]+\S/;
var index = passValue.search(regex_pass);
if(passValue.length < 6){
console.log('password is invalid. Minimum length is 6');
errorPassLen.style.display = 'inline';
}
if(index != 0){
console.log('password is invalid. Please make sure there is no spaces in between');
errorPassFormat.style.display = 'inline';
}
}
form is refreshed after being submitted by default. To prevent that, use event.preventDefault(); in your validateLogin
Here is an example of a form with a username and password, maybe it will suit you and you can customize it for your needs
async function tebeFxhr() {
let logfil = 1;
let sotebe= false;
let tes =(logt) => {
return /^[a-zA-Z0-9]+$/ui.test(logt);
}
tes(gtebe)==true ? logfil++ : alert('Login cannot contain characters or spaces')
let textrf =(rutext) => {
return /[а-я]/i.test(rutext);
}
textrf(stebe)==true ? alert('The password cannot contain Cyrillic characters') : logfil++;
stebe.length < 8 ? alert('Password is very short') : logfil++;
stebe===ftebe ? logfil++ : alert('Enter the password 2 times so that they match')
if (logfil === 5){
const data = {data_0:gtebe, data_1:stebe, data_2:ftebe};
const response = await fetch("/form", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then((response) => {
return response.text();
})
.then((sotebe) => {
console.log(sotebe)
if(sotebe==='error-1'){
console.log('error-1')
}
else{
sotebe =='' ? location.replace("../") : alert(sotebe)
}
});
}
}
When submit event is triggered, all values are sent to server and get reset. If you want to prevent this, use event.preventDefault(); inside the event handling function validateLogin(event). Then, the values are not going to be reset!
Still If you want your values to be empty after submission, try below.
elements.forEach(e => e.value = '');
I have a function that loads user information including followers and following,
From that function, I go to the 2nd function that loads a button
on clicking the button it goes to the 3rd function that changes the value in the backend.
After updating the value, how can I change the innerHTML of the divs in my first function that loads the user info?
The goal is to show the new value without refreshing the page.
The function that loads the user info.
function load_user_info(user_clicked_on){
document.querySelector('#page-view').style.display = 'none';
document.querySelector('#posts-view').style.display = 'none';
document.querySelector('#show-posts').style.display = 'none';
document.querySelector('#load-profile').style.display = 'block';
fetch(`/profile/${user_clicked_on}`)
.then(response => response.json())
.then(profile => {
const profile_element = document.createElement('div');
const followers = document.createElement('div');
const following = document.createElement('div');
followers.innerHTML = 'Followers: ' + profile.followers;
following.innerHTML = 'Following: ' + profile.following;
profile_element.appendChild(followers);
profile_element.appendChild(following);
profile_element.classList.add('profile_element');
insert_follow_btn(user_clicked_on) // insert follow or unfollow button.
document.querySelector('#user-profile').appendChild(profile_element);
});
document.querySelector('#user-profile').innerHTML = `<h3>${user_clicked_on.charAt(0).toUpperCase() + user_clicked_on.slice(1)} Profile</h3>`;
}
the function that inserts a button and then when clicking on the button it goes to the 3rd function that updates the value in the backend.
function insert_follow_btn(user_clicked_on){
// For any other user who is signed in show the follow button
current_logged_in_user = document.querySelector('#user_detail').value;
if(user_clicked_on != current_logged_in_user){
const profile_buttons = document.createElement('div');
const follow_button = document.createElement('button');
fetch(`/following/${user_clicked_on}`)
.then(response => response.json())
.then(data => {
result = data.result
if(result == true){
follow_button.innerHTML += 'UnFollow'
profile_buttons.appendChild(follow_button);
follow_button.addEventListener("click", () => {
if(follow_button.innerHTML === 'Follow'){
follow_button.innerHTML = 'UnFollow'
}else{
follow_button.innerHTML = 'Follow'
}
unfollow_user(user_clicked_on)
});
}else{
follow_button.innerHTML += 'Follow'
profile_buttons.appendChild(follow_button);
follow_button.addEventListener("click", () => {
if(follow_button.innerHTML === 'Follow'){
follow_button.innerHTML = 'UnFollow'
}else{
follow_button.innerHTML = 'Follow'
}
follow_user(user_clicked_on)
});
}
})
profile_buttons.classList.add('profile_buttons');
document.querySelector('#user-profile').appendChild(profile_buttons);
console.log('Current profile:'+user_clicked_on+' Current logged in user: '+ current_logged_in_user);
}else{
return ``;
}
}
the function that updates on the backend
function follow_user(user_clicked_on){
fetch(`/follow/${user_clicked_on}`, {
method: 'PUT',
body: JSON.stringify({
user_clicked_on: user_clicked_on
})
})
.then(response => response.json())
.then(result => {
// Print result
console.log(result.followers)
// How to update my followers.innerHTML in load_user_info function?
})
}
When you create the followers div inside load_user_info give it an id, like "followersdiv":
const followers = document.createElement('div');
followers.setAttribute("id", "followersdiv");
Then, inside the last function, follow_user, you can:
console.log(result.followers);
document.querySelector('#followersdiv').innerHTML='Followers: ' + result.followers;
Or
document.getElementById('followersdiv').innerHTML='Followers: ' + result.followers;
i have customer service application using in app browser call using nexmo and laravel as framework. I have some users and each users have their list phone numbers in table and each row has contact action button to call. The target of phone number is put in button like this :
Contact
but user can do inspect element and edit those button then put another phone numbers they want. How can i prevent this cheat and alert user in example "You have not authorize to call this phone number." when they do that action?
this my handler when .call-button is clicked:
dataTableAdminLeader.on('click', '.call-button', function(){
let id = $(this).data('id');
let master_number_id = $(this).data('master_numbers_id');
let target_number = $(this).data('number');
const trashButton = document.querySelector('.btn-trash');
const updateButton = document.querySelector(".btn-update");
trashButton.setAttribute('disabled', 'disabled');
updateButton.setAttribute('disabled', 'disabled');
$('#phone-call-modal').modal('show');
// input reset
document.querySelector('#target-phone').value = target_number;
document.querySelector('#id-edit').value = id;
document.querySelector('#master-numbers-id-edit').value = master_number_id;
document.querySelector('#member-id').value = $(this).data('id-member');
document.querySelector('#member-name').value = $(this).data('name');
trashButton.removeAttribute('disabled');
updateButton.removeAttribute('disabled');
// all constant needed for call
const USER_JWT = "{{ $jwt_token }}";
const phoneNumberInput = document.querySelector("#cs-phone");
const statusElement = document.querySelector("#status-call");
// button object selector
const callButton = document.querySelector(".btn-call");
callButton.setAttribute('disabled', 'disabled');
const hangupButton = document.querySelector(".btn-hangup");
const closeButton = document.querySelector('.btn-close');
closeButton.style.removeProperty('display');
const statusButton = document.querySelector('.btn-status');
// input object selector
let campaign_result = document.querySelector('#campaignresult');
let note_contacted = document.querySelector('#note_contacted');
let note_container = document.querySelector('.note_container');
let nameContainer = document.querySelector('.name-container');
let campaignContainer = document.querySelector('.campaign-container');
let waContainer = document.querySelector('.wa-container');
let inputCallStatus = document.querySelector('#call-status');
// call status check
let callStatusCompleted = false;
let callStatusAnswered = false;
// reset property
campaign_result.value = "";
note_container.style = 'display: none';
nameContainer.style = 'display: none';
// sound object
var sndAnswered = new Audio("{{ asset('storage/sounds/answered.wav') }}");
// listening to event
campaign_result.addEventListener('change', function(){
if(campaign_result.value != ''){
note_container.style.removeProperty('display');
note_contacted.setAttribute('required', 'required');
}else{
note_container.style = 'display: none';
note_contacted.removeAttribute('required');
}
});
// nexmo status reset
statusElement.innerText = '';
inputCallStatus.value = '';
// nexmo call button reset
callButton.style.display = "inline";
hangupButton.style.display = "none";
// timeouts set
setTimeout(() => {
callButton.removeAttribute('disabled');
}, 5000);
// nexmo object start
new NexmoClient({ debug: true }).login(USER_JWT).then(app => {
callButton.addEventListener("click", event => {
event.preventDefault();
let number = String(target_number);
console.log(number);
if (number !== ""){
app.callServer(number).catch(function(error){
console.log('debug: ',error);
});
} else {
statusElement.innerText = 'Please enter your phone number.';
}
});
app.on("member:call", (member, call) => {
// object selector reset
callButton.style.display = 'none';
closeButton.style.display = 'none';
hangupButton.style.removeProperty('display');
statusButton.style.removeProperty('display');
$('#wa-valid').removeAttr('checked');
// event when hangup button clicked
hangupButton.addEventListener("click", () => {
call.hangUp();
});
});
app.on("call:status:changed",(call) => {
console.log('Periodik : ', call.status);
// animation call
let statusAnimation = `<p class="saving">Call status: ${call.status}<span>.</span><span>.</span><span>.</span></p>`;
// assign call animation to nexmo status display
statusElement.innerHTML = statusAnimation;
// filter nexmo status condition
switch(call.status) {
case call.CALL_STATUS.STARTED:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.RINGING:
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.FAILED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
statusButton.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
nameContainer.style.removeProperty('display');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.CANCELLED:
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.removeProperty('display');
hangupButton.style.display = 'none';
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.COMPLETED:
callStatusCompleted = true;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
campaign_result.setAttribute('required', 'required');
nameContainer.style.removeProperty('display');
campaignContainer.style.removeProperty('display');
dataTableAdminLeader.ajax.reload();
console.log('Case call status: ', call.status);
break;
case call.CALL_STATUS.ANSWERED:
// play sound
sndAnswered.play();
inputCallStatus.value = call.status;
callStatusAnswered = true;
callButton.style.display = 'none';
hangupButton.style.removeProperty('display');
nameContainer.style.removeProperty('display');
closeButton.style.display = 'none';
statusButton.style.display = 'none';
console.log('Case call status: ', call.status);
break;
default:
// BUSY
// REJECTED
// TIMEOUT
// UNANSWERED
inputCallStatus.value = call.status;
callStatusAnswered = false;
callButton.style.display = 'none';
hangupButton.style.display = 'none';
updateButton.style.removeProperty('display');
trashButton.style.removeProperty('display');
statusButton.style.display = 'none';
nameContainer.style.removeProperty('display');
waContainer.style.removeProperty('display');
closeButton.style.removeProperty('dispaly');
console.log('Case call status: ', call.status);
console.log('Case call status default: ', call.status);
break;
}
});
}).catch(function(){
alert('Network Problem, refresh page and try again later. Please contact dev team if this problem not fix in few minutes.');
console.error;
$('#phone-call-modal').modal('hide');
});
});
There is no possible way for the Vonage (Nexmo) Voice API to validate whether your user should be able to call a phone number they have access to in your application. It sounds like you have provided users of your application the ability to initiate voice conversations with your Vonage API credentials. The validation logic for your users must rest in your application.
One solution you can consider is before initiating the new voice call, you can check against your database if the user has access or not. If they do not have access you can redirect them to another view in your application, and if they do have access you can initiate the call. Laravel has a entire suite of validation tooling that you may find helpful.
This is supposed to handle the form validation for a simple contact form with name, email address, website url, and 10 line comment section for project description, then hand the information as a JSON object to a php file to send to a designated email address.
When I had action="emailprocessor.php in the HTML code, the form validation went through the PHP file and not JS, and it sent properly to the designated email address.
Without the action in the html, it's supposed to flow through the JS and then to the PHP. It's not doing that.
Here is my code:
(function () {
"use strict";
const contactForm = document.getElementById('contactform');
contactForm.addEventListener('submit', validateForm);
//Messages to be put in the message element when there is an error or success...
// The last element in this array loads the preloader css.
const feedBackMessage = [
'<div class="error"><h3>Ooops!</h3><p>The name field is reqired, that\'s how I know who you are. Please fix that and try again!</p></div>',
'<div class="error"><h3>Ooops!</h3><p>You forgot to give me a valid email address. Please fix that and try again!</p></div>',
'<div class="error"><h3>Ooops!</h3><p>You forgot to enter your website. Please fix that and try again!</p></div>',
'<div class="error"><h3>Ooops!</h3><p>Please enter your project description or comment.</p></div>',
'<div class="success"><h3>Thank you!</h3><p>Your information has been sent, and we will be in touch.</p></div>',
'<div class="preloader"><div class="loading-dot"></div></div>'
];
// The actual form validation function. Added url regex.
function validateForm(event) {
event.preventDefault();
const nameField = document.getElementById('name');
const emailField = document.getElementById('email');
const siteField = document.getElementById('website');
const commentField = document.getElementById('comment');
const reName = /^[a-zA-Z]+(([\'\- ][a-zA-Z])?[a-zA-Z]*)*$/;
const reEmail = /^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)#([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$/;
const reUrl = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/;
let errors = 0;
if (!reName.test(nameField.value)) {
displayMessage(nameField, feedBackMessage[0]);
errors++;
}
else if (!reEmail.test(emailField.value)) {
displayMessage(emailField, feedBackMessage[1]);
errors++;
}
else if (!reUrl.test(siteField.value)) {
displayMessage(siteField, feedBackMessage[2]);
errors++;
}
else if (commentField.value == "") {
displayMessage(commentField, feedBackMessage[3]);
errors++;
}
else if (errors === 0) {
sendData();
}
}
// This displays error / success messages
function displayMessage(field, message) {
document.getElementById('message').className = "show-message";
document.getElementById('message').innerHTML = message;
setTimeout(function () {
document.getElementById('message').classList.add("fadeOutElement");
setTimeout(function () {
if (field != 'success') {
document.getElementById('message').className = "hide-message";
document.getElementById(field.id).focus();
}
else {
document.getElementById('message').setAttribute("class", "hide-message");
document.getElementById('name').value = '';
document.getElementById('email').value = '';
document.getElementById('website').value = '';
document.getElementById('comment').value = '';
}
}, 2000);
}, 2000);
//puts messages in the DOM??
}
function sendData() {
document.getElementById('message').className = "show-message";
document.getElementById('message').innerHTML = feedBackMessage[5];
setTimeout(async () => {
const formdata = new FormData(contactForm);
const fetchPromise = await fetch('emailprocessor.php', { method: 'POST', body: formdata });
const data = await fetchPromise.json();
console.log(data.result);
if (data.result == "success") {
displayMessage('success', feedBackMessage[4]);
}
}, 2000);
}
//actually sends the data asynchronously or so it claims
});