I have created a SPA Translator App using the Yandex API. I have just finished the logic and the functionality to my app, I am stuck though on how to remove the trailing letter in my output text-area when a user removes all the text from the input text-area.
How would one write a function to clear the output text-area back to ('') blank string after the user has removed all the input text. A link to my live site is here (https://translex-app-shanemuir.c9users.io/dist/index.html).
Here I have a HTML form:
<div class="container myForm text-center">
<div class="row row-center">
<div class="col-sm-12">
<form class="form-inline well justify-content-center">
<textarea id="inputText" class="form-control" placeholder="Enter a Word..."></textarea>
<select class="form-control" id="selectLang">
<option selected>Choose Language...</option>
</select>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h2 class="translation-header">Translation</h2>
<form class="form-inline well justify-content-center">
<textarea readonly class="form-control" placeholder="Translation" id="translation"></textarea>
</form>
</div>
</div>
</div>
Here I have some JS:
let searchInput = document.querySelector('#inputText');
let select = document.querySelector('#selectLang');
let textArea = document.querySelector('#translation');
let selectedLang = 'es';
function getLanguages(){
axios.get('https://translate.yandex.net/api/v1.5/tr.json/getLangs?key=trnsl.1.1.20180914T205319Z.b0ffef87e97badd3.e78787ec8a392b9772f8b8f56933b1d86463d330&ui=en')
.then((response) => {
let languages = response.data.langs;
let languageCode = {
name:'',
code:''
};
for(language in languages) {
languageCode.name = languages[language];
languageCode.code = language;
let option = document.createElement('option');
option.innerHTML = languageCode.name;
option.value = languageCode.code;
select.appendChild(option);
}
})
.catch((err) => {
console.log(err);
});
}
function translateText(textArg){
let searchText;
if(textArg == ''){
searchText = document.querySelector('#inputText').value;
}
else{
searchText = textArg;
}
if(searchText != ''){
axios.get('https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20180914T205319Z.b0ffef87e97badd3.e78787ec8a392b9772f8b8f56933b1d86463d330&lang=' + selectedLang + '&text=' + searchText)
.then((response) => {
let translateInput = document.querySelector('#translation');
translateInput.value = response.data.text[0];
})
.catch((err) => {
console.log(err);
});
}
}
searchInput.addEventListener('keyup',() => {
translateText('');
});
select.addEventListener('change',() => {
selectedLang = select.options[select.selectedIndex].value;
translateText('');
});
getLanguages();
Add an else clause to the if, to empty the textarea.
if(searchText != ''){
axios.get('https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20180914T205319Z.b0ffef87e97badd3.e78787ec8a392b9772f8b8f56933b1d86463d330&lang=' + selectedLang + '&text=' + searchText)
.then((response) => {
let translateInput = document.querySelector('#translation');
translateInput.value = response.data.text[0];
})
.catch((err) => {
console.log(err);
});
} else {
document.querySelector('#translation').value = '';
}
Related
I put a snippet to make the idea better.
Type any character in the Find field, in the console you will see the log of the dataAdd object, if now we change the value of the select Department and type any character again, the log becomes double, with the value of Department previous and current one, and if you repeat this, each time you add the value in the log.
I need the passed value to send it on the server side to filter the search by department but this way it can't work.
Can you help me, I'm going crazy
const $ = id => document.getElementById(id);
let ajaxInProgress = false;
const ajaxGet = async (elab, q, dataAdd) => {
if (ajaxInProgress) return;
ajaxInProgress = true;
let url;
if (dataAdd != null) {
url = "/utility/cerca/getLiveSearch/" + elab + "/" + q + "/" + btoa(JSON.stringify(dataAdd));
} else {
url = "/utility/cerca/getLiveSearch/" + elab + "/" + q;
}
let response = await fetch(url),
data = await response.text();
if (response.ok) {
ajaxInProgress = false;
return data;
} else if (response.status === 404) {
ajaxInProgress = false;
return false;
} else {
ajaxInProgress = false;
return "Error: " + response.status;
}
};
const liveSearch = (id, elCont, elab, dataAdd) => {
const el = document.querySelector("input" + id);
// If I can't find the execution block element
if (!el) return !1;
el.classList.add("liveSearch");
el.parentElement.classList.add("position-relative");
el.setAttribute("autocomplete", "off");
// If the item doesn't already exist, I create it
if (!$(elCont)) {
// Appendo elemento al campo input
let lsContainer = document.createElement("div");
lsContainer.id = elCont;
lsContainer.classList.add("liveSearchContent", "shadow", "bg-white", "border", "border-2", "rounded-2", "position-absolute", "overflow-auto", "mt-1", "d-none");
el.after(lsContainer);
}
// To KeyUp
el.addEventListener("keyup", ls => {
// I get the typed value
let q = el.value,
innerResult = document.querySelector("#" + elCont);
if (q != "") {
// Log data send from input field
console.log(dataAdd);
ajaxGet(elab, q, dataAdd).then(html => {
// Resize liveSearch
resizeLiveSearch();
// I hang the results
innerResult.innerHTML = html + ' - ' + q;
// Hide/Show liveSearch
ls.target.value.length < 1 ? innerResult.classList.add("d-none") : innerResult.classList.remove("d-none");
});
} else {
// Hide/Show liveSearch
ls.target.value.length < 1 ? innerResult.classList.add("d-none") : innerResult.classList.remove("d-none");
}
});
el.addEventListener("focus", el => {
el.target.closest("div").querySelector(".liveSearchContent").classList.remove("d-none");
});
// When I resize the window, I resize the livesearch
window.onresize = resizeLiveSearch;
document.addEventListener("click", e => {
let box = document.querySelector(".liveSearchContent");
if (box) {
if (box.contains(e.target) || !e.target.classList.contains("liveSearch")) {
handleBlur();
} else {
return false;
}
}
});
};
let resizeLiveSearch = () => {
document.querySelectorAll(".liveSearch").forEach(e => {
e.closest("div").querySelector(".liveSearchContent").style.width = e.offsetWidth + "px";
});
};
let handleBlur = () => {
document.querySelectorAll(".liveSearchContent").forEach(el => {
el.classList.add("d-none");
});
};
// -- Piece of code that interacts with liveSearch
document.addEventListener("DOMContentLoaded", () => {
let idReparto = $("id_reparto"),
idEvento = $("id_evento"),
evento = $("evento"),
reparto = idReparto.value;
idReparto.addEventListener("change", el => {
console.clear();
idEvento.value = evento.value = "";
reparto = el.target.value;
liveSearch("#evento", "searchEventoRicerca", "evento_reparto", { reparto: reparto });
});
liveSearch("#evento", "searchEventoRicerca", "evento_reparto", { reparto: $("id_reparto").value });
$("searchEventoRicerca").addEventListener("click", el => {
let elt = el.target,
evento2 = "";
if (elt.matches(".srel")) {
evento2 = elt.getAttribute("id");
el.preventDefault();
elt.blur();
evento.value = elt.text;
idEvento.value = evento2;
pdvEvento.value = idPdv.value = "";
// Mostro pdv_evento e occulto pdv
pdvEvento.parentElement.classList.remove("d-none");
console.log(evento2);
}
});
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"/>
<form class="mb-5 mt-2 mx-2">
<div class="row g-3">
<input type="hidden" id="id_evento" name="id_evento" value="">
<div class="col-md-3">
<label for="id_reparto" class="form-label">Department</label>
<select class="form-select" id="id_reparto" name="id_reparto" title="id_reparto">
<option value="1">Dep 1</option>
<option value="3">Dep 3</option>
<option value="2" selected="selected">Dep 2</option>
</select>
</div>
<div class="col-md-6">
<label for="evento" class="form-label">Find</label>
<input type="text" class="form-control liveSearch" placeholder="Type any character" id="evento" name="evento" value="" autocomplete="off">
<div id="searchEventoRicerca" class="liveSearchContent shadow bg-white border border-2 rounded-2 position-absolute overflow-auto mt-1 d-none"></div>
</div>
</div>
</form>
I have a firebase database and I want to get all the chats and add an HTML element to all of them. Each div has a password input and a button. I made a forEach() loop but it only makes an event listener for the last one. I'm not very experienced so it is probably a simple problem. This is my code:
get(ref(db, "chats")).then((snapshot)=>{
snapshot.forEach((child)=>{
var html = "";
var childName = child.val().chatname;
var childPassword = child.val().chatpassword;
console.log(childName);
html += `
<li>
<div class="chat-login-container">
<h3>`+childName+`</h3>
<input id="`+childName+`-input" type="password" placeholder="Enter Chat Password">
<button id="`+childName+`-button" class="login">Enter</button>
</div>
</li>
`;
messages.innerHTML += html;
var button = document.getElementById(childName+"-button");
var passwordInput = document.getElementById(childName+"-input");
button.addEventListener("click", ()=>{
get(ref(db, "chats/"+childName)).then((snapshot) =>{
if(passwordInput==childPassword){
chat = childName;
console.log("Logging in to "+childName);
messages.innerHTML = "";
start();
}else{
window.alert("Incorrect password, please try again");
}
}).catch((error)=>{
console.log(error);
});
});
});
}).catch((error)=>{
console.log(error);
});
Because, you are capturing the button by ID. It will capture the last ID recorded.
Instead use querySelector.
Try below, which is not a proper code, you need to tweak based on error messages.
get(ref(db, "chats")).then((snapshot) => {
snapshot.forEach((child) => {
var html = "";
var childName = child.val().chatname;
var childPassword = child.val().chatpassword;
console.log(childName);
html += `
<li>
<div class="chat-login-container">
<h3>`+ childName + `</h3>
<input type="hidden" class="childname" value="`+ childname + `">
<input type="hidden" class="childPassword" value="`+ childPassword + `">
<input id="`+ childName + `-input" class="password" type="password" placeholder="Enter Chat Password">
<button id="`+ childName + `-button" class="login">Enter</button>
</div>
</li>
`;
messages.innerHTML += html;
});
const chatLoginContainers = document.querySelectorAll('.chat-login-container');
chatLoginContainers.forEach((element) => {
const loginBtn = element.querySelector('.login');
loginBtn.addEventListener('click', (event) => {
const childNameEle = event.target.closest('li').querySelector('.childname');
const childPasswordEle = event.target.closest('li').querySelector('.childPassword');
const passwordEle = event.target.closest('li').querySelector('.password');
const childNameVal = childNameEle.value;
const childPasswordVal = childPasswordEle.value;
const passwordVal = passwordEle.value;
get(ref(db, "chats/" + childNameVal)).then((snapshot) => {
if (passwordVal == childPasswordVal) {
chat = childNameVal;
console.log("Logging in to " + childNameVal);
messages.innerHTML = "";
start();
} else {
window.alert("Incorrect password, please try again");
}
}).catch((error) => {
console.log(error);
});
})
});
}).catch((error) => {
console.log(error);
});
I created function where I block all my inputs( I did it with for of loop). Now I would like to add condition if button checked unblock, if not checked block.
I wrote following code:
<div class="container">
<input type="number" class="block">
<input type="text" class="block">
<input type="email" class="block">
<input type="checkbox" id="scale1" name="scales">
<label for="scales">Scales</label>
</div>
function blockFileds() {
let inputsForm = document.getElementsByClassName('block');
let checker = document.getElementById('scale1');
for (const singleField of inputsForm) {
if (checker.checked) {
singleField.disabled = false;
} else {
singleField.disabled = true;
}
}
}
blockFileds()
input are blocked, but I cant' unblock it.
Remove the elements from the function,
And attach addEventListener to the input
let inputsForm = document.getElementsByClassName('block');
let checker = document.getElementById('scale1');
function blockFileds() {
for (let singleField of inputsForm) {
if (checker.checked) {
singleField.disabled = false;
} else {
singleField.disabled = true;
}
}
}
blockFileds()
checker.addEventListener("click", (e)=>{
blockFileds()
})
this way...
const
inputsForm = document.querySelectorAll('input.block')
, checker = document.querySelector('#scale1')
;
blockFileds()
checker.onclick = blockFileds
function blockFileds()
{
inputsForm.forEach( singleField =>
{
singleField.disabled = !checker.checked
})
}
.block, label {
display : block;
margin : .3em 0;
}
<div class="container">
<input type="number" class="block">
<input type="text" class="block">
<input type="email" class="block">
<label>
<input type="checkbox" id="scale1" name="scales">
Scales
</label>
</div>
you can try this:
const inputsForm = document.getElementsByClassName("block");
const checker = document.getElementById("scale1");
function blockFileds() {
for (let singleField of inputsForm) {
if (!checker.checked) {
singleField.disabled = "";
} else {
singleField.disabled = true;
}
}
}
checker.onclick = () => {
blockFileds();
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<h1 class="heading">Book Search</h1>
<input placeholder="Type Book name" class="searchBar" id="searchInput" type="search">
<br>
<select id="selectDisplayCount" class="options">
<option selected value="10">10 Books</option>
<option value="20">20 Books</option>
<option value="30">30 Books</option>
</select>
</div>
<div id="searchResults">
<div class="col-12 d-none mt-5" id="spinner">
<div class="d-flex flex-row justify-content-center">
<div class="spinner-border" role="status"></div>
</div>
</div>
</div>
</body>
</html>
let searchInputEl = document.getElementById("searchInput");
let spinnerEl = document.getElementById("spinner");
let searchresultsEl = document.getElementById("searchResults")
let selectDisplayCountEl = document.getElementById("selectDisplayCount");
let bookcount = selectDisplayCountEl.value;
let formData = {
count: "10 Books",
}
function createAndAppendSearchResult(result) {
let {
title,
imageLink,
author
} = result;
let resultItemEl = document.createElement("div");
resultItemEl.classList.add("country-card", "col-6", "mr-auto", "ml-auto", "d-flex", "flex-column")
searchresultsEl.appendChild(resultItemEl);
let imageEl = document.createElement("img");
imageEl.classList.add("image", "mt-auto", "mb-auto")
imageEl.src = imageLink;
resultItemEl.appendChild(imageEl);
let authorEl = document.createElement("p");
authorEl.classList.add("author-name")
authorEl.textContent = author;
resultItemEl.appendChild(authorEl);
}
function displaySearchResults(searchresult) {
for (let result of searchresult) {
let titleName = result.title
if (titleName.includes(searchInputEl.value)) {
createAndAppendSearchResult(result);
} else {
searchInputEl.textontent = "No reuslts found";
}
}
}
function searchBook(event) {
if (event.key === "Enter") {
let url = "https://apis.ccbp.in/book-store?title=kalam&maxResults=30" + searchInput;
let options = {
method: "GET"
}
spinnerEl.classList.remove("d-none");
searchresultsEl.classList.add("d-none");
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
searchresultsEl.classList.remove("d-none");
spinnerEl.classList.add("d-none");
console.log(jsonData)
let {
search_results
} = jsonData;
console.log(JSON.stringify(jsonData))
displaySearchResults(search_results);
})
}
}
selectDisplayCountEl.addEventListener("change", function(event) {
formData.count = event.target.value;
console.log(formData.count)
});
searchInputEl.addEventListener("keydown", searchBook);
errors I am getting
When a value is entered in the HTML input element with id searchInput, x books option is selected in the HTML select element with id selectDisplayCount, an HTTP GET request with a valid url parameters title and maxResults should be made
When a value is entered in the HTML input element with id searchInput, x books option is selected in the HTML select element with id selectDisplayCount, an HTTP GET request should be made to fetch and display x book items
how exactly it should work is:
https://assets.ccbp.in/frontend/content/dynamic-webapps/book_search_output.gif
let searchInputEl = document.getElementById("searchInput");
let spinnerEl = document.getElementById("spinner");
let searchresultsEl = document.getElementById("searchResults")
let selectDisplayCountEl = document.getElementById("selectDisplayCount");
let bookcount = selectDisplayCountEl.value;
let formData = {
count: "10 Books",
}
function createAndAppendSearchResult(result) {
let {
title,
imageLink,
author
} = result;
let resultItemEl = document.createElement("div");
resultItemEl.classList.add("country-card", "col-6", "mr-auto", "ml-auto", "d-flex", "flex-column")
searchresultsEl.appendChild(resultItemEl);
let imageEl = document.createElement("img");
imageEl.classList.add("image", "mt-auto", "mb-auto")
imageEl.src = imageLink;
resultItemEl.appendChild(imageEl);
let authorEl = document.createElement("p");
authorEl.classList.add("author-name")
authorEl.textContent = author;
resultItemEl.appendChild(authorEl);
}
function displaySearchResults(searchresult) {
for (let result of searchresult) {
let titleName = result.title
if (titleName.includes(searchInputEl.value)) {
createAndAppendSearchResult(result);
} else {
searchInputEl.textontent = "No reuslts found";
}
}
}
function searchBook(event) {
if (event.key === "Enter") {
let url = "https://apis.ccbp.in/book-store?title=kalam&maxResults=30" + searchInput;
let options = {
method: "GET"
}
spinnerEl.classList.remove("d-none");
searchresultsEl.classList.add("d-none");
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(jsonData) {
searchresultsEl.classList.remove("d-none");
spinnerEl.classList.add("d-none");
console.log(jsonData)
let {
search_results
} = jsonData;
console.log(JSON.stringify(jsonData))
displaySearchResults(search_results);
})
}
}
selectDisplayCountEl.addEventListener("change", function(event) {
formData.count = event.target.value;
console.log(formData.count)
});
searchInputEl.addEventListener("keydown", searchBook);
<link rel='stylesheet' href='//stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css' integrity='sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z' crossorigin='anonymous' />
<script src='//code.jquery.com/jquery-3.5.1.slim.min.js' integrity='sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj' crossorigin='anonymous'></script>
<script src='//cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js' integrity='sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN' crossorigin='anonymous'></script>
<script src='//stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js' integrity='sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV' crossorigin='anonymous'></script>
<div class='container'>
<h1 class='heading'>Book Search</h1>
<input placeholder='Type Book name' class='searchBar' id='searchInput' type='search'>
<br>
<select id='selectDisplayCount' class='options'>
<option selected value='10'>10 Books</option>
<option value='20'>20 Books</option>
<option value='30'>30 Books</option>
</select>
</div>
<div id='searchResults'>
<div class='col-12 d-none mt-5' id='spinner'>
<div class='d-flex flex-row justify-content-center'>
<div class='spinner-border' role='status'></div>
</div>
</div>
</div>
According to the animated GIF the select menu ought to also trigger the AJAX request to the 3rd party api however according to your code it simply updates the global variableformData. As both the select and the keydown/enter are to trigger the same actions a single event handler can be used. With a little re-writing of the above and some new functions one can simplify the code to accomplish what you are trying (I think) to do.
The following code snippet omits the various external scripts and stylesheets used in the original but will serve to illustrate the result.
document.addEventListener('DOMContentLoaded',()=>{
let oRes=document.getElementById('searchResults');
let oText=document.getElementById('searchInput');
let oSel=document.getElementById('selectDisplayCount');
let oSpin=document.getElementById('spinner');
const baseurl='https://apis.ccbp.in/book-store';
// utility to ease construction of full urls in modern browsers
const buildurl=function( endpoint, params ){
let url=new URL( endpoint );
url.search = new URLSearchParams( params ).toString();
return url;
};
// utility method to create new DOM elements
// where t=node type, a=attributes & p=parent to append to.
const create=function(t,a,p){
let el = ( typeof( t )=='undefined' || t==null ) ? document.createElement( 'div' ) : document.createElement( t );
let _arr=['innerHTML','innerText','html','text'];
for( let x in a ) if( a.hasOwnProperty( x ) && !~_arr.indexOf( x ) ) el.setAttribute( x, a[ x ] );
if( a.hasOwnProperty('innerHTML') || a.hasOwnProperty('html') ) el.innerHTML=a.innerHTML || a.html;
if( a.hasOwnProperty('innerText') || a.hasOwnProperty('text') ) el.innerText=a.innerText || a.text;
if( p!=null ) typeof( p )=='object' ? p.appendChild( el ) : document.getElementById( p ).appendChild( el );
return el;
};
// The callback method to generate output HTML
const callback=(json)=>{
toggleclasses(false);
let data=json.search_results;
oRes.innerHTML='';
Object.keys( data ).forEach( k => {
let obj=data[ k ];
let div=create(null,{'class':'country-card col-6 mr-auto ml-auto d-flex flex-column'},oRes);
create('h1',{text:obj.title},div);
create('img',{src:obj.imageLink,'class':'image mt-auto mb-auto'},div);
create('p',{text:obj.author,'class':'author-name'},div);
});
};
// helper to switch classes as per original
const toggleclasses=(b)=>{
switch(b){
case true:
oSpin.classList.remove('d-none');
oRes.classList.add('d-none');
break;
case false:
oSpin.classList.add('d-none');
oRes.classList.remove('d-none');
break;
}
};
// single event handler to send AJAX request
const requesthandler=(e)=>{
if( e.key === 'Enter' || e.type=='change' ) {
toggleclasses(true);
if( oText.value=='')return;
let args={
title:oText.value,
maxResults:oSel.value
};
fetch( buildurl( baseurl, args ) )
.then( r=>r.json() )
.then( json=>callback( json ) )
}
};
oSel.addEventListener('change',requesthandler);
oText.addEventListener('keydown',requesthandler);
});
<div class='container'>
<h1 class='heading'>Book Search</h1>
<input placeholder='Type Book name' class='searchBar' id='searchInput' type='search' />
<br />
<select id='selectDisplayCount' class='options'>
<option value='1'>1 Book
<option value='5'>5 Books
<option selected value='10'>10 Books
<option value='20'>20 Books
<option value='30'>30 Books
<option value='50'>50 Books
<option value='100'>100 Books
</select>
</div>
<div id='searchResults'>
<div class='col-12 d-none mt-5' id='spinner'>
<div class='d-flex flex-row justify-content-center'>
<div class='spinner-border' role='status'></div>
</div>
</div>
</div>
I'm trying to validate an input field. When i try to submit without filling in something, it gives me the error i made: please start your question with: will i ever. So i'm trying to check wether the text that the user types into the field, starts with: will i ever.
However, when i type a single (or more) random character(s), it just submits the form. I want it to check if the input starts with those fixed tree words, otherwise, no submission.
{
const handleSubmitForm = e => {
const $form = e.currentTarget;
if (!$form.checkValidity()) {
e.preventDefault();
const field = $form.querySelector('.question_field');
showValidationInfo(field);
//$form.querySelector('.error').innerHTML = 'Some errors occured';
} else {
console.log('Form is valid => submit form');
}
};
const showValidationInfo = field => {
console.log(field);
let message;
if (field.validity.valueMissing) {
message = 'Please fill in a question starting with: Will i ever';
}
if (field.validity.typeMismatch) {
message = 'Type not right';
}
if (field.validity.rangeOverflow) {
const max = field.getAttribute('max');
message = 'Too big, max ${max}';
}
if (field.validity.rangeUnderflow) {
const min = field.getAttribute('min');
message = 'Too small, min ${min}';
}
if (field.validity.tooShort) {
const min = field.getAttribute('minlength');
message = 'Too short, minimum length is ${min}';
}
if (field.validity.tooLong) {
const max = field.getAttribute('maxlength');
message = 'Too long, maximum length is ${max}';
}
if (!field.value.toLowerCase().startsWith("will i ever")) {
message = 'Start your question with: Will i ever';
}
if (message) {
field.parentElement.querySelector('.error').textContent =
message;
field.parentElement.querySelector('.error').style.color = "red";
}
};
const handeInputField = e => {
const $field = e.currentTarget;
if ($field.checkValidity()) {
$field.parentElement.querySelector('.error').textContent = '';
if ($field.form.checkValidity()) {
$field.form.querySelector('.error').innerHTML = '';
}
}
};
const handeBlurField = e => {
const $field = e.currentTarget;
showValidationInfo($field);
};
const addValidationListeners = fields => {
fields.forEach($field => {
$field.addEventListener('input', handeInputField);
$field.addEventListener('blur', handeBlurField);
});
};
const init = () => {
const $form = document.querySelector('form');
$form.noValidate = true;
$form.addEventListener('submit', handleSubmitForm);
const fields = $form.querySelectorAll('.input');
addValidationListeners(fields);
};
init();
}
<div class="name_wrapper">
<form autocomplete="off" class="form_question" action="answer.html">
<label class="name question" for="name">Ask me a question</label>
<div class="question_wrapper">
<p class="error">Start your question with: Will i ever...</p>
<input class="field question_field" type="text" name="question" placeholder="Will i ever..." value="" required>
</div>
<input id="button" class="answr-btn btn-question" type="submit" value="answer it!">
<input autocomplete="false" name="hidden" type="text" style="display:none;">
</form>
</div>
This line makes no sense:
const fields = $form.querySelectorAll('.input');
There are no HTML elements with class="input" in your form.
Did you mean $form.querySelectorAll('input')?
The problem is how you are handling the validation, the key is in this line if (!$form.checkValidity()) { this will not check if your string starts with Will i ever you have to do it manually before the if, here you have an alternative solution:
{
const handleSubmitForm = e => {
const $form = e.currentTarget;
const field = $form.querySelector('.question_field');
//here we validate the form manually
const message = showValidationInfo(field);
//if a message is found we show the error on the DOM, if is undefined we have no errors and we can submit the form
if (message) {
e.preventDefault();
$form.querySelector('.error').innerHTML = message;
$form.querySelector('.error').style.color = "red";
} else {
console.log('Form is valid => submit form');
}
};
const showValidationInfo = field => {
if (field.validity.valueMissing) {
return 'Please fill in a question starting with: Will i ever';
}
if (field.validity.typeMismatch) {
return 'Type not right';
}
if (field.validity.rangeOverflow) {
const max = field.getAttribute('max');
return 'Too big, max ${max}';
}
if (field.validity.rangeUnderflow) {
const min = field.getAttribute('min');
return 'Too small, min ${min}';
}
if (field.validity.tooShort) {
const min = field.getAttribute('minlength');
return 'Too short, minimum length is ${min}';
}
if (field.validity.tooLong) {
const max = field.getAttribute('maxlength');
return 'Too long, maximum length is ${max}';
}
if (!field.value.toLowerCase().startsWith("will i ever")) {
return 'Start your question with: Will i ever';
}
return undefined;
};
const handeInputField = e => {
const $field = e.currentTarget;
if ($field.checkValidity()) {
$field.parentElement.querySelector('.error').textContent = '';
if ($field.form.checkValidity()) {
$field.form.querySelector('.error').innerHTML = '';
}
}
};
const handeBlurField = e => {
const $field = e.currentTarget;
showValidationInfo($field);
};
const addValidationListeners = fields => {
fields.forEach($field => {
$field.addEventListener('input', handeInputField);
$field.addEventListener('blur', handeBlurField);
});
};
const init = () => {
const $form = document.querySelector('form');
$form.noValidate = true;
$form.addEventListener('submit', handleSubmitForm);
const fields = $form.querySelectorAll('.input');
addValidationListeners(fields);
};
init();
}
<div class="name_wrapper">
<form autocomplete="off" class="form_question" action="answer.html">
<label class="name question" for="name">Ask me a question</label>
<div class="question_wrapper">
<p class="error">Start your question with: Will i ever...</p>
<input class="field question_field" type="text" name="question" placeholder="Will i ever..." value="" required>
</div>
<input id="button" class="answr-btn btn-question" type="submit" value="answer it!">
<input autocomplete="false" name="hidden" type="text" style="display:none;">
</form>
You have uncommented backtick at occured `;