I have a list of and fields where users enter the name of an item and the quantity. The PHP function
generateMaterialsTable();
is responsible for generating one text field and one number field if there are no existing records in the database. If there are multiples, the function shows all items and their corresponding quantities. Here is the PHP code:
function generateMaterialsTable($month_id, $table, $item, $addOrEdit){
global $mysqli;
$item_singular = substr($item, 0, strlen($item)-1);
$item_singular_title = $item_singular.'_title';
if($addOrEdit == 'Edit'){
$materials_query = "SELECT * FROM archivestats.".$table."_".$item." WHERE month_id = '$month_id'";
$materials_result = $mysqli->query($materials_query);
if($materials_result->num_rows > 0){
$counter = 1;
while($materials_match = $materials_result->fetch_assoc()){
$output .= '
<div class="form-group '.$item_singular.'-row row">
<div class="col-sm-8">
<input type="text" name="'.$item_singular.'[]" class="form-control item-field" value="'.htmlentities($materials_match[$item_singular_title]).'">
</div>
<div class="col-sm-4">
<input type="number" name="'.$item_singular.'qty[]" class="form-control align-right '.$item_singular.'qty" value="'.$materials_match['quantity'].'">
</div>
</div>
';
$counter++;
}
} else {
$output .= '
<div class="form-group '.$item_singular.'-row row">
<div class="col-sm-8">
<input type="text" name="'.$item_singular.'[]" class="form-control item-field" value="">
</div>
<div class="col-sm-4">
<input type="number" name="'.$item_singular.'qty[]" class="form-control align-right '.$item_singular.'qty" value="">
</div>
</div>
';
}
}
return $output;
}
The user also has the option to add a new text and quantity field. This is done via the following JQuery:
//WHEN USER CLICKS '+Add Another Field'
$('.new-field').click(function(){
var newFieldId = $(this).attr('id'); //find id of the '+Add Another Field' paragraph
var newField = newFieldId.substr(0, newFieldId.lastIndexOf('-')); //find the name of the field before the last - (eg. 'book' from 'book-new')
var fields = $(this).parents().siblings().closest('.'+newField+'-row').find('input[type="text"]');
var count = 0;
$(fields).each(function(){
//we only need to get information for the last text box in the bunch
if(count == fields.length-1){
var last_field = $(this).attr('name'); //the name attribute of the last text box
var field_name = last_field.substr(0, last_field.indexOf('[')); //find the name of the field before a _ (eg. 'book' from 'book_1')
var regEx = /\d+/; //find the number of the field contained in the name (eg. '1' from 'book_1')
var field_number = parseInt(last_field.match(regEx));
$(this).parent().parent().after('<div class="form-group '+ field_name +'-row row"> <div class="col-sm-8"><input type="text" name="'+ field_name +'[]" class="form-control item-field"></div><div class="col-sm-4 add-field"><input type="number" name="'+ field_name +'qty[]" class="form-control align-right ' + field_name + 'qty"></div></div>');
}
count++; //iterate our counter
});
}); //end .new-feild.click()
For whatever reason, when I go to submit the form, the array as defined in
name="'.$item_singular.'[]"
only works properly with one group of text fields - that is, it properly records all array items. For example, let's say I have the following:
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="book[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="bookqty[]" class="form-control align-right bookqty">
</div>
</div>
</div>
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="book[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="bookqty[]" class="form-control align-right bookqty">
</div>
</div>
For this, I will input values of EXAMPLE 1 / 4 and EXAMPLE 2 / 15. When I submit and do:
print_r($_POST['book'])
I get the proper value of
Array([0] => "Example 1", [1] => "Example 2")
But then in another section of that EXACT SAME FORM I do this:
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="digbook[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="digbookqty[]" class="form-control align-right digbookqty">
</div>
</div>
</div>
<div class="form-group book-row row">
<div class="col-sm-8">
<input type="text" name="digbook[]" class="form-control item-field">
</div>
<div class="col-sm-4">
<input type="number" name="digbookqty[]" class="form-control align-right digbookqty">
</div>
</div>
</div>
For this, I will input values of EXAMPLE 3 / 1 and EXAMPLE 4 / 20. Now I'll get ONLY the first item in the array:
Array([0] => "Example 3")
This makes absolutely no sense and it is driving me crazy. It is the exact same function spitting out the exact same code with two completely different results. Unreal...
Related
const form = document.querySelector("#user-form");
const userInput = document.querySelector("#name", "#surname", "#age", "#country");
const userList = document.querySelector(".list-group");
const firstCardBody = document.querySelectorAll(".card-body")[0];
const secondCardBody = document.querySelectorAll(".card-body")[1];
const filter = document.querySelector("#filter");
const clearButton = document.querySelector("#clear-users");
<form id="user-form" name="form">
<div class="form-row">
<div class="form-group col-md-6">
<input class="form-control" type="text" name="name" id="name" placeholder="İsim">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="surname" id="surname" placeholder="Soyadı">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="age" id="age" placeholder="Yaş">
</div>
<div class="form-group col-md-6">
<input class="form-control" type="text" name="country" id="country" placeholder="Ülke">
</div>
</div>
<button type="submit" class="btn btn-primary">Bilgilerinizi Kaydedin</button>
</form>
My form looks like this.
But when I run my JS code, it only shows me the name not surname, age or country. How do I display all of them?
enter image description here
document.querySelector cannot be use the way you use it as it returns the first matched element (in your case the name input). To get all input fields you can do it like this:
const userInput = document.querySelectorAll(".form-control");
This returns all 4 input fields in an array which can be iterated via
userInput.forEach(input => { ... });
Get a specific element like this:
Array.from(userInput).find(input => input.id === "name");
Another approach would be to get the input fields via their ID's:
const name = document.querySelector("#name");
const surname= document.querySelector("#surname");
const age = document.querySelector("#age");
const country = document.querySelector("#country");
I have created two text boxes and wrote the JSfunction to give alert msg that both the boxes together should be of 50 characters. Function called in onclick() event in Submit button. Also in controller Store() function, save the content of these two text boxes and validated with "required", then redirected to another page.
Problem is, if I give less than 50 characters it shows alert msg, but store the data even less than 50 characters given and redirected to specified page. If i give less than 50 characters, after showing the alert msg, it has to be in the same page until i give together 50 characters. It should ave the textboxes content only if more than 50 characters. Can anyone help me?
In create.blade.php
<form method="post" action="{{route('training.applicants.aim.create.process', $request->training_request_id)}}">
<div class="form-group" id="goal_group" >
<label class="col-form-label font-weight-bold" for="ziele[1]">Ziele 1</label>
<input type="text" name="ziele[1]" class="form-control form-control-sm #error('ziele.1') is-invalid #enderror" id="ziele.1" >
#error('ziele.1') <div class="invalid-feedback">{{ $errors->get('ziele.1')[0] }}</div> #enderror
</div>
<div class="form-group">
<label class="col-form-label font-weight-bold" for="ziele[2]">Ziele 2</label>
<input type="text" name="ziele[2]" class="form-control form-control-sm #error('ziele.2') is-invalid #enderror" id="ziele.2" >
#error('ziele.2') <div class="invalid-feedback">{{ $errors->get('ziele.2')[0] }}</div> #enderror
</div>
<div id="additional_goals"></div>
<hr/>
<div class="form-group row container-fluid" >
<div class="col">
<div class="col-2 float-right">
<br>
<button type="submit" style="position: absolute; right:0" class="btn btn-sm btn-primary" id="submit_btn" onclick="goal_validation()"> Submit </button>
</div>
</div>
</form>
Js function:
function goal_validation()
{
var l1=document.getElementById('ziele.1').value;
var l2=document.getElementById('ziele.2').value;
var Total=50-(l1.length +l2.length);
if(Total<50 && Total>0)
{
alert("U have to give minimum "+Total+" characters");
}
}
In controller store function:
public function storeGoals(TrainingRequest $antrag, Request $request)
{
$request->validate([
//'ziele.*' => 'required|string',
'ziele.1' => 'required|string',
'ziele.2' => 'required|string',
]);
$antrag->goals = isset($request->ziele) ? $request->ziele : NULL;
$antrag->save();
return redirect()
->route('Training.participation.mein', $request)
->with('Message', $Message);
}
You can try use strlen() function to find character length.
$request->validate([
//'ziele.*' => 'required|string',
'ziele.1' => 'required|string',
'ziele.2' => 'required|string',
]);
length1= strlen($request->ziele.1);
length2= strlen($request->ziele.2);
if((length1+length2) >= 50){
$antrag->goals = isset($request->ziele) ? $request->ziele : NULL;
$antrag->save();
return redirect()
->route('Training.participation.mein', $request)
->with('Message', $Message);
}
else{
return redirect()->back();
}
In the form I am making, there is a section that requires users to enter the amount of people in their family. After they provide it, the form generates enough input fields so that the user can enter information for each family member.
What I am having trouble with is none of the attributes that I am trying to apply to the input element actually work.
function addHouseMembers(that){
var family = document.getElementById("family-input-container");
while(family.hasChildNodes()){
family.removeChild(family.lastChild);
}
for(var i = 1; i < that.value; i++){
family.appendChild(document.createTextNode("Family Member " + (i+1)));
family.appendChild(document.createElement("br"));
//name
family.appendChild(document.createTextNode("Name: " ));
var input = document.createElement("input");
input.type = "text";
input.name = "member" + i + "_name";
input.pattern = "/^[a-zA-Z ]*$/";
input.required = true;
family.appendChild(input);
family.appendChild(document.createElement("br"));
}
}
The parameter that refers to the input where the user would put in the number of people in their family.
And here is the relevant HTML:
<form>
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input type="text" class="form-control" name="household-size" required onchange="addHouseMembers(this);"/>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group" id = "family-input-container" required>
</div>
</div>
</div>
</form>
The element shows up as it should, and is submitted with the form when the user hits the submit button, but the regex pattern and required attributes are not enforced.
in addHouseMembers(that) the value of that is a string, not a number, and you have to check if is value can be 'translated' in an integer value.
use the "onchange" event on the input field household-size is not a good idea because this event is triggered each time a digit of the number entered, which has the effect of erasing and completely rewrite the family-input-container part
I Imagine you are looking for something like that ?
const myForm = document.getElementById('my-form')
, familyElm = document.getElementById('family-input-container')
, parserDOM = new DOMParser()
;
function newHouseMember(ref)
{
let div=
` <div>
Family Member ${ref}<br>Name: <br>
<input type="text" name="member${ref}_name" pattern="/^[a-zA-Z ]*$/" required >
</div>`
return parserDOM.parseFromString( div, 'text/html').body.firstChild
}
myForm.btPeoples.onclick=_=>
{
let nbPeoples = parseInt(myForm['household-size'].value)
if (!isNaN(nbPeoples) && nbPeoples > 0 )
{
familyElm.innerHTML = ''
for (let i=1; i<=nbPeoples; i++)
{
familyElm.appendChild( newHouseMember(i) )
}
}
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" >
<form id="my-form">
<div class="form-group">
<label class="col-lg-3 control-label">What is the total amount of people living in your household?</label>
<div class="col-lg-3 inputGroupContainer">
<div class = "input-group">
<input class="form-control" name="household-size" required value="" placeholder="number of peoples" pattern="\d*" />
<button name="btPeoples" class="btn btn-info" type="button" >check it!</button>
</div>
</div>
</div>
<div class="form-group", id="family-info">
<label class="col-lg-12">Information for other Family Members</label>
<div class="col-lg-3 inputGroupContainer">
<div class="input-group" id="family-input-container">
</div>
</div>
</div>
</form>
I have a customer registration form, it has a button for adding additional phone number fields. After submitting the form and validating the input, the page needs to recreate the same forms with the old inputs. I made the below solution, I would like to know if this is an efficient way and also if I can not create the empty lines, since currently it will recreate all fields even if they were empty.
html
<h3>{{__('Phone Numbers')}} <button type="button" id="addPersonPhone">+</button></h3>
<input type="hidden" name="personPhoneLines" id="personPhoneLines" value="{{(old('personPhoneLines')? old('personPhoneLines') : 1)}}">
<div id="personPhone">
<div class="form-group row">
<div class=" col-2">
<label class="col-form-label col-form-label-sm" for="personPhoneType-1">{{__('Type')}}</label>
<select class="custom-select form-control-sm" id="personPhoneType-1" name="personPhoneType-1">
<option selected value=''>{{__('Choose')}}...</option>
#foreach ($phonetypes as $phonetype)
<option value="{{$phonetype->id}}" {{(old( 'personPhoneType-1')==$ phonetype->id)? "selected":""}}>{{$phonetype->name}}</option>
#endforeach
</select>
</div>
<div class="col-3">
<label class="col-form-label col-form-label-sm" for="personCountryCode-1">{{__('Country')}}</label>
<select class="custom-select form-control-sm" id="personCountryCode-1" name="personCountryCode-1">
<option selected value="">{{__('Choose')}}...</option>
#foreach ($countries as $country)
<option value="{{$country->id}}" {{(old( 'personCountryCode-1')==$ country->id)? "selected":""}}>{{$country->name.' (+'.$country->dialing_code.')'}}</option>
#endforeach
</select>
</div>
<div class="col-4">
<label class="col-form-label col-form-label-sm" for="personPhoneNo-1">{{__('Number')}}</label>
<div class="input-group mb-2">
<input type="text" class="form-control form-control-sm" placeholder="{{__('Number')}}" name="personPhoneNo-1" id="personPhoneNo-1" value="{{old('personPhoneNo-1')}}">
</div>
</div>
</div>
javascript
var phoneLines = parseInt($("#personPhoneLines").val(), 10);
var phoneRow = $('#personPhone').html();
var oldPersonPhones =["{{old('personPhoneNo-1')}}", "{{old('personPhoneNo-2')}}",
"{{old('personPhoneNo-3')}}", "{{old('personPhoneNo-4')}}", "{{old('personPhoneNo-5')}}"];
for (i = 2; i <= phoneLines; i++) {
newLine = phoneRow.split('personPhoneType-1').join('personPhoneType-' + i);
newLine = newLine.split('personCountryCode-1').join('personCountryCode-' + i);
newLine = newLine.split('personPhoneNo-1').join('personPhoneNo-' + i);
$("#personPhone").append(newLine);
$("#personPhoneNo-" + i).val(oldPersonPhones[i-1]);
}
$('#addPersonPhone').click(function(){
if (phoneLines >=5) {
alert('You cannot add more than 5 lines')
} else {
phoneLines = phoneLines + 1;
newLine = phoneRow.split('personPhoneType-1').join('personPhoneType-'+phoneLines);
newLine = newLine.split('personCountryCode-1').join('personCountryCode-'+phoneLines);
newLine = newLine.split('personPhoneNo-1').join('personPhoneNo-'+phoneLines);
$("#personPhone").append(newLine);
$("#personPhoneLines").val(phoneLines);
}
});
Best practice would be to change your input name to an array like this:
<select name="people[phone_type][]"></select>
<select name="people[phone_country_code][]"></select>
<input type="text" name="people[phone_number][]">
This way you can simply duplicate the fields, without needing to name them after something.
Then in your validation you can refer to docs for your fields: https://laravel.com/docs/5.6/validation#validating-arrays
And to parse in your controller simply loop them to get the array you need.
Have a form to create a contract, where that contract can have one or more users associated.
The area to input the users info, starts with only one field of one user, and one button to add more fields if needed.
<div id="utilizadores" class="row">
<div id="utilizador1" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador1" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador1" placeholder="Função">
</div>
</div>
</div>
</div>
This is the starting div
Clicking on Add User button it adds a new div under the "utilizador1"
<div id="utilizadores" class="row">
<div id="utilizador1" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador1" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador1" placeholder="Função">
</div>
</div>
</div>
<div id="utilizador2" class="container-fluid">
<div class="row">
<div class="col-lg-5">
<input type="text" class="form-control" id="nomeUtilizador2" placeholder="Nome Utilizador">
</div>
<div class="col-lg-6">
<input type="text" class="form-control" id="funcaoUtilizador2" placeholder="Função">
</div>
</div>
</div>
My question is, how can I get the number of users created, and insert them into a list using Javascript. The list will be a attribute of a Object (Contract).
What i have til now:
function test_saveItem() {
var contract = new Object();
contract.Dono = <% =uID %>;
contract.BoostMes = $("#boostMes").val();
contract.BoostAno = $("#boostAno").val();
var ListaUtilizadores = [];
var divs = document.getElementsByName("utilizador");
for (var i = 0; i < divs.length; i++){
var user = new Object();
user.Nome = $('#nomeUtilizador' + i).val();
ListaUtilizadores.push(user);
}
var test = JSON.stringify({ "contract": contract });
}
Any help appreciated
Edit: Got to a solution thanks to Shilly
List = [];
Array.prototype.slice.call(document.querySelectorAll('.user')).forEach(function (node, index) {
List.push({
"name" : document.getElementById('nameUser' + (index + 1)).value,
"job" : document.getElementById('jobUser' + (index + 1)).value
});
});
Something like this? But adding it into the addUser function as Super Hirnet says, will be more performant.
var divs = document.querySelector('#utilizadores').childNodes,
users = [];
Array.slice.call(divs).forEach(function (node, index) {
users.push({
"name" : divs[index].getElementById('nomeUtilizador' + (index + 1)).value
});
});
You can have an empty array and on every click of addUser put a new object into the array. The object can have information related to the added user.