function only works one time - javascript

This is my first question on here. I use this site all of the time, but have never posted on here.
When I call the function writeMessage(), when the checkbox is checked, the textarea is created. When I uncheck the checkbox, the textarea is removed. When I check the checkbox the second time, the function is not called. Any suggestions? I need for it to show the textarea any time the checkbox is checked, not just the first time around. Below is my code.
HTML:
<table>
<th>
<input type = "checkbox" name = "os0" id = "spaceForMsg" onClick = "writeMessage()">
<label for "gift"> Gift for someone</label>
</th>
</table>
<table >
<tr id = 'parent'>
<div id = 'printMsg'></div>
</tr>
</table>
javascript function:
function writeMessage() {
var x = document.getElementById('spaceForMsg');
var docBody = document.getElementById('parent');
var element = document.createElement('textarea');
element.cols='60';
element.rows='8';
element.id = 'msgArea';
if (x.checked) {
give = 'Type your gift message here: ';
docBody.appendChild(element);
} else {
give = '';
y = document.getElementById('parent').parentNode;
y.removeChild(y.childNodes[0]);
}
document.getElementById('printMsg').innerHTML = give;
}

writeMessage is removing "the first child of the parent of document.getElementById('parent') (which happens to be equal to docBody). This means that you are removing docBody itself.
The next time you call writeMessage after removing docBody, the document will fail to find a proper parent, thus docBody.appendChild(element); will fail.
Try this instead:
function writeMessage() {
var give;
var x = document.getElementById('spaceForMsg');
var docBody = document.getElementById('parent');
if (x.checked) {
var element = document.createElement('textarea');
element.cols='60';
element.rows='8';
element.id = 'msgArea';
give = 'Type your gift message here: ';
docBody.appendChild(element);
} else {
give = '';
y = docBody.removeChild(docBody.getElementsByTagName('textarea')[0]);
}
document.getElementById('printMsg').innerHTML = give;
}

You are removing <div id='parent'></div>, with this line y.removeChild(y.childNodes[0]);, so you can't put anything in there since it doesn't exist.

Related

Making array with input of textarea

I'm trying to capture the input of a textarea and converting it to an array but it is reading the whole input as one element and making array of length 1.
<html>
<textarea id="area"></textarea>
<input type="submit" onclick="won()">
<p id="one" style="display: none;"></p>
</html>
The js part displays a message of the length of the array.
var area = document.getElementById("area");
var lines = area.value.split("\n");
var pa = document.getElementById("one");
function won() {
pa.style.display = "block";
pa.innerHTML = lines.length;
}
What I'm trying to achieve with the whole thing is that. The multi line input is to be converted into an array with each new line being a new element. Then I loop through the array and if even one element doesn't pass a validation function, an exception message is displayed under the texarea.
Can someone kindly help me with this?
With your snippet, you're grabbing the value onload so it would be empty, it should be in the event where you grab the value. Also avoid inline event triggering, add the event via js.
var area = document.getElementById("area");
var button = document.getElementById("btn-submit");
var one = document.getElementById("one");
button.addEventListener('click', () => {
// get value
var lines = area.value.split("\n");
one.style.display = "block";
one.innerHTML = lines.length;
})
<textarea id="area"></textarea>
<button type="button" id="btn-submit">Submit</button>
<p id="one" style="display: none;"></p>
What I'm trying to achieve with the whole thing is that. The multi
line input is to be converted into an array with each new line being a
new element. Then I loop through the array and if even one element
doesn't pass a validation function, an exception message is displayed
under the texarea.
const area = document.getElementById("area");
const button = document.getElementById("btn-submit");
const error = document.getElementById("error");
const items = document.getElementById("items");
button.addEventListener('click', () => {
// get textarea value, remove emptys
const lines = area.value.split("\n").filter(Boolean);
// reset error and items dom
error.innerHTML = items.innerHTML = ''
// do your validation, could loop or use .some(), .includes()
if (!lines.length) {
error.innerHTML = 'Enter at least one item'
} else if (!lines.includes('cat')) {
error.innerHTML = 'Entered lines should include at least one cat'
} else {
// no errors
items.innerHTML = `${lines.length} items<br><ul><li>${lines.join('</li><li>')}</li></ul>`
}
})
<textarea id="area"></textarea>
<button type="button" id="btn-submit">Submit</button>
<div id="error"></div>
<div id="items"></div>
Simply put your line var lines = area.value.split("\n"); under the won function like below and you will get your total lines.
Example
var area = document.getElementById("area");
var pa = document.getElementById("one");
function won() {
var lines = area.value.split("\n");
pa.style.display = "block";
pa.innerHTML = lines.length;
}
You can check it here too, https://codepen.io/vadera-abhijeet/pen/yLPxLRY

