PHP code doesn't see input added through js - javascript

I have form that collect datas when SAVE button is pressed from three inputs. First two is already loaded on the site, but last appears when DVD-disk is selected in <select>. So PHP code see values from first two inputs, but not from the last one. I added name and id to all of them. Inputs are in the main container that is in form.
Expected output: echo ($DVDdisk) show data
Real output: Undefined index: DVDsize
let selector = document.getElementById("selector");
let main = document.getElementById("input-main-add");
let div = document.createElement('div');
let h2 = document.createElement('H2');
let input = document.createElement('input');
selector.addEventListener("change", (e) => {
if (selector.value == "DVD") {
div.classList.add('input-add-holder');
main.appendChild(div);
h2.textContent = 'Enter size:';
h2.style.display = 'inline-block';
div.appendChild(h2);
input.setAttribute("name", "DVDsize");
input.setAttribute("id", "DVDsize");
div.appendChild(input);
}
});
<form method="POST" action="add.php">
<button class="accept-btn" type="submit">SAVE</button>
<!-- + -->
<button class="decline-btn">CANCEL</button>
<!-- + -->
</div>
</div>
<div class="input-main-add" id="input-main-add">
<!-- + -->
<div class="input-add-holder">
<H2 style="display:inline-block">SKU: </H2>
<input class="something" name="SKU" id="SKU"></input>
</div>
<div class="input-add-holder">
<H2 style="display:inline-block">Name: </H2>
<input class="something" name="name" id="name"></input>
</div>
<div class="input-add-holder">
<H2 style="display:inline-block">Type Switcher: </H2>
<select name="selector" id="selector">
<option value="DVD" id="DVD" name="DVD">DVD-Disk</option>
<option value="book" id="book" name="book">Book</option>
<option value="furniture" id="furniture" name="furniture">Furniture</option>
</select>
</div>
</div>
</form>
PHP code:
<?php
$SKU = $_POST["SKU"];
$name = $_POST["name"];
$DVDsize = $_POST["DVDsize"];
echo ($SKU);
echo ($name);
echo ($DVDsize);
?>

Your JS listen for change event on Type Switcher select box that the selected value must be DVD-Disk but your default value of this select box is DVD-Disk which is already selected.
So, this event will never happens when you just load the page, fill form (without change select box) and submit.
If this event never happens, it means input name DVDSize will not rendered and not send to server. That's why your PHP doesn't see this input.
You have to manually trigger change event for select box once DOM ready.
let selector = document.getElementById("selector");
let main = document.getElementById("input-main-add");
let div = document.createElement('div');
let h2 = document.createElement('H2');
let input = document.createElement('input');
selector.addEventListener("change", (e) => {
if (selector.value == "DVD") {
div.classList.add('input-add-holder');
main.appendChild(div);
h2.textContent = 'Enter size:';
h2.style.display = 'inline-block';
div.appendChild(h2);
input.setAttribute("name", "DVDsize");
input.setAttribute("id", "DVDsize");
div.appendChild(input);
}
});
// manually trigger change event.
let selectTypeSwitcher = document.getElementById('selector');
if (selectTypeSwitcher) {
selectTypeSwitcher.dispatchEvent(new Event('change'));
}
<form method="POST" action="add.php">
<button class="accept-btn" type="submit">SAVE</button>
<!-- + -->
<button class="decline-btn">CANCEL</button>
<!-- + -->
</div>
</div>
<div class="input-main-add" id="input-main-add">
<!-- + -->
<div class="input-add-holder">
<H2 style="display:inline-block">SKU: </H2>
<input class="something" name="SKU" id="SKU"></input>
</div>
<div class="input-add-holder">
<H2 style="display:inline-block">Name: </H2>
<input class="something" name="name" id="name"></input>
</div>
<div class="input-add-holder">
<H2 style="display:inline-block">Type Switcher: </H2>
<select name="selector" id="selector">
<option value="DVD" id="DVD" name="DVD">DVD-Disk</option>
<option value="book" id="book" name="book">Book</option>
<option value="furniture" id="furniture" name="furniture">Furniture</option>
</select>
</div>
</div>
</form>
Run the code above while open network inspector and you will see DVDSize input send to the server.

