Hi I'm having my personal experiment with arrays what I was trying to do is to rename the index of the array from the result of my text field that dynamically adds using Javascript(I dont want to use jquery or other libraries like angular js). See image below for the UI
the problem is that the output looks like this
I want to be able to rename the index of the array generated(THIS IS WHAT I WANT FYI)
btw PHP handles my data and Javascript obviously handles my textfield manipulation
see my code
Javascript
var countBox =1;
var boxName = 0;
var boxName2 = 0;
function addInput()
{
var boxName="index"+countBox;
var boxName2="value"+countBox;
document.getElementById('response').innerHTML+='<input type="text" name="aindex" id="'+boxName+'" value="'+boxName+'" " /><input type="text" name="avalue[]" id="'+boxName2+'" value="'+boxName2+'" " /><br/>';
countBox += 1;
}
PHP
if(isset($_POST['save'])){
$b = $_POST['avalue'];
$results = print_r( $b, true);
file_put_contents( $filepath, print_r($b, true));
}
From your HTML, it appears you want to have pairs of form fields to hold keys and values? If so, just set the name of your all of your key fields to "keys[]" and all the value fields to "values[]" which when submitted will provide two arrays to your backend service.
Related
I have been stuck on this for a few days now and could use some expert advice!
So, as a personal/learning project I'm making a fun little 'character relationship tracker' for my friends' D&D games. With this, I have a DB table of dummy dungeon masters as well as the game(s) they are running for the purpose of testing code. I am trying to create a cascading dropdown list generated from a mix of PHP and encoded to JSON as part of the submit new character form. It works! Except, in the database containing the info for the options, some have only one game in the list for a DM while others have multiple games for the same DM. For those singles, the JS is listing out every single letter as a different choice instead of just the single full option. I have tried remaking the PHP twice to try resolving this and shuffled through a handful of JS attempts to no avail. These changes have either broken the code completely or resulted in no changes.
This fiddle is what it is doing with my best attempt
as for the actual code:
HTML
<div class="selectdiv">
<select name="chargm" id="charadm" onChange="chgm(this.value);" required>
<option value="" selected="true" disabled>Game Master</option>
<?php foreach ($gameMasters as $masterName) { echo "<option value='". $masterName . "'>" . $masterName . "</option>"; } ?>
</select>
</div>
<div class="selectdiv">
<select name="chargame" id="chargm" required>
<option value="" selected="true" disabled>Game Name</option>
</select>
</div>
here is the PHP (I know it's super messy and redundant but I couldn't get it to work any other way for some reason and it does its job?)
//database connection stuff
$sqls = "SELECT * FROM datgames;";
$stmts = mysqli_query($conn, $sqls);
$resultcheck = mysqli_num_rows($stmts);
$gameMasters = array(); //create empty array of game masters.
$gameData = array(); //set up game list data array
//check if db can be read before contiuning.
if($resultcheck > 0){
while($row = mysqli_fetch_assoc($stmts)){ //while there are rows, add to array
$gameMasters[] = $row["datgamDM"]; //fill the gameMasters array with all gm's
$gmdm = $row["datgamDM"]; //define gmdm as the game master of the row
//copy existing info in gameData to preserve data
$anotm = $gameData;
//clear game data to reset it to avoid repeats
unset($gameData);
//create the key => value pair
$tmpar[$gmdm] = $row["datgamName"];
//merge the temp arrays and apply them to the global array
$gameData = array_merge_recursive($anotm, $tmpar);
//clear the temporary arrays to avoid repeats
unset($anotm);
unset($tmpar);
}
}else{ exit(); } //if db can't be reached, break the code.
$gameMasters = array_unique($gameMasters);
//print_r($gameData); //making sure the array is right. this line is removed once this is working
and the exact JSON output from the PHP currently with this loop
{
"Reid":[
"Curse of Strahd",
"ufkck"],
"bob":[
"Curse of Strahd",
"fffs"]
,"jomama":"blaal",
"taco":"salff"
};
and the JS adapted from divy3993's answer here
var list = <?php echo json_encode($gameData); ?>;
function chgm(value) {
if (value.length == 0) document.getElementById("chargm").innerHTML = "<option></option>";
else {
var games = "";
for (categoryId in list[value]) {
games += "<option>" + list[value][categoryId] + "</option>";
}
document.getElementById("chargm").innerHTML = games;
}
}
The question in short: What am I doing wrong in either PHP (most likely the cause) or Javascript that is causing the words in single-object groups to split into letters instead of showing the full word as the only option for the second drop down option?
Or rather, how do I get the PHP to make single-entries to show up as a multidimensional array while keeping the key so it shows up as an array in the JSON object?
The trouble with using array_merge_recursive() is that it can produce an inconsistent structure as it creates depth.
For instance, see that a 1st level key contains an indexed subarray if there is more than one element, but creates an associative array on the first level when only one element exists. I explain this here and provide a simple demonstration.
A result set from mysqli's query() is instantly traversable using foreach(), so I recommend that concise technique which sets up intuitive associative array accessing.
$result = [];
foreach ($conn->query("SELECT datgamDM, datgamName FROM datgames") as $row) {
$result[$row["datgamDM"]][] = $row["datgamName"];
}
exit(json_encode($result));
This way, you have a consistent structure -- an associative array of indexed arrays. In other words:
{
"Reid":["Curse of Strahd","ufkck"],
"bob":["Curse of Strahd","fffs"],
"jomama":["blaal"],
"taco":["salff"]
}
Then life only gets easier. You only need to iterate like:
for (index in list[value]) {
As for the technique that you are using to generate the select/option markup -- that's not the way I would do it, there are multiple ways to do it, there are TONS of pages on StackOverflow that explain these options for you.
I generally don't like the UI of providing form instructions or labels as the top option of a field. I recommend that you give your form fields <label>s so that the options only contain real options.
As a completely different alternative, if you don't want to keep modifying the DOM every time the user makes a selection change, you could print ALL of the secondary select fields with their options preloaded, then "hide" them all. Then as the user changes the primary select field, merely "show" the field with the related id. This does of course create more html markup (which may or may not be attractive depending on your data volume), but it greatly reduces the complexity of the javascript code since all of the dynamic processing is done on page load. If one day, you wanted to make your primary select field a "multi-select", then having toggle-able secondary fields will work nicely. ..."horses for courses" and all that.
don't take my comments too serious
// is your old code
/// are my comments
var list = {
"Reid": ["Curse of Strahd", "uuck"],
"bob": ["Curse of Strahd", "fffts"],
"jomama": "blaal",
"taco": "salff"
};
function chgm(value) {
// if (value.length == 0) document.getElementById("chargm").innerHTML = "<option></option>";
/// do not use == use ===
/// avoid innerHTML
var node = document.getElementById("chargm");
var option;
if (!value) {
node.appendChild( document.createElement('options') );
return;
}
//else {
/// pls do not append to a string!
/// imagine you have 7000 values, the OS have everytime to get the string size AND
/// (re-)allocate new memory!!
// var games = "";
/// var games = []; // use an array instead of!
/// use of instead of in, if you want to use in, you have to make sure if list.hasOwnProperty(value) is true
// for (gameMas in list[value]) {
/// for (var gameMas of Object.keys(list)) {
/// but we know already what we are looking for, so let's check for that:
if (list.hasOwnProperty(value)) {
// ok we have now other new values, but what's with the other ones?
// lets kill everything for lazyness
while(node.firstChild && node.removeChild(node.firstChild));
/// reset the header
node.appendChild( document.createElement('option') ).innerText = 'Game / RP Name';
// games += "<option>" + list[value][gameMas] + "</option>";
/// your example array is inconsistent, so we have to check for the type
if (!Array.isArray(list[value])) {
/// with an array do this:
/// games.push('<option>' + list[gameMas] + '</option>');
option = node.appendChild( document.createElement('option') );
option.innerText = list[value];
option.value = list[value];
return;
}
/// else
for (var v of list[value]) {
/// with an array do this:
/// games.push('<option>' + list[gameMas][value] + '</option>');
option = node.appendChild( document.createElement('option') );
option.innerText = v;
option.value = v;
}
}
// document.getElementById("chargm").innerHTML = games;
/// with an array do this:
/// document.getElementById("chargm").innerHTML = games.join('');
}
<select name="chargm" id="charadm" onChange="chgm(this.value);">
<option value="" selected="true" disabled="">DM/Admin</option>
<option value="Reid">Reid</option>
<option value="bob">bob</option>
<option value="jomama">jomama</option>
<option value="taco">taco</option>
</select>
<select name="chargame" id="chargm">
<option value="" selected="true" disabled>Game / RP Name</option>
</select>
Below is a javascript which is able to get the input value & needs external libraries.
I know this seem odd but I have to use javascript to grab the price from the input title and no external libraries is required. Is it possible to work from input title ?
<?php
include_once('database_conn.php');
$sqlCDs = 'SELECT CDID, CDTitle, CDYear, catDesc, CDPrice FROM nmc_cd b inner join nmc_category c on b.catID = c.catID WHERE 1 order by CDTitle';
$rsCDs = mysqli_query($conn, $sqlCDs);
while ($CD = mysqli_fetch_assoc($rsCDs)) {
//have a look at the input field below
echo "\t<div class='item'>
<span class='CDTitle'>{$CD['CDTitle']}</span>
<span class='CDYear'>{$CD['CDYear']}</span>
<span class='catDesc'>{$CD['catDesc']}</span>
<span class='CDPrice'>{$CD['CDPrice']}</span>
<span class='chosen'><input type='checkbox' id="yourId" name='CD[]' value='{$CD['CDID']}' title='{$CD['CDPrice']}' /></span>
</div>\n";
}
?>
JS:
function isChecked(chosen) {
//and here it is called again
var valOfTitle = document.selectElementById("yourId").getAttribute('title');
var number = parseFloat(valOfTitle);
if(chosen.is(':checked')) {
sum = sum + parseFloat(valOfTitle);
} else {
sum = sum - parseFloat(valOfTitle);
}
$('#total').valOfTitle(sum.toFixed(2));
};
Just use getAttribute if you dont want to use any external libraries.
element.getAttribute("title")
i hope i understood you correctly:
you can access the data in your input field via jQuery's attr() method.
// "valOfTitle" is just a name..could also be "george" or "germany"
// "yourInputElementId needs to be the id of your element (written in
// "")
var valOfTitle = $(yourInputElementId).attr('title');
without jQuery:
var valOfTitle = document.selectElementById(yourInputFieldId).getAttribute('title');
if you want it as a number you can just do:
var number = parseFloat(valOfTitle);
if you don't want to add an id to your element you also can use another javascript selector, p.e. getElementsByName- but note: this will return a HTML Collection and not a single element, which means you will have to loop over this collection to access your data.
http://www.w3schools.com/jsref/met_doc_getelementsbyname.asp
maybe this google search may help you too:
https://www.google.de/search?q=javascript+selectors&oq=javascript+selectors&aqs=chrome..69i57.4015j0j7&sourceid=chrome&es_sm=91&ie=UTF-8#q=pure+javascript+selectors
or even
How can I use the jQuery-like selector in pure JavaScript
I have an input tag that takes a users input that calls an AJAX dynamically outputs suggestions from my database. The issue is I want to store the primary key associated with that attribute.
I have figured out a way set it to the primary key when the user selects a value; however I would rather only have the attribute displayed on the front end. Essentially what I was thinking about doing was using the option tag and setting the value to the primary key, but after reading the documentation for it, that doesnt look like it would work.
HTML:
<input type="text" id = "zip_id" class="tftextinput2" autocomplete = "off" name="zip" placeholder="Zip Code" onkeyup = "autocompleter()">
<ul id = "zip_codes_list_id"></ul>
JS:
function autocompleter()
{
var min_length = 1; // min caracters to display the autocomplete
var keyword = $('#zip_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'ajax_refresh.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#zip_codes_list_id').show();
$('#zip_codes_list_id').html(data);
}
});
} else {
$('#zip_codes_list_id').hide();
}
}
// set_item : this function will be executed when we select an item
function set_item(item)
{
// change input value
$('#zip_id').val(item);
// hide proposition list
$('#zip_codes_list_id').hide();
}
PHP:
<?php
//connect to db here
$keyword = '%'.$_POST['keyword'].'%';
$sql = "SELECT * FROM zip_codes WHERE zip LIKE (:keyword) ORDER BY zip_codes_id ASC LIMIT 0, 10";
$query = $pdo->prepare($sql);
$query->bindParam(':keyword', $keyword, PDO::PARAM_STR);
$query->execute();
$list = $query->fetchAll();
foreach ($list as $rs)
{
// put in bold the written text
$zip = str_replace($_POST['keyword'], '<b>'.$_POST['keyword'].'</b>', $rs['zip']);
// add new option
// echo '<li onclick="set_item(\''.str_replace("'", "\'", $rs['zip']).'\')">'.$zip.'</li>'; (this one only passes the attribute)
echo '<li " onclick="set_item(\''.str_replace("'", "\'", $rs['zip_codes_id']).'\')">'.$zip.'</li>';
//this one passes the attribute but changes the displayed value to the primary key.
}
?>
As you can see from the PHP file, what I am trying to do is pass in the primary key value but keep the displayed value the attribute. I am not sure how to do that. Should I be using the UL tag?
The issue in your code is that you try to the zip_id value for the input, but this input contains the zip field value - I assume it's the textual representation. There are a few ways how you could save the zip_id on the frontend - either store it in the model (if you're using some MVC framework, but I gues it's not the case) or simply add a hidden input field:
<input type="hidden" id="actual_zip_id" name="zip_id">
And
function set_item(item)
{
// change input value
$('#actual_zip_id').val(item);
// hide proposition list
$('#zip_codes_list_id').hide();
}
UPD
Speakng about the entire idea of autocompleting zip codes, it looks pretty nasty, as pointed by Darren Gourley (check the comments).
So you'd rather validate it with regex first, and then do your db-related logic like that:
$('#zip_id').on('change', function(){
// your stuff
})
Best regards, Alexander
I am attempting to get all the form values into a normal array[]. I had it working for tags but then I added some tags and can't seem to get it.
With just tags it worked with this
var content = document.querySelectorAll("#form input[name='content[]']");
I am currently trying something like this
var content = document.elements["content[]"].value;
This form can change from user input down the road as each section of the form is a module that they choose to add. It is also important to get the values in order, if that isn't possible then I would need to make it a JSON array. Pure javascript or jquery is fine either way.
Thank you for any help.
EDIT
I used this to solve my problem
var contents=[]
var content = $('#form').serializeArray()
for (var i = 0; i < content.length; i++) {
contents[contents.length]=content[i].value
};
Try
html
<form id="form">
<input type="text" name="content[]" value="abc" />
<textarea name="textarea" value="">123</textarea>
</form>
js
$(function() {
var form = $("#form");
// escape `[]`
var content = form.find("input[name=content\\[\\]]");
// array `literal declaration`
var _arr = [content.prop("value")];
// map all form values to single array
var arr = $.map(form.serializeArray(), function(v, k) {
return [v.value]
});
// array literal with `textarea` `value`
var t = [$("textarea").prop("value")];
console.log(_arr, arr, t);
// _arr: `["abc"]` , arr:`["abc", "123"]` t:`["123"]`
})
Demo.
See Arrays
I want to implement a search box same as this, at first, just first dropdown list is active once user selects an option from the first dropbox, the second dropdown box will be activated and its list will be populated.
<s:select id="country" name="country" label="Country" list="%{country} onchange="findCities(this.value)"/>
<s:select id="city" name="city" label="Location" list=""/>
Jquery chained plugin will serve your purpose,
https://plugins.jquery.com/chained/
usage link - http://www.appelsiini.net/projects/chained
this plugin will chain your textboxes.
Try this code where based on your needs you have to populate it with your options:
var x;
$('#pu-country').on('change', function () {
if (this.value != '0') {
$('#pu-city').prop('disabled', false);
$('#pu-city').find("option").not(":first").remove();
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
switch (this.value) {
case 'A':
x = '<option value="A.1">A.1</option><option value="A.2">A.2</option><option value="A.3">A.3</option>'
}
$('#pu-city').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
$('#pu-city').prop('disabled', true);
$('#pu-city').val("Choose");
}
});
$('#pu-city').on('change', function () {
if (this.value != '0') {
$('#pu-location').prop('disabled', false);
$('#pu-location').find("option").not(":first").remove();
switch (this.value) {
case 'A.1':
x = '<option value="A.1.1">A.1.1</option><option value="A.1.2">A.1.2</option><option value="A.1.3">A.1.3</option>'
break;
case 'A.2':
x = '<option value="A.2.1">A.2.1</option><option value="A.2.2">A.2.2</option><option value="A.2.3">A.2.3</option>'
break;
case 'A.3':
x = '<option value="A.3.1">A.3.1</option><option value="A.3.2">A.3.2</option><option value="A.3.3">A.3.3</option>'
break;
}
$('#pu-location').append(x)
} else {
$('#pu-location').prop('disabled', true);
$('#pu-location').val("Choose");
}
});
I have also set up and a demo to see the functionallity with more options.
FIDDLE
Your code should be something like this:
$(country).change(function(){
var l=Document.getElementByID("country");
for(i=0;i<=l.length;i++)
{
if(l.options[i].selected?)
{
text_array=[HERE YOU NEED TO ADD THE CITIES OF l.options[i].text];
val_array=[HERE YOU NEED TO ADD THE VALUES OF THECITIES OF l.options[i].text];
}
}
var c=Document.getElementByID("city");
c.options.text=[];
c.options.value=[];
//You now should have an empty select.
c.options.text=text_array ;
c.options.value=val_array ;
});
As I don't know, what kind of DB you use, to have the cities connected to their countrys, I can't tell you, what to put into the uppercase text...
Ciao j888, in this fiddle i tried to reconstruct the same system as the site you provided the link
the number of states cityes and locality is less but the concept remains the same
If you want to add a new state you must enter a new html options in select#paese with an id.
Then you have add in obj.citta a property with this id name and an array of cityes for a value.
The same thing for obj.localita where you will create an array of arrays.
The jQuery code you need is
<script type="text/javascript">
$(document).ready(function(){
var obj={
citta:{ //value is the same of option id
albania:['Durres','Tirana'],
austria:['Vienna','innsbruck','Graz'],
},
localita:{//for every city create a sub array of places
albania:[['località Durres1','località Durres 2'],['località Tirana','località Tirana 2']],
austria:[['località Vienna','località Vienna 2'],['località innsbruck','località innsbruck 2'],['località Graz','località Graz 2','località Graz 3']],
}
}
$('#paese').on('change',function(){
$('#località').attr('disabled','disabled').find('option').remove()
var quale=$(this).find('option:selected').attr('id')
var arr=obj.citta[quale]
if(arr){
$('#citta').removeAttr('disabled')
$('#citta option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#citta')
}
}
})
$('#citta').on('change',function(){
var ind=($(this).find('option:selected').index())-1
var quale=$('#paese').find('option:selected').attr('id')
var arr=obj.localita[quale][ind]
if(arr){
$('#località').removeAttr('disabled')
$('#località option.added').remove()
for(i=0;i<arr.length;i++){
$('<option class="added">'+arr[i]+'</option>').appendTo('#località')
}
}
})
})
</script>
If this solution does not suit your needs, i apologize for making you lose time.
Hi i have done this for license and its dependent subject in yii 1.
The license dropdown
//php code
foreach($subject as $v) {
$subj .= $v['licenseId'] . ":" . $v['subjectId'] . ":" . $v['displayName'] . ";";
}
Yii::app()->clientScript->registerScript('variables', 'var subj = "' . $subj . '";', CClientScript::POS_HEAD);
?>
//javascript code
jQuery(document).ready(function($) {
//subject. dependent dropdown list based on licnse
var ty, subjs = subj.split(';'), subjSel = []; //subj register this varible from php it is
for(var i=0; i<subjs.length -1; i++) { //-1 caters for the last ";"
ty = subjs[i].split(":");
subjSel[i] = {licId:ty[0], subjId:ty[1], subjName:ty[2]};
}
//dropdown license
jQuery('#license#').change(function() {
$('#add').html(''); //clear the radios if any
val = $('input[name="license"]:checked').val();
var selectVals = "";
selectVals += '<select>';
for(var i=0; i<subjSel.length; i++) {
if(subjSel[i].licId == val) {
if(subjSel[i].subjId *1 == 9) continue;
selectVals += '<option value="'+subjSel[i].subjId+'">'+subjSel[i].subjName+'</option>';
}
}
selectVals += '</select>';
$("#subject").html(selectVals);
});
});
You seem to be asking two questions:
QUESTION 1. How to have a disabled select box (the second and third select boxes in the case of your example) which is activated upon the selection of an option from the first select box.
ANSWER 1:
simply use the disabled=true/false as below...
<select id="country" name="country" label="Country" onchange="document.getElementById('city').disabled=false; findCities(this.value)"/>
<select id="city" name="city" label="Location" disabled=true/>
NOTE: I changed "s:select" to "select" on the basis that your question does not make reference or tag the Struts framework that uses this syntax.
QUESTION 2: How to populate the second select box when a selection is made in the first.
ANSWER 2: There are many ways to do this, and the choice depends on where you have the data to populate the lists with. In the case of your Rentalcars example, if you chose Barbados, the browser sends an ajax GET request to "http://www.rentalcars.com/AjaxDroplists.do;jsessionid=5DCBF81333A88F37BC7AE15D21E10C41.node012a?country=Barbados&wrapNonAirports=true" -try clicking on this link and you will see what that request is sending back. This '.do' address is a server side file of a type used with the Struts framework I mentioned above.
A more conventional approach, which would be included in your function findCities(country)would be to send an AJAX request to a PHP script which queries a database and sends back an array of place names to the browser. The AJAX javascript code includes instructions as to what to do with the response. Without knowing more about where you want to store your list, giving an example of this would most likely not be useful.
Alternatively, the whole list of places could be included in the javascript script as an array (as demonstarated by Devima, above), in a text document on the server as comma separated values, or you could save it to a browser database like WebSQL or IndexedDB if offline use would be useful.
When you have got your list, probably as an array of values, you could save the array as a variable eg. var cities=result (in the case of a simple ajax request). You will then need to iterate through cities, for example
for (var i = 0; i < cities.length; i++){
var place=cities[i];//an individual city name
document.getElementById("city").innerHTML+="<option value='" + place + "'>" + place + "</option>";//adds an 'option' with the value being the city name and the text you see being the city name
}
IMO this is the base case AngularJS was designed to completely alleviate. Check it out!