How to execute local stored value by search function afther page reload / refresh

I use the following form and script to let users filter a td table on the input they give in. It filters the rows of the table and only shows the rows corresponding to their given value. They can update the rows that they are seeing, after they do this the page refreshes/reloads to refresh the table. After the page is refreshed/reloaded the search filter shows all rows again. I am searching for a way to keep the rows that they had before the update event happend based on their filter input. In other words, as if the refresh never happend.
Search form;
...
<p align='left' style="display:inline">
<table class="userprof" align='left'>
<tr>
<td class="footer">Filter:
<input type="text" id="myInput" name="filter" style="color:black !important;" placeholder="Filter table" onkeyup='saveValue(this);' />
</td>
</tr>
</table>
</p>
...
I use the folowing script to save their input as localstorage.
...
document.getElementById("myInput").value = getSavedValue("myInput"); // set the value to this input
/* Here you can add more inputs to set value. if it's saved */
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e) {
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val); // Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue(v) {
if (!localStorage.getItem(v)) {
return ""; // You can change this to your defualt value.
}
return localStorage.getItem(v);
}
...
I use the following script to filter the table rows
...
function filterTable(event) {
var filter = event.target.value.toUpperCase();
var rows = document.querySelector("#myTable tbody").rows;
for (var i = 0; i < rows.length; i++) {
var nameCol = rows[i].cells[1].textContent.toUpperCase();
var rankCol = rows[i].cells[2].textContent.toUpperCase();
var rankerCol = rows[i].cells[5].textContent.toUpperCase();
var typeCol = rows[i].cells[6].textContent.toUpperCase();
var emailCol = rows[i].cells[3].textContent.toUpperCase();
if (nameCol.indexOf(filter) > -1 || rankCol.indexOf(filter) > -1 || rankerCol.indexOf(filter) > -1 || typeCol.indexOf(filter) > -1 || emailCol.indexOf(filter) > -1) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
}
}
document.querySelector('#myInput').addEventListener('keyup', filterTable, false);
...
You are almost there and only need minor modifications to make this happen.
I'd suggest that you change your flow up a bit.
First remove the onkeyup inline listener from your HTML. You are currently listening for that event 3 times on 1 element which seems overkill.
...
<p align='left' style="display:inline">
<table class="userprof" align='left'>
<tr>
<td class="footer">Filter:
<input type="text" id="myInput" name="filter" style="color:black !important;" placeholder="Filter table" />
</td>
</tr>
</table>
</p>
...
Then modify the filterTable to accept just a value, not an event object. This way you can call filterTable at any time and inject a value into it. And it allows you to call it immediately with the stored value when the page loads so that your initial filter will be set (or not if there is nothing stored).
Now listen for the keyup event with only a single listener which will both pass the value of the event to filterTable and the event itself to saveValue so that are both filtering and saving.
// Store the input in a variable for reference.
var myInput = document.getElementById("myInput");
var savedValue = getSavedValue("myInput");
// Immediately filter the table and set the input value.
filterTable(savedValue);
myInput.value = savedValue;
//Save the value function - save it to localStorage as (ID, VALUE)
function saveValue(e) {
var id = e.id; // get the sender's id to save it .
var val = e.value; // get the value.
localStorage.setItem(id, val); // Every time user writing something, the localStorage's value will override .
}
//get the saved value function - return the value of "v" from localStorage.
function getSavedValue(v) {
if (!localStorage.getItem(v)) {
return ""; // You can change this to your default value.
}
return localStorage.getItem(v);
}
function filterTable(value) {
console.log(value);
var filter = value.toUpperCase();
var rows = document.querySelector("#myTable tbody").rows;
for (var i = 0; i < rows.length; i++) {
var nameCol = rows[i].cells[1].textContent.toUpperCase();
var rankCol = rows[i].cells[2].textContent.toUpperCase();
var rankerCol = rows[i].cells[5].textContent.toUpperCase();
var typeCol = rows[i].cells[6].textContent.toUpperCase();
var emailCol = rows[i].cells[3].textContent.toUpperCase();
if (nameCol.indexOf(filter) > -1 || rankCol.indexOf(filter) > -1 || rankerCol.indexOf(filter) > -1 || typeCol.indexOf(filter) > -1 || emailCol.indexOf(filter) > -1) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
}
}
myInput.addEventListener('keyup', function(event) {
var value = event.target.value;
saveValue(event);
filterTable(value);
});

