Element renders each time button is clicked - javascript

For the sake of practice I am trying to render an element on submitting the form but each time I click the button element renders on the page but it should render only once in the case of an invalid value.
My question is how to execute function renderError() only once, when Submit button is clicked?
The code I'm trying to accomplish this with is:
const form = document.querySelector('.form')
const renderError = () => {
const newElement = document.createElement('div')
newElement.className = 'error'
newElement.innerHTML = `
<img class="error__icon" src="images/icon-error.svg" alt="error icon" />
<p class="error__message">Please provide a valid email</p>
`
const rootElement = document.getElementById('error__container')
rootElement.append(newElement)
}
const validateForm = () => {
const isValid = /^[^\s#]+#[^\s#]+\.[^\s#]+$/
if (isValid.test(email.value)) {
// return something
} else {
renderError()
}
}
form.addEventListener('submit', (e) => {
e.preventDefault()
validateForm()
})
<div class="form__container">
<form class="form" novalidate>
<input type="email" name="email" id="email" aria-label="Email" placeholder="Email Address" />
<div id="error__container"></div>
<button class="submit">
<img src="images/icon-arrow.svg" alt="submit icon">
</button>
</form>
</div>

Don't create a new error element each time. Try to find the one created before (by id, for example). Create it only if you need it. This is often called "lazy" initialization.
// lazily return the error element (create it if we can't find it)
const errorElement = () => {
let element = document.getElementById('errorElement')
if (!element) {
element = document.createElement('div')
element.className = 'error'
element.id = 'errorElement';
const rootElement = document.getElementById('error__container')
rootElement.append(element)
}
return element
}
let count = 0
const validateForm = () => {
const isValid = /^[^\s#]+#[^\s#]+\.[^\s#]+$/
if (isValid.test(email.value)) {
// return something
} else {
const element = errorElement();
element.innerHTML = `something went wrong ${++count} times`
}
}
const form = document.getElementById('myform')
form.addEventListener('submit', (e) => {
e.preventDefault()
validateForm()
})
<div class="form__container">
<form id="myform" class="form" novalidate>
<input type="email" name="email" id="email" aria-label="Email" placeholder="Email Address" />
<div id="error__container"></div>
<button class="submit">Button
</button>
</form>
</div>

One solution: you can clear the contents of the rootElement before re-rendering:
const renderError = () => {
const newElement = document.createElement('div')
newElement.className = 'error'
newElement.innerHTML = `
<img class="error__icon" src="images/icon-error.svg" alt="error icon" />
<p class="error__message">Please provide a valid email</p>
`
const rootElement = document.getElementById('error__container')
rootElement.innerHTML = ""; // <-- Empty before appending
rootElement.append(newElement)
}
Another solution would be to add the newElement in the HTML, hide it using visibility: hidden and then toggle a class on/off that will turn the visibility value to visible and hidden. This way, when the render error runs, it will just add a special class that will display the error element and upon clicking again the element will just get the class enabled again without re-appearing.

Related

javascript button is not working based on code

I am trying to make login button enabled and color change to darker blue when there is at least one input for both id and password. (I have not implemented enabling portion yet.) Yet, above code does not seem to work. Could anyone help? Thanks!
const button = document.getElementById('button');
const idbar = document.getElementsByClassName('id-bar')[0];
const pwbar = document.getElementsByClassName('password-bar')[0];
const bar = document.getElementById('input')
bar.addEventListener("keyup", () =>{
const id = idbar.value;
const pw = pwbar.value;
if (id.length > 0 && pw.length > 0) {
button.style.backgroundColor = "#0095F6"
} else {
button.style.backgroundColor = "#C0DFFD"
}
});
<head>
<script src="js/login.js"></script>
</head>
<body>
<div class = wrapper>
<input id = "input" class = "id-bar" type = "text" placeholder = "email">
<input id = "input" class = "password-bar" type = "password" placeholder = "password">
<button id = "button">login</button>
</div>
</body>
id should be unique...
if not using id
const button = document.getElementById('button');
const idbar = document.getElementsByClassName('id-bar')[0];
const pwbar = document.getElementsByClassName('password-bar')[0];
const bar = document.getElementsByTagName("input");
[...bar].forEach(bar => {
bar.addEventListener("keyup", () =>{
const id = idbar.value;
const pw = pwbar.value;
if (id.length > 0 && pw.length > 0) {
button.style.backgroundColor = "#0095F6"
} else {
button.style.backgroundColor = "#C0DFFD"
}
});
})
<head>
<script src="js/login.js"></script>
</head>
<body>
<div class = wrapper>
<input id = "input" class = "id-bar" type = "text" placeholder = "email">
<input id = "input" class = "password-bar" type = "password" placeholder = "password">
<button id = "button">login</button>
</div>
</body>
So the problem with your code is that you are using id for targeting two element which is not possible and many have answered it, but I have a different suggestion which is CSS.
.submit {
background-color: #c0dffd;
}
.email-input:valid + .password-input:valid + .submit {
background-color: #0095f6;
}
<input type="text" class="email-input" required />
<input type="password" class="password-input" required />
<button class="submit">Submit</button>
You can even check whether email is valid or not just by adding type="email" in email input !
Your ids/classes are kind of all over the place, and as #dangerousmanleesanghyeon mentions, they don't conform to proper usage. Might be worth your time briefly reading up on how to use them correctly, via MDN: CSS selectors.
Anyway, I've refactored your code a little, and replaced the getElementBys with more versatile querySelectors, which is a great method to use, and might save you from some future headaches along your coding journey.
Just a note: querySelectorAll (used to get both the bars) returns a NodeList, which I've had to make into an Array in order to use map. This might feel a little complex right now, but these are useful concepts to familiarise yourself with!
const button = document.querySelector('#button')
const idbar = document.querySelector('#idInput')
const pwbar = document.querySelector('#passwordInput')
const bars = document.querySelectorAll('.input')
Array.from(bars).map(bar => bar.addEventListener("keyup", () => {
const id = idbar.value
const pw = pwbar.value
if (id.length > 0 && pw.length > 0) {
button.style.backgroundColor = "#0095F6"
} else {
button.style.backgroundColor = "#C0DFFD"
}
}))
<head>
<script src="js/login.js"></script>
</head>
<body>
<div class=wrapper>
<input id="idInput" class="input" type="text" placeholder="email">
<input id="passwordInput" class="input" type="password" placeholder="password">
<button id="button">login</button>
</div>
</body>
Just interchange the id & class values of inputs and changed the JS code accordingly. id must be unique.
const bars = document.getElementsByClassName('input');
const idbar = document.getElementById('id-bar');
const pwbar = document.getElementById('password-bar');
const button = document.getElementById('button');
for (bar of bars) {
bar.addEventListener("keyup", () => {
const id = idbar.value;
const pw = pwbar.value;
button.style.backgroundColor = (id.length && pw.length) ? "#0095F6" : "#C0DFFD"
});
}
<div class = wrapper>
<input id="id-bar" class="input" type="text" placeholder="email">
<input id="password-bar" class="input" type="password" placeholder="password">
<button id="button">login</button>
</div>

How to submit form on Enter using DIV

I'm trying to figure out how to make my form submit when enter is pressed inside the div that is acting as input. Any help?
Here is my code.
const socket = new WebSocket("ws://localhost:5000");
const Chat = () => {
let divText = "";
const SendMessage = (event) => {
event.preventDefault();
console.log(divText);
divText = "";
}
const HandleChange = (event) => {
divText = event.target.textContent;
}
return (
<div className='chat-div'>
<div className='chat-box'>
<span className='razmak'></span>
</div>
<form className='input-form' onSubmit={SendMessage} spellCheck='false'>
<div className='chat-input' contentEditable='true' onInput={HandleChange}></div>
<button className='send-button' type='submit'><AiOutlineSend/></button>
</form>
</div>
)
}
export default Chat;
What I'd do is update your div to use an onKeyDown like this:
const socket = new WebSocket("ws://localhost:5000");
const Chat = () => {
let divText = "";
const sendMessage = (event) => {
alert("submit");
event.preventDefault();
console.log(divText);
divText = "";
};
const handleChange = (e) => {
divText = e.target.textContent;
if (e.key === "Enter") {
sendMessage(e);
}
};
return (
<div className="chat-div">
<div className="chat-box">
<span className="razmak"></span>
</div>
<form className="input-form" onSubmit={sendMessage} spellCheck="false">
<div
className="chat-input"
contentEditable="true"
onKeyDown={(e) => handleChange(e)}
></div>
<button className="send-button" type="submit">
jhgj
</button>
</form>
</div>
);
};
export default Chat;
There's a couple of other things, some which I've not included above:
Lowercase the method names if they don't return JSX
The divText should ideally use the useState React hook
Consider using a standard input rather than a div, as this is semantically more correct, and accessible for people using screen readers.

How to remove unwanted element

I'm trying to write easy validation code and I have trouble. I've created element div '._error-alert' and I cant remove it if the input isn't empty.
When I press submit appears my element '._error-alert' but it doesnt disapear when I try to type something there. I'll be very grateful if u help or at least show me the other path to solve it
const form = document.querySelector('.validation__form'),
reqItems = document.querySelectorAll('._req'),
emailTest = /^(([^<>()\[\]\.,;:\s#\"]+(\.[^<>()\[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()\.,;\s#\"]+\.{0,1})+[^<>()\.,;:\s#\"]{2,})$/,
onlyTextTest = /^[a-zA-Z0-9#]+$/,
onlyNums = /^[0-9]+$/;
const inputTest = (example, input) => example.test(input.value);
const formAddError = (input) => {
if (input.classList.contains('_req')) {
const createBlock = document.createElement('div');
createBlock.classList.add('_error-alert');
input.parentElement.insertAdjacentElement("beforeend", createBlock);
createBlock.innerText = `Invalid ${input.getAttribute("name")}!`;
}
input.parentElement.classList.add('_error');
input.classList.add('_error');
};
const formRemoveError = (input) => {
input.parentElement.classList.remove('_error');
input.classList.remove('_error');
};
// validates form if function validateForm didn't have any errors and removes my created elements '._error-alert'
const sendValidatedForm = (e) => {
e.preventDefault();
let error = validateForm(form);
if (error === 0) {
console.log('fine');
form.reset();
document.querySelectorAll('._error-alert').forEach((errorAlert) => {
errorAlert.remove();
});
}
};
form.addEventListener('submit', sendValidatedForm);
// there I want to check input and remove '._error-alert' if input isnt wrong
const checkInput = () => {
reqItems.forEach((reqInput, index) => {
reqInput.addEventListener('input', () => {
formRemoveError(reqInput);
});
});
};
checkInput();
const validateForm = (form) => {
let error = 0;
reqItems.forEach(reqInput => {
reqInput.value.trim();
formRemoveError(reqInput);
if (reqInput.getAttribute("name") == "email") {
if (!inputTest(emailTest, reqInput)) {
formAddError(reqInput);
error++;
}
} else if (reqInput.getAttribute("name") == "phone") {
if (!inputTest(onlyNums, reqInput) && reqInput.value.length < 8) {
formAddError(reqInput);
error++;
}
} else if (reqInput.getAttribute("name") == "name") {
if (!inputTest(onlyTextTest, reqInput)) {
formAddError(reqInput);
error++;
}
}
});
console.log(error);
return error;
};
<form action="" class="validation__form">
<div class="validation__input-list">
<div class="validation__input-item">
<input type="text" class="validation__input-input _req" name="name" placeholder="Name">
</div>
<div class="validation__input-item">
<input type="text" class="validation__input-input" name="surname" placeholder="Surname">
</div>
<div class="validation__input-item">
<input type="text" class="validation__input-input _req" name="phone" placeholder="Phone">
</div>
<div class="validation__input-item">
<input type="text" class="validation__input-input _req" name="email" placeholder="Email">
</div>
<div class="validation__input-item">
<input type="text" class="validation__input-input" name="password" placeholder="Password">
</div>
</div>
<button class="validation__form-btn">Submit</button>
</form>
Set the css visibility property of the element to hidden.
const error_element = document.getElementsByClassName('_error-alert')
error_element.style.visibility = 'hidden'

How I can display the form data in the same page without submit the form?

I have a form in HTML and I want to display the form text input data on the same page but before pressing the submit button.
Mean, When Users put the data in the form it must display below the form on same page.
It's mean that I want to show all data before submitting the form.
I know this code will not work as i want
var strText = document.getElementById("textone");
document.write(strText.value);
var strText1 = document.getElementById("textTWO");
document.write(strText1.value);
}
This is how I would do it by directly manipulating the DOM:
const input = document.getElementById('textInput');
const textElement = document.getElementById('displayText');
function updateValue(e) {
textElement.textContent = e.target.value;
}
input.addEventListener('input', updateValue);
<input type="text" id="textInput">
<p>value from input:</p>
<div id="displayText"></div>
There are also javascript libraries like VueJS and ReactJS that can help you do this more easily and efficiently.
This is an example of something like what you would want to do in VueJS: https://v2.vuejs.org/v2/examples/index.html
I've prepared an example of general functioning, I hope you like it. It may not be exactly what you want, but if it is, please tell me.
const myForm = document.getElementById("myForm");
const nameInput = document.getElementById("nameInput");
const emailInput = document.getElementById("emailInput");
const nameOutput = document.getElementById("nameOutput");
const emailOutput = document.getElementById("emailOutput");
let nameSpan = document.getElementById("name");
let emailSpan = document.getElementById("email");
myForm.addEventListener("submit", e => {
e.preventDefault();
alert(`NAME: ${nameInput.value}, EMAİL : ${emailInput.value}`)
// select name , mail
nameSpan.innerText = nameInput.value;
emailSpan.innerText = emailInput.value;
// clear ınputs
nameInput.value = "";
emailInput.value = ""
})
showData();
function showData() {
nameInput.addEventListener("keyup", e => {
nameOutput.value = e.target.value;
})
emailInput.addEventListener("keyup", e => {
emailOutput.value = e.target.value;
})
}
<form id="myForm">
<input type="text" id="nameInput" placeholder="your name">
<input type="text" id="emailInput" placeholder="your email">
<button type="submit" id="getInputValue"> Get Input Value </button>
</form>
<div id="values" style="margin-top: 100px;">
<input type="text" placeholder="NAME" id="nameOutput">
<input type="text" placeholder="EMAİL" id="emailOutput">
</div>
<div>
<p>Your name : <span id="name"></span></p>
<p>Your email : <span id="email"></span></p>
</div>

JS Form: How do I push() into an array, without creating a new array every time I click Submit?

Every time I click Submit, its creating a new array with an object
Array should receive keep receiving objects and not create a new one
JS:
const form = document.querySelector('#form')
form.addEventListener('submit', (e) => {
e.preventDefault()
const title = document.querySelector('#title').value
const img = document.querySelector('#img').value
const story = document.querySelector('#story').value
const author = document.querySelector('#author').value
const eachStory = {
myTitle : title,
myImg : img,
myStory : story,
myAuthor : author
}
let stories = []
stories.push(eachStory)
stories.forEach((story) => {
root.innerHTML +=
`
${eachStory.myTitle}
${eachStory.myStory}
${eachStory.myImg}
${eachStory.myAuthor}
`
})
console.log(stories)
})
HTML:
<body>
<div>
<form id="form">
<input type="text" id="title" >
<input type="text" id="img" >
<input type="text" id="story" >
<input type="text" id="author" >
<button>SUBMIT</button>
</form>
<div id="root"></div>
</div>
Can someone tell me what I should do here?
I need to add objects to the same array every time i click submit
Everytime the form is submitted, the submit event fires up and the handler function is executed. Since, you are initializing a new stories array inside your function, every time the form is submitted, a new stories array is created.
You might want to move your stories array declaration out of the function, so that new posts are added to the existing the stories array.
const form = document.querySelector('#form')
let stories= [];
form.addEventListener('submit', (e) => {...}
First declare the array outside the submit handler. Secondly if you want to append it to the dom you can avoid the array and iterating it. Also iterating over the array may create duplication over row
const form = document.querySelector('#form')
let stories = []
form.addEventListener('submit', (e) => {
e.preventDefault()
const title = document.querySelector('#title').value;
const img = document.querySelector('#img').value;
const story = document.querySelector('#story').value;
const author = document.querySelector('#author').value;
root.innerHTML +=
`<div>
${title}
${img}
${story}
${author}</div>
`;
stories.push({
myTitle: title,
myImg: img,
myStory: story,
myAuthor: author
})
})
<div>
<form id="form">
<input type="text" id="title">
<input type="text" id="img">
<input type="text" id="story">
<input type="text" id="author">
<button>SUBMIT</button>
</form>
<div id="root"></div>
</div>
On Submit click it will create new Object and add in array.And next/every click it will add only object in existing array and not will remove the existing Object.
const form = document.querySelector("#form");
let stories = [];
form.addEventListener("submit", e => {
e.preventDefault();
const title = document.querySelector("#title").value;
const img = document.querySelector("#img").value;
const story = document.querySelector("#story").value;
const author = document.querySelector("#author").value;
var storyObj = {};
storyObj["myTitle"] = title;
storyObj["myImg"] = img;
storyObj["myStory"] = story;
storyObj["myAuthor"] = author;
stories.push(storyObj);
stories.forEach(story => {
root.innerHTML += `
${story.myTitle}
${story.myStory}
${story.myImg}
${story.myAuthor}
`;
});
console.log("Create data value==>+", JSON.stringify(stories));
});

Categories

Resources