Related

How to make a dropdown autocomplete navigable by keyboard

Here, I have a nice autocomplete dropdown that, given a city typed by the user, the page will show all possible city-state-country triplets. For example the name Guadalajara would suggest
Guadalajara de Buga, Valle del Cauca Department, Colombia
Guadalajara, Castilla La Mancha, Spain
and
Guadalajara, Jalisco, Mexico
The code works perfectly from both the backend and the frontend, the only problem left is that the autosuggest drop down menu will only work with the mouse and not with the keyboard. The Up and Down arrow keys will not allow to navigate through the most appropriate choice and pressing esc doesn't cancel the menu.
I tried everything and I have no idea about what is missing to make this work with the keyboard as well. I would like to find a solution with pure vanilla JavaScript and that would involve the least possible changes in the rest of working code. Here the entire code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vanilla Javascript Cities Test</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma#0.8.2/css/bulma.min.css">
</head>
<body id="body">
<div class="title has-text-centered" id="main"></div>
<section id="form" class="section" onclick="clearCities()">
<div class="container">
<h1 class="title">Vanilla Cities Javascript</h1>
<!-- Row for City, State and Country -->
<div id="location">
<div class="field">
<div class="control">
<div id="cities-dropdown" class="dropdown">
<div class="dropdown-trigger">
<input name="cities" id="cities" onkeyup="getCities()" maxlength="50" class="input" type="text" placeholder="Enter a city" aria-haspopup="true" aria-controls="dropdown-menu3" -autocomplete="off" required
>
</div>
<div class="dropdown-menu" id="dropdown-menu3" role="menu">
<div id="cities-dropdown-content" class="dropdown-content">
<!-- content -->
<a class="dropdown-item"></a>
</div>
</div>
</div> Clear
</div>
<span class="is-size-7 has-text-info">(If your location doesn't appear immediately, try to type slower).</span>
</div>
<!-- City Field -->
<div class="field">
<div class="control">
<input name="city" id="city" class="input" type="text" placeholder="City" required>
</div>
</div>
<!-- State Field -->
<div class="field">
<div class="control">
<input name="state" id="state" class="input" type="text" placeholder="State" required>
</div>
</div>
<!-- Country Field -->
<div class="field">
<div class="control">
<input name="country" id="country" class="input" type="text" placeholder="Country" required>
</div>
</div>
</div>
</div>
</section>
</body>
<script>
function getCities(){
var inputCity = document.getElementById('cities').value;
const city = changeCase(inputCity);
if(city.length <= 2){
return false;
}
// Create request to get cities locations
var request = new XMLHttpRequest();
request.addEventListener("load", transferComplete);
request.open("GET", "/cities/?cityname=" + city);
request.send();
// Called when transfer is complete
function transferComplete(event){
//alert(event.srcElement.response);
locations = JSON.parse(event.srcElement.response);
// Return false if no matching city was found
if(locations.length == 0){
return false;
}
// Append choices
dropContent = document.getElementById('cities-dropdown-content');
dropContent.innerHTML = "";
for (var i = 0; i < locations.length; i++) {
var link = document.createElement("a");
link.setAttribute("onclick", "setCity(" + JSON.stringify(locations[i].name) + "," + JSON.stringify(locations[i].state) + "," + JSON.stringify(locations[i].country) + ")");
link.setAttribute("class", "dropdown-item");
link.innerHTML = locations[i].name + ", " + locations[i].state.name + ", " + locations[i].country.name
dropContent.append(link);
}
document.getElementById("cities-dropdown").classList.add("is-active");
}
// document.getElementById("products-list").innerHTML = html;
}
function setCity(city, state, country){
document.getElementById('cities').value = city+', '+state.name+', '+country.name;
document.getElementById('city').value = city;
document.getElementById('state').value = state.name;
document.getElementById('country').value = country.name;
document.getElementById('cities-dropdown-content').innerHTML = "";
document.getElementById("cities-dropdown").classList.remove("is-active");
}
function clearCities(){
document.getElementById('cities-dropdown-content').innerHTML = "";
document.getElementById("cities-dropdown").classList.remove("is-active");
}
function deleteEntry(e){
e.preventDefault();
document.getElementById('cities').value = '';
}
function changeCase(inputCity){
return inputCity
.replace(/([a-z])([A-Z])/g, function (allMatches, firstMatch, secondMatch) {
return firstMatch + " " + secondMatch;
})
.toLowerCase()
.replace(/([ -_]|^)(.)/g, function (allMatches, firstMatch, secondMatch) {
return (firstMatch ? " " : "") + secondMatch.toUpperCase();
}
);
}
var eraser = document.getElementById("clear");
eraser.addEventListener('click', deleteEntry);
</script>
I hope to find the simpler and least invasive solution to complete a code that just have this left.
I would change your dropdown and input to the semantic html datalist element:
<label for="ice-cream-choice">Choose a flavor:</label>
<input list="ice-cream-flavors" id="ice-cream-choice" name="ice-cream-choice" />
<datalist id="ice-cream-flavors">
<option value="Chocolate">
<option value="Coconut">
<option value="Mint">
<option value="Strawberry">
<option value="Vanilla">
</datalist>
Then both search and keyboard accessibility should work more or less out of the box.
If you really don't want to do that, you have to attach event listeners (vanilla js) to the different elements of your dropdown and input field and write a rather long thing to be able to tab or arrow key your way down and up and back into the search field. I would say it's too much work compared to the reward.
Better to use some time to css-animate the datalist so it behaves a bit smoother and style it neatly.

how to add one on name attribute with javascript?

I have a dynamic form section which I need the name attribute to be dynamic as well.
the number should always get +1 each time the user create a new section !
name="training**1**[institut]"
This is crucial to have a proper SQL insert ... otherwise the array won't have a classical database logics !
JSFIDDLE here
Any idea ? thanks a lot from France !
<form method="post" action="">
<!-- INFO SECTION -->
<div id="infos">
<h2>Infos personnelles</h2>
<input placeholder="Prénom">
<input placeholder="Nom">
</div>
<!-- TRAINING SECTION -->
<div id="training">
<h2>Formation</h2>
<!-- Template -->
<div id="new-training" style="display:none">
<div>
</br>
<p></p>
<input id="mytext" type="text" name="training[1][institut]" placeholder="Diplôme" value="">
<input name="training[1][institut]" placeholder="Institut">
</div>
</div>
</div>
<p id="addnew">
+ Ajouter une formation
</p>
<p>
<br>
<input type="submit" value="Sauvergarder" name="submit">
</p>
</form>
<script> // 1st : Enregistrer / supprimer une formation
var ct = 1;
function addTraining()
{
ct++;
var div1 = document.createElement('div');
div1.id = ct;
// link to delete extended form elements
var delLink = 'Supprimer cette formation';
div1.innerHTML = document.getElementById('new-training').innerHTML + delLink;
document.getElementById('training').appendChild(div1);
}
function removeTraining(eleId)
{
d = document;
var ele = d.getElementById(eleId);
var parentEle = d.getElementById('training');
parentEle.removeChild(ele);
}
The best solution (my opinion) is to use a simple templating engine
https://jsfiddle.net/nget5dq2/1/
Addition to your HTML:
<template id="new_el_template" hidden>
<div id="row-{cid}">
<input id="mytext-{cid}" type="text" name="training[{cid}][institut]" placeholder="Diplôme" value="">
<input name="training[{cid}][institut]" placeholder="Institut">
</div>
Supprimer cette formation
</template>
JS
var ct = 1;
function addTraining() {
ct++;
let div = document.createElement('div');
div.innerHTML = document.getElementById('new_el_template').innerHTML.replace(/\{cid\}/gi, ct);
document.getElementById('training').appendChild(div);
}
function removeTraining(eleId) {
document.getElementById('row-' + eleId).parentNode.remove();
}
And yes, you can go ahead and generate the initial element directly from the template.
write the name attribute this way you should get all the data from the form when u post it.
<input id="mytext" type="text" name="training[diploma][]" placeholder="Diplôme" value="">
<input name="training[institut][]" placeholder="Institut">
Here is a working example with comments added throughout..
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<form method="post" action="">
<!-- INFO SECTION -->
<div id="infos">
<h2>Infos personnelles</h2>
<input placeholder="Prénom">
<input placeholder="Nom">
</div>
<!-- TRAINING SECTION -->
<div id="training">
<h2>Formation</h2>
<!-- Template -->
<div id="new-training" >
<div>
</br>
<p></p>
<input id="mytext" type="text" name="training[1][institut]" placeholder="Diplôme" value="">
<input name="training[1][institut]" placeholder="Institut">
</div>
</div>
</div>
<p id="addnew">
<a style="color: blue" onclick="addTraining()">+ Ajouter une formation</a>
</p>
<p>
<br>
<input type="submit" value="Sauvergarder" name="submit">
</p>
</form>
</body>
<script>
const addTraining = () => {
//Get parent container to place new input into
const parent = document.getElementById('training');
//Create DIV to wrap around input elements
let div = document.createElement('div')
//Create new input with a unique name attribute
let newInput1 = document.createElement('input');
let newInput2 = document.createElement('input');
//You can get an array of all existing elements and add 1 to create a unique name for each
let num = parent.querySelectorAll('div').length + 1,
newName = 'training['+ num +'][institut]';
//Set name attribute
newInput1.setAttribute('name', newName);
newInput2.setAttribute('name', newName);
//Set other attributes you alreadt had
newInput1.setAttribute('placeholder', 'Diplôme');
newInput2.setAttribute('placeholder', 'Institut');
newInput1.setAttribute('id', 'myText');
newInput1.setAttribute('type', 'text');
//Append elements
parent.appendChild(div);
div.appendChild(newInput1);
div.appendChild(newInput2)
}
</script>
</html>

Clone div not being removed, just the original one

I have a div being cloned and I would like the button remove to remove the selected div. It's only removing the html div that is used to clone the field.
See my code below:
JS
// Clones Schedule Field
function cloneField(){
const newFieldContainer = document.querySelector(".schedule-item").cloneNode(true)
console.log(newFieldContainer)
let fields = newFieldContainer.querySelectorAll('input')
fields.forEach(function(field){
field.value = ""
})
document.querySelector("#schedule-items").appendChild(newFieldContainer)
}
// Adds new field
function addButton(){
let button = document.querySelector("#add-time")
const selected = document.getElementById('select').selected
let scheduleItems = document.querySelector('#schedule-items')
let inputs = scheduleItems.querySelectorAll('input')
if(selected == true || [...inputs].some(input=>input.value === "")){
alert('Tem o dia ou a hora faltando nos Horários Disponíveis.')
button.removeEventListener('click',cloneField)
}else{
button.addEventListener('click',cloneField)
}
}
// Removed field added if needed
let buttonRemove = document.querySelector('.remove-schedule-item')
buttonRemove.addEventListener('click',removeField)
function removeField(){
let scheduleItem = document.querySelector('.schedule-item')
scheduleItem.parentNode.removeChild(scheduleItem);
console.log('hey')
}
HTML
<fieldset id="schedule-items">
<legend>Horários disponíveis
<button type="button" id="add-time" onclick="addButton()">+Novo horário</button>
</legend>
<div class="schedule-item">
<div class="select-block">
<label for="weekday">Dia da semana</label>
<select name="weekday[]" required="true">
<option id="select" value="select" selected>Selecione uma opção</option>
{%for weekday in weekdays %}
<option value="{{loop.index0}}">{{weekday}}</option>
{%endfor%}
</select>
</div>
<div class="input-block">
<label for="time_from">Das</label>
<input type="time" name="time_from[]" required>
</div>
<div class="input-block">
<label for="time_to">Ate</label>
<input type="time" name="time_to[]" required>
</div>
<div class="remove-schedule-item">
<button>remove</button>
</div>
</div>
</fieldset>
</form>
Thanks in advance
when you try to remove the item
function removeField(){
let scheduleItem = document.querySelector('.schedule-item')
scheduleItem.parentNode.removeChild(scheduleItem);
console.log('hey')
}
you are always selecting the first .schedule-item and then delete the first item
edit:
when you clone you element you need to add event listener to the new element
function cloneField(){
const newFieldContainer = document.querySelector(".schedule-item").cloneNode(true);
let fields = newFieldContainer.querySelectorAll('input')
fields.forEach(function(field){
field.value = ""
});
document.querySelector("#schedule-items").appendChild(newFieldContainer);
const removeBtn = newFieldContainer.querySelector('.remove-schedule-item');
if(removeBtn){
removeBtn.addEventListener('click',function(){
newFieldContainer.remove();
});
}
}

Activate textbox on change of an item in Drop down in HTML

I am trying to do the following:
I have drop down menu with four options in it. When I choose Shipped a text box should enabled. So I tried the following:
<div class="col-md-3">
<select class="form-control" id="ostatus" name= "ostatus">
<option value="Uploaded" <?php if ($dispatch_status == "Uploaded") echo "selected='selected'";?> >Uploaded</option>
<option value="Processing" <?php if ($dispatch_status == "Processing") echo "selected='selected'";?> >Processing</option>
<option value="Dispatched" <?php if ($dispatch_status == "Dispatched") echo "selected='selected'";?> >Dispatched</option>
<option value="Shipped" <?php if ($dispatch_status == "Shipped") echo "selected='selected'";?> >Shipped</option>
</select>
</div>
</div>
<input type="text" class="form-control" name="shipping_notes" disabled="true" id="shipping_notes" aria-describedby="" placeholder="Enter Shipping details">
Java script:
<head>
<script type="text/javascript">
document.getElementById('ostatus').addEventListener('change', function()
{
console.log(this.value);
if (this.value == 'Shipped') {
document.getElementById('shipping_notes').disabled = false;
} else {
document.getElementById('shipping_notes').disabled = true;
}
});
</script>
</head>
Doesn't seem to trigger? I don't see log on console too. What could be wrong here?
Update:
I have pasted the html code here:
https://justpaste.it/6zxwu
Update
Since you've now shared your other code I think I know what you want. You have multiple modals, each with a select list and shipping_notes textbox which should be enabled when the selection is Shipped for that particular modal. I've modified your HTML to get this working.
I've updated your HTML a bit. You have multiple elements with the same ID. HTML IDs should be unique. If you want to target multiple elements it's safer to use class (or data-) attributes. I've added class="order-status" to each select and class="shipping_notes_txt" to each textbox. I've used element.querySelector() and document.querySelectorAll() to select DOM elements.
The snippet below mimics two modals. When the select is updated, it only enables/disabled the textbox within the same form element.
// wait for the DOM to load
document.addEventListener('DOMContentLoaded', function() {
// get all select elements with class=order-status
var selects = document.querySelectorAll('.order-status');
// iterate over all select elements
for (var i = 0; i < selects.length; i++) {
// current element
var element = selects[i];
// add event listener to element
element.addEventListener('change', function()
{
console.log(this.value);
// get the form closest to this element
var form = this.closest('form');
// find the shipping notes textbox inside form and disable/enable
if (this.value == 'Shipped') {
form.querySelector('.shipping_notes_txt').disabled = false;
} else {
form.querySelector('.shipping_notes_txt').disabled = true;
}
});
// default value if status == Shipped: enable textbox
if (element.value == "Shipped")
{
var form = element.closest('form');
form.querySelector('.shipping_notes_txt').disabled = false;
}
}
});
.modal1 {
display:inline-block;
vertical-align:top;
padding: .5em;
padding-bottom:5em;
border: 1px solid black;
}
<div class="modal1">
<h3>First Modal</h3>
<div id="edit1" class="modal fade" role="dialog">
<form action="order.php" autocomplete="off" method="post">
<div class="col-md-2 ml-3 pt-1">
<label for="role" class="mr-3">Status</label>
</div>
<select class="form-control order-status" id="ostatus1" name= "ostatus">
<option value="Uploaded" selected='selected' >Uploaded</option>
<option value="Processing">Processing</option>
<option value="Dispatched">Dispatched</option>
<option value="Shipped">Shipped</option>
</select>
<input type="text" class="form-control shipping_notes_txt" name="shipping_notes" disabled="true" id="shipping_notes1" aria-describedby="emailHelp" placeholder="Enter Shipping details">
</form>
</div>
</div>
<div class="modal1">
<h3>Second Modal</h3>
<div id="edit20" class="modal fade" role="dialog" >
<form action="order.php" autocomplete="off" method="post">
<div class="col-md-2 ml-3 pt-1">
<label for="role" class="mr-3">Status</label>
</div>
<select class="form-control order-status" id="ostatus20" name= "ostatus">
<option value="Uploaded" >Uploaded</option>
<option value="Processing">Processing</option>
<option value="Dispatched">Dispatched</option>
<option value="Shipped" selected='selected' >Shipped</option>
</select>
<input type="text" class="form-control shipping_notes_txt" name="shipping_notes" disabled="true" id="shipping_notes20" aria-describedby="emailHelp" placeholder="Enter Shipping details">
</form>
</div>
</div>
Add onchange to your <select>
<select class="form-control" id="ostatus" name= "ostatus" onchange = "statuschange()">
And change the JavaScript to :
<script type="text/javascript">
function statuschange(){
var drpDownValue = document.getElementById('ostatus').value;
if (drpDownValue == 'Shipped')
{
document.getElementById('shipping_notes').disabled = false;
}
else
{
document.getElementById('shipping_notes').disabled = true;
}
}
</script>
assuming everything on the server side this works HTML comes first
<div class="col-md-3"> <select class="form-control" id="ostatus" name= "ostatus">
<option value="Uploaded" selected="selected" >Uploaded</option>
<option value="Processing" >Processing</option>
<option value="Dispatched" >Dispatched</option>
<option value="Shipped" >Shipped</option>
</select>
</div>
</div>
<input type="text" class="form-control" name="shipping_notes" disabled="true" id="shipping_notes" aria-describedby="" placeholder="Enter Shipping details">
document.getElementById('ostatus').addEventListener('change', function()
{
console.log(this.value);
if (this.value == 'Shipped') {
document.getElementById('shipping_notes').disabled = false;
} else {
document.getElementById('shipping_notes').disabled = true;
}
});

javascript appendChild show the list item then make it disappear

<div id="task-list"> <!-- Table that show tasks -->
<ul id="list"> <!--Blank table that uses JavaScript to add tasks -->
</ul>
<input type="image" src="image/plus.svg" class="add-btn-hidden" onclick="addButton()" >
</div>
<div id="hidden-add-form">
<form>
<h2 id="form-header">Add New Task</h2>
<button id="cancel" onclick="cancelButton()">X</button>
<br>Name<br>
<input type="text" id="task-name"><br>
<div class="same-line-input">
<span id="place">Place</span> <span id="department">Department</span><br>
<input type="text" id="task-place">
<select id="select">
<option value="Blank"></option>
<option value="Cleanning">Cleaning</option>
<option value="Kitchen">Kitchen</option>
<option value="Receptionist">Receptionist</option>
<option value="Beltboy">Bellboy</option>
<option value="All">All</option>
</select><br>
</div>
Description<br>
<textarea rows="10" cols="50" id="description"></textarea><br>
<input type="radio" name="urgent" value="other" id="urgent-btn"> Urgent<br>
Attachment:<br><input type="file" name="fileToUpload" id="fileToUpload"><br>
<input type="submit" id="form-submit" onclick="addTask ()">
</form>
</div>
Javascript:
function addButton (){
document.getElementById("hidden-add-form").style.visibility = "visible";
};
function cancelButton(){
document.getElementById("hidden-add-form").style.visibility= "hidden";
};
function addTask (){
let ul = document.getElementById("list");
let name = document.getElementById("task-name");
let place = document.getElementById("task-place");
let department = document.getElementById("select");
let description = document.getElementById("description");
let nameValue = "Name: " + name.value;
let li = document.createElement("li")
li.setAttribute("id", "task-on-list");
li.appendChild(document.createTextNode(nameValue));
ul.appendChild(li);
};
Functions addButton() and cancelButton() work fine but the addTask() function shows the new list-item real quick then the list item disappear. I wanted to pass the information from the form to show it in a list item of an unordered list. nameValue is just a part of my experiment

Categories