Unable to set the onclick property of a button

I have a button calling a js function. Everything in the function runs but at the end I try to set the onclick value for the button and nothing happens. The catch block doesn't even generate an error
var nextButton = document.getElementById("next");
try{
if(tvalue == "trend"){
nextButton.onclick = "generateLocations()";
}
else if (tvalue == "stats"){
nextButton.onclick = "generateCategories()";
}
}
catch(err) {
document.getElementById("demo").innerHTML = err.message;
}
I have also tried setting the onclick value these ways
nextButton.onclick = function () { generateCategories(); };
nextButton.onclick = generateCategories;
the tvalue variable is set like this:
var t = document.getElementById("type");
var tvalue = t.options[t.selectedIndex].value;
Other test outputs have shown that this retrieves the value no problem
The relevant HTML:
<form id='fieldsets' action="../scripts/reportParse.php">
<fieldset>
<legend> Select Report Type </legend>
<select id="type" name="type">
<option value="trend"> Waitlists over Time </option>
<option value="stats"> Region Statistics </option>
</select>
</fieldset>
<button id="next" onclick="generateRegions()"> Next </button>
I've been trying solutions based on the following page:
Change onclick action with a Javascript function
and w3schools.com
Thanks for any help. I've been hung up on this for a little bit now
Edit: I've tried useing event listeners based on a comment below and am now getting the error "i is not defined'. which seems odd since i is not referred too inside the try block.
The whole function in case i've missed something stupid:
function generateRegions(){
var t = document.getElementById("type");
var tvalue = t.options[t.selectedIndex].value; // The value of the selected option
var names = ["Downtown", "Glenmore", "Mission", "Rutland"];
var regions = document.createElement("FIELDSET");
regions.setAttribute("id","Region");
var temp = document.createElement("LEGEND");
temp.innerHTML = "Select Region:";
regions.appendChild(temp); //creating the fieldset div and assigning its legend
for(var i = 0; i < 4; i++){
var templ = document.createElement("LABEL");
var str1 = "chk";
var str2 = i.toString();
var id = str1.concat(str2); //creating a dynamic ID so each checkbox can be referred to individually
templ.setAttribute("for",id);
temp = document.createElement("INPUT"); //creating the checkbox and assigning its values
temp.setAttribute("type","checkbox");
temp.setAttribute("name","region");
temp.setAttribute("value",names[i]);
temp.setAttribute("id",id);
regions.appendChild(templ);
templ.innerText = names[i]+':'; //creating and placing the label, then placing its checkbox
regions.appendChild(temp);
}
document.getElementById("fieldsets").appendChild(regions); //adding the fieldset to the overall form
var nextButton = document.getElementById("next");
try{
if(tvalue == "trend"){
nextButton.onclick = "generateLocations()";
}
else if (tvalue == "stats"){
nextButton.onclick = "generateCategories()";
}
}
catch(err) {
document.getElementById("demo").innerHTML = err.message;
}
//document.getElementById("demo").innerHTML = tvalue; //checking that the type variable is properly found
}
Try adding an event listener to your code so the JavaScript is separated from the HTML markup. Like so:
var nextButton = document.getElementById("next");
try{
if(tvalue == "trend"){
nextButton.addEventListener("click",generateLocations()) ;
}
else if (tvalue == "stats"){
nextButton.addEventListener("click",generaCategories()) ;
}
}
catch(err) {
document.getElementById("demo").innerHTML = err.message;
}
You can test if the event listener is working by adding a console log on the functions you are executing.
Source: https://www.w3schools.com/js/js_htmldom_eventlistener.asp

Search function filter li's in pure Js

I'm trying to make an input that filters a <ul> based on the value in pure JavaScript. It should filter dynamically with the onkeyup by getting the li's and comparing their inner element name with the filter text.
Here is my function:
var searchFunction = function searchFeature (searchString) {
console.log("Is my search feature working?");
//Get the value entered in the search box
var inputString = document.getElementById('inputSearch');
var stringValue = inputString.value;
//Onkeyup we want to filter the content by the string entered in the search box
stringValue.onkeyup = function () {
//toUpperCase to make it case insensitive
var filter = stringValue.toUpperCase();
//loop through all the lis
for (var i = 0; i < eachStudent.length; i++) {
//Do this for all the elements (h3, email, joined-details, date)
var name = eachStudent[i].getElementsByClassName('student-details')[1].innerHTML;
//display all the results where indexOf() returns 0
if (name.toUpperCase().indexOf(filter) == 0)
eachStudent[i].style.display = 'list-item';
else
eachStudent[i].style.display = 'none';
}
}}
My HTML for the search bar:
<div class="student-search">
<input id="inputSearch" placeholder="Type name here.." type="text"> <button>Search</button></div>
My HTML for one of the li's:
<ul class="student-list">
<li class="student-item cf">
<div class="student-details">
<img class="avatar" src="#">
<h3>John Doe</h3>
<span class="email">John.Doe#example.com</span>
</div>
<div class="joined-details">
<span class="date">Joined 01/01/14</span>
</div>
</li>
I would like to filter all the elements (name, email, joined date) based on the value of the input.
Unfortunately, I don't get any errors and it's simply not working.
The function is correctly invoked because the console.log prints...
Here goes the codepen: http://codepen.io/Delano83/pen/qaxxjA?editors=1010
Any help or comments on my code is very appreciated.
There were several issues:
stringValue.onkeyup - stringValue is the value. You can't onkeyup it.
var eachStudent = document.querySelector(".student-item"); will fetch the first thing with student-item class. You need to use querySelectorAll or just use jquery's $('.find-item').
if (name.toUpperCase().indexOf(filter) == 0) indexOf returns 0 if the filter is found at the beginning of the name. 0 as match if found at index 0. You need to check against -1, which means it was not found at all.
Otherwise it more or less worked, good job.
I also added Jquery for me to fix it faster. If you insist on using pure javascript I am sure you will be able to edit it.
Check it out here: http://codepen.io/anon/pen/WGrrXW?editors=1010. Here is the resulting code:
var page = document.querySelector(".page");
var pageHeader = document.querySelector(".page-header");
var studentList = document.querySelector(".student-list");
var eachStudent = document.querySelectorAll(".student-item");
var studentDetails = document.querySelector(".student-details");
//Recreate Search Element in Js
var searchBar = function createBar(searchString) {
var studentSearch = document.createElement("div");
var input = document.createElement("input");
var searchButton = document.createElement("button");
input.type = "text";
var txtNode = document.createTextNode("Search");
if (typeof txtNode == "object") {
searchButton.appendChild(txtNode);
}
studentSearch.setAttribute("class", "student-search");
input.setAttribute("id", "inputSearch");
//append these elements to the page
studentSearch.appendChild(input);
studentSearch.appendChild(searchButton);
input.placeholder = "Type name here..";
return studentSearch;
}
var searchFunction = function searchFeature(searchString) {
console.log("Is my search feature working?");
//Get the value entered in the search box
var inputString = document.getElementById('inputSearch');
var stringValue = inputString.value;
//Onkeyup we want to filter the content by the string entered in the search box
inputString.onkeyup = function() {
//toUpperCase to make it case insensitive
var filter = $(this).val().toUpperCase()
//loop through all the lis
for (var i = 0; i < eachStudent.length; i++) {
//Do this for all the elements (h3, email, joined-details, date)
var name = $(eachStudent[i]).find('h3').text()
console.log(name, filter, name.toUpperCase().indexOf(filter))
//display all the results where indexOf() does not return -1
if (name.toUpperCase().indexOf(filter) != -1)
eachStudent[i].style.display = 'list-item';
else
eachStudent[i].style.display = 'none';
}
}
}
function addElements() {
console.log('Add search bar, trying to anyway...')
pageHeader.appendChild(searchBar());
// page.appendChild(paginationFilter());
onLoad();
}
window.onload = addElements;
window.onLoad = searchFunction;

entry in input one by one should show added result in result field

when user select any option in radio buttons in group one and then enter any number in respective input field and then select the next any radio option and enter any value in input field then this time it should add the new result with old one and display it in result input field and now if he empty any input field then that should also minus from the total result and display it in result field.
i have so many groups like that but here i just put two of them to get the result.
here id the FIDDLE
here is the jquery code. i can work in jquery but not very good i used separate code for every group and i know there must be a way to get this whole functionality through generic code but again i am not good at jquery
jQuery("#txt_im").keyup(setValue);
jQuery('[name="rdbtn-im"]').change(setValue);
function setValue() {
var txt_value = jQuery("#txt_im").val();
var rad_val = jQuery('[name="rdbtn-im"]:checked').val();
if(!txt_value.length) {
jQuery('#final_res').val('');
return;
}
if (!rad_val.length) return;
var res = txt_value * rad_val;
var final = parseInt(res, 10);
var MBresult = final / 1024;
jQuery('#final_res').val(MBresult.toFixed(2));
}
var final2 = 0;
jQuery("#txt_fb").keyup(setValue2);
jQuery('[name="rdbtn-fb"]').change(setValue2);
function setValue2() {
var txt_value = jQuery("#txt_fb").val();
var rad_val = jQuery('[name="rdbtn-fb"]:checked').val();
if(!txt_value.length) {
jQuery('#final_res').val('');
return;
}
if (!rad_val.length) return;
var res2 = txt_value * rad_val;
final2 = parseInt(res2, 10) + final;
var MBresult = final2 / 1024;
jQuery('#final_res').val(MBresult.toFixed(2));
}
infact user is free to select any number of groups or also free to remove any number of group after selection.
i know there is error in fiddle when user select 2nd group after the select of first it removes the result which is wron and i tried to solve it but failed but i define the whole seen what i need to do. i will be very thankfull to you for this kind favour.
HTML:
<table>
<tr>
<td>
<input type="radio" name="rdbtn-im" id="rdbtn-im-day" value="25" class="rdbtn-style-social" />Daily
<input type="radio" name="rdbtn-im" id="rdbtn-im-week" value="175" class="rdbtn-style-social" />Weekly
<input type="text" name="txb3" id="txt_im" class="txt-email" style="width:100px;margin: 2px;" />
</td>
</tr>
<tr>
<td class="sec-td-rdbtns-social">
<input type="radio" name="rdbtn-fb" id="rdbtn-fb-day" value="3500" class="rdbtn-style-social" />Daily
<input type="radio" name="rdbtn-fb" id="rdbtn-fb-week" value="500" class="rdbtn-style-social" />Weekly
<input type="text" name="txb1" id="txt_fb" class="txt-email" style="width:100px;margin: 2px;" /> </td>
</tr>
</table>
<br>result
<input type="text" name="final_res" id="final_res" class="" style="width:100px;margin: 2px;" />
Jquery:
jQuery(".txt-email").keyup(setValue);
jQuery('.rdbtn-style-social').change(setValue);
function setValue() {
var total = 0;
$(".rdbtn-style-social:checked").each(function () {
var myInput = $(this).siblings(".txt-email").val();
if (myInput.length) {
total += myInput * $(this).val();
}
});
if (total) {
jQuery('#final_res').val((total / 1024).toFixed(2));
} else {
jQuery('#final_res').val('');
}
}
FIDDLE
If you are using chrome, then console is your best friend ( https://developers.google.com/chrome-developer-tools/docs/console )
For firefox you have firebug, opera has dragonfly (or something like that ?). Even IE has console now. There you can see all errors popping up.
Ok, so first of all let's clean up this a little bit by wrapping it all in closure (we can now safely use the $ instead of jQuery even if there is namespace conflict outside). Also, we will use single function for both cases, because they are so similar.
!function ($) {
$(".txt-email").keyup(setValue);
$('.rdbtn-style-social').change(function(e) { setValue(e, true) });
function setValue(e, radio) {
if('undefined' === typeof radio) radio = false;
var attr = radio ? 'name' : 'id';
var tmp = e.target[attr].split('-');
var media = tmp[tmp.length - 1];
var txt_value = $("#txt-"+media).val();
var rad_val = $('.rdbtn-style-social[name="rdbtn-'+media+'"]:checked').val();
if (!txt_value.length || !rad_val.length) {
$('#final_res').val('');
return false;
}
var res = (txt_value | 0) * rad_val;
var final = parseInt(res, 10);
var MBresult = final / 1024;
$('#final_res').val(MBresult.toFixed(2));
}
}(jQuery);
(variable | 0 is same as parseInt(variable, 10)).
So, long story short: when radio or text gets changed, the function is fired (if it's radio, additional argument is passed). We retrieve whether we want to work on im or fb, then do whatever you want. I changed id of inputs to replace _ with -'s (for split consistency)
Final jsfiddle: http://jsfiddle.net/Misiur/f6cxA/1/

Categories