I have a multidimensional array of stores and states, which makes a json as follows:
<?php
$list[$store][$state] = $city;
echo json_encode ($list);
{"store 1": {"state x": "city 1", "state y": "city 2"}, "store 2": {"state z": "city 3"}}
?>
I need to create a select that changes the second select according to what was chosen, using the data of the array in question.
Something like this http://www.daviferreira.com/blog/exemplos/cidades/index.php
How can I handle this data in php for javascript?
And how can I separate them to use them in each select?
I've already tried:
var list = JSON.parse ("<? php echo json_encode($list)?>");
But it did not work :(
EDIT The structure of the selects should look like this.
{"store 1": {"state x": "city 1", "state y": "city 2"}, "store 2": {"state z": "city 3"}}
First select
Store 1
Store 2
if store 1 selected
Second select
State x
State y
if store 2 selected
Second select
State z
Something like that
You can simply do this using jQuery:
$(document).ready(function(){
var list = <?= json_encode($list); ?>;
var storeSelect = $("<select></select>");
storeSelect.attr('id', 'storeSelect');
for(var item in list)
{
storeSelect.append('<option value="' + item + '">' + item + '</option>');
}
$('#theForm').append(storeSelect);
var storeStates = $("<select></select>");
storeStates.attr('id', 'storeState');
$('#theForm').append(storeStates);
$('#storeSelect').change(function ()
{
var storeName = $(this).val();
for(var item in list[storeName])
{
storeStates.html('<option value="' + item + '">' + item + '</option>');
}
});
$('#storeSelect').change();
});
It simply uses loops to create the select menu. And uses the onChange event to manipulate the values.
Here's how to do it using jQuery. If you're using plain JS, converting it is an exercise for the reader.
var list = <?php echo json_encode($list); ?>;
$.each(list, function(store) {
$("#store_menu").append($("<option>", {
value: store,
text: store
}));
});
$("#store_menu").change(function() {
var store = $(this).val();
$("#state_menu").empty();
$.each(list[store], function(state) {
$("#state_menu").append($("<option>", {
value: state,
text: state
}));
});
});
Related
I have a javascript object that I would like to traverse and print data based off 1 common category.
Javascript object:
var $states = {
"AL" : {
"longname": "Alabama",
"lawOne": "Alabama Law 1",
"lawTwo": "Alabama Law 2",
"lawThree": "Alabama Law 3",
"region" : "Southeast"
},
"AK" : {
"longname": "Alaska",
"lawOne": "Alaska Law 1",
"lawTwo": "Alaska Law 2",
"lawThree": "Alaska Law 3",
"region" : "Northwest"
},
"AZ" : {
"longname": "Arizona",
"lawOne": "Arizona Law 1",
"lawTwo": "Arizona Law 2",
"lawThree": "Arizona Law 3",
"region" : "Southwest"
},
etc...
}
I am able too loop the array and get as granular as getting the console to log all of the states that are in the same region:
for (var key in $states) {
if ($states.hasOwnProperty(key)) {
var $getStateRegion = $states[key].region
if ($getStateRegion === "Northeast") {
console.log ($states[key].longname);
}
}
}
Once I try to loop through those and print a table with that data is where I am running into an issue. I want to be able to have a withthe 's longname, lawOne, lawTwo, and lawThree values input in there. What gives? Once I try running a for loops through this is where I'm hitting a roadblock. Thanks in advance!
Try the working code below.
var $states = {
"AL" : {
"longname": "Alabama",
"lawOne": "Alabama Law 1",
"lawTwo": "Alabama Law 2",
"lawThree": "Alabama Law 3",
"region" : "Southeast"
},
"AK" : {
"longname": "Alaska",
"lawOne": "Alaska Law 1",
"lawTwo": "Alaska Law 2",
"lawThree": "Alaska Law 3",
"region" : "Northwest"
},
"AZ" : {
"longname": "Arizona",
"lawOne": "Arizona Law 1",
"lawTwo": "Arizona Law 2",
"lawThree": "Arizona Law 3",
"region" : "Southwest"
}
};
var result = {};
Object.keys($states).forEach(function(key) {
if ($states[key]["region"] === "Southwest") {
result[key] = $states[key];
}
});
console.log(result);
You are on the right track. Before I continue, I would like to point out that you are using a for..in loop, but newer versions of Javascript support the for..of loop also, so this is something you may want to consider. The difference is that the for..in loop gives you the keys of the object, and the for..of loop gives you the values, so it shortens the code by skipping the step where you write something to the effect of:
for( var index in array ){
var currentObject = array[ index ];
}
The secret to your solution is in how you handle the DOM, and there are many ways to do this. I will show you one, but it is not necessarily the fastest or the best. I recommend playing around with different DOM manipulations to find the one that works best for you.
First, we know how to get a record, so the javascript aspect of looping, you have that handled...
Next, we need to create the table.... I will assume that you want four columns based on your description, but you could easily adjust this to put the state name and one law on each line, which would probably be a better design allowing a variable number of laws.
The html would look something like this:
<table>
<tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>
<!-- Here is where we would create new html for each state -->
</table>
Your loop then would need to add to this html by creating several lines that appear as:
<tr><td>[State]</td><td>[Law1]</td><td>[Law2]</td><td>[Law3]</td><tr>
We will use string manipulation of the DOM, because it is a good place to start, because it is most similar to what you would write by hand.
We will break the table into three parts: the header, the body and the footer.
var header = "<table><tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>";
var body = ""; //this is where we add the data
var footer = "</table>";
Now, on the loop, we will create each line as needed and add it to the body:
for( var index in stateObj ){
...error checking occurs here...
var state = stateObj[ index ];
var stateColumn = "<td>" + state.longname + "</td>";
var law1Col = "<td>" + state.lawOne + "</td>";
var law2Col = "<td>" + state.lawTwo + "</td>";
var law3Col = "<td>" + state.lawThree + "</td>";
var row = "<tr>" + stateColumn + law1Col + law2Col + law3Col + "</tr>";
//now that we have a row, we add it to the body
body += row; //same as body = body + row;
}
After we have the body, we can make our table by combining the header, body and footer:
var tableHTML = header + body + footer;
And then we find a place to inject it into our document:
var outputDiv = document.getElementById( "stateTableData" );
outputDiv.innerHTML = tableHTML;
Here is a live example:
var states = {
PA: {
longname:"Pennsylvania",
lawOne:"It is illegal to sing in the shower in apartment buildings within the city limits of Philadelphia",
lawTwo:"All motorists are required to stop the vehicle for passing horsemen. The vehicle shall be covered with camoflage so as not to scare the horses.",
lawThree:"Any house having more than four women occupants shall be considered a brothel and shall be in violation of the law."
},
NJ: {
longname:"New Jersey",
lawOne:"There is no such thing as the Mafia",
lawTwo:"Any reference to the denizens of New Jersey shall be derogatory and degrading, think Jersey Shore",
lawThree:"There is no escape from New Jersey and we are not a suburb of NYC"
},
VA: {
longname:"Virginia",
lawOne: "Civil War re-enactments must have the North as the victor.",
lawTwo: "All roads shall end in Richmond, VA",
lawThree: "I have run out of silly ideas for this example."
}
};
function buildTableForState( stateNames ){
var stateList = stateNames.split(",");
//remove spaces
for( var i in stateList ){ stateList[i] = stateList[i].trim(); }
//initialize table parts
var header = "<table><tr><th>State</th><th>Law 1</th><th>Law 2</th><th>Law 3</th></tr>";
var footer = "</table>";
var body = "";
//build body
for( var index in states ){
if( stateList.indexOf( index ) !== -1 ){
var currentState = states[index];
body += buildRowForState( currentState );
}
}
//compose and inject table
var tableHTML = header + body + footer;
var documentOut = document.getElementById( "outputDiv" );
documentOut.innerHTML = tableHTML;
}
function submitTable(value){
buildTableForState( value );
}
function buildRowForState( currentState ){
var state = makeTableCol( currentState.longname );
var law1 = makeTableCol( currentState.lawOne );
var law2 = makeTableCol( currentState.lawTwo );
var law3 = makeTableCol( currentState.lawThree );
var row = makeTableRow( [state, law1, law2, law3] );
return row;
}
function makeTableCol( stringText ){
return "<td>" + stringText + "</td>";
}
function makeTableRow( arrayColumns ){
return "<tr>" + arrayColumns.join("") + "</tr>";
}
<h1>Table Loader</h1>
<form>
<p>Use the values "PA", "NJ", and "VA" to generate a table. You can use more than one value by separating them with a comma.</p>
<input type="text" id="stateNames" name="stateNames" /><br/>
<button onclick="submitTable(stateNames.value);">Build Table</button>
<p>Try:
</p>
<ul>
<li>PA</li>
<li>NJ,VA</li>
<li>VA,PA,NJ</li>
</ul>
</form>
<h1>Table Output appears here</h1>
<div id="outputDiv"></div>
NOTE: Regarding the live code, the HTML is bigger than the display box. In my browser I have to scroll down on the snippit HTML to view the generated table. Either that or expand the snippit window to a full tab to view it in a larger screen.
The above code is simplified, and most coders would tell you not to use HTMLElement.innerHTML, because it is slow, but it is a good place to start. Once you have this down, start practicing with document.create( tagName ), and then use more direct DOM manipulations.
I want to get the json data from a file which has a nested JSON objects, like this.
{
"userId": "1",
"data": {
"id": 1,
"name" : "Lorem Ipsum",
"value" : "Salut Dolor"
}
}
And once I get it I want to create a select object with the Id as the displayed text and append it to a div.
Once the select object is created, I also want to automatically open the select options when the page gets loaded.
Once a value is selected from there, I want to display the name that is present in the json for that id.
I'm able to fetch only the UserId from this code, how will i meet the requirements?
$.ajax({
url: 'obj.json',
dataType: 'JSON',
success: function (data) {
var items = [];
$.each(data, function (key, value) {
items.push('<option id="' + key + '">' + value + '</option>');
});
$('<select/>', {
class: 'intrest-list',
html: items.join('')
}).appendTo('body');
},
statusCode: {
404: function () {
alert("There was a problem");
}
}
});
what is this good for? do you want to fetch more then 1 user in the future?
you could so something like this:
//user.json
[{id:1,name:'xxxx'},...]
....
for(var i = 0;i<data.length;i++){
items.push('<option id="' + data[i].id + '">' + data[i].name+'</option>');
}
...
or in your case, you can access it directly with:
data.data.id
data.data.name
data.data.value
would get you the right values
Solved it myself. Although i came up with an alternative to display the list of select elements as:
<select name="" id="details" size="2"></select>
also created a container to post the values of the JSON object selected from the select box:
<div id="container"></div>
and the jQuery part where the magic happens goes like this:
$.getJSON('obj.json', function(obj) {
$.each(obj, function(key, value) {
$("#details").append('<option>'+ value.name +'</option>')
});
$( "select" ).change(function () {
var value = $( "select option:selected").val();
$.each(obj, function(key, val) {
if (val.name == value) {
$("#container").html(val.value);
}
});
});
});
This pretty much made the select box as a list of items and the value.name selected in it makes the value.value visible in the div container.
Sorry for my bad English as I'm not native English speaker.
The question is this,
I have plan to do a three multiple select box in a single page, how to retrieve the query data before hand when the query in php is executed, individual query loop result will be add into a multidimensional array.
2nd, when the user click on any one of the option on the 1st multiple select box, it will structure the 2nd select box accordingly to the by calling out reference from array, how do i work on this?
Lastly, I would like to do this without using ajax.
Here's part of my code,
Javascript/jquery + php
$(document).ready(function(){
var selectValues = { "1" : "General Health",
"2": "Head and Neck",
"3": "Ear, nose and throat" ,
"4": "Stomach, bowel and bladder",
"5": "Bones and muscles",
"6": "Mental Health or confusion",
"7": "Pregnancy Problem",
"8": "Accident, wound or injury"
};
var $cateSymptom = $('#cateSymptom');
var $dropdownSymptom = $("#dropdownSymptom");
$.each(selectValues, function(key, value) {
$('#cateSymptom')
.append($("<option></option>")
.attr("value",key)
.text(value));
});
<?php
$query = "select a.*, asy.*, s.* from ailment as a join symptom_ailment as asy on a.ailment_id = asy.ailment_id join symptom as s on asy.symptom_id = s.symptom_id";
$result = mysqli_query($conn,$query) or die(mysqli_error($conn));
while($row = mysqli_fetch_assoc($result))
{
$sid = $row["symptom_id"];
$sname = $row["symptom_name"];
$stype = $row["stype_id"];
$aname = $row["ailment_name"];
$aid = $row["ailment_id"];
echo "<script>alert('$sid $sname $stype $aname $aid'); </script>";
?>
var selectValues2 = { "<?php echo $stype; ?>" :
{
"<?php echo $sname ?>" :
[
"<?php echo $aid ?>",
"<?php echo $aname; ?>"
]
}
};
<?php }
?>
$cateSymptom.change(function() {
alert('1');
$dropdownSymptom.empty().append(function() {
alert('2');
var output = '';
console.debug(selectValues2);
$.each(selectValues2[$cateSymptom.val()], function(key, value) {
alert('3');
output += '<option>' + key + '</option>';
});
return output;
});
}).change();
});
HTML:
<div id="scCategory">
<h3>Choose Symptoms Category</h3>
<form name="frmSC2" method="POST" id="frmSC2">
<select multiple name="symp[]" id="cateSymptom" style="width:230px;height:280px;">
</select>
</div>
<div id="scDepth">
<h3>List of Symptoms</h3>
<select multiple name="symptom[]" id="dropdownSymptom" style="width:230px;height:280px;">
</select>
</div>
<div id="scCondition">
<h3>Possible Condition</h3>
<select multiple name="condition[]" id="dropdownCondition" style="width:230px;height:240px;">
</select>
</div>
Following is a fully integrated solution for all 3 levels
Data structure uses objects with ID as keys, and a children property if applicable
var data = {
"1": {
"val": "1",
"text": "General Health",
"children": {
"1.0": {
"text": "Item - 1.0",
"val": "1.0",
"children": {
"1.0.0": {
"text": "Item - 1.0.0",
"val": "1.0.0"
}
}
}
}
In the JS the active data for each select is storedd on the element using jQuery data() for easy access to populate the next select within change handler
/* change handler to manage emptying and populating chained selects */
var $selects = $('select').change(function () {
var idx = $selects.index(this),
$currSelect = $(this),
val = $currSelect.val(),
$nextSelect = $selects.eq(idx + 1);
if (idx < 2) {
/* empty select(s) after this one */
$selects.filter(':gt(' + idx + ')').empty();
/* if value update next select */
if (val) {
var nextSelectData = $currSelect.data('selectData')[val].children;
populateSelect($nextSelect, nextSelectData);
}
}
});
/* load first select */
populateSelect($selects.first(), data);
function populateSelect($select, selectData) {
$select.append('<option value=""> -- Select -- </option>')
$.each(selectData, function (key, item) {
$select.append($("<option></option>")
.attr("value", key)
.text(item.text));
});
/* store the data on this element for easy access in change handler */
$select.data('selectData', selectData);
}
DEMO
Since you don't want to use ajax.. The VERY DIRTY way to do this would be to output the PHP array on the page as something like an unordered list (and display:none; or jquery.hide) on those said lists. Point at them with Jquery like so:
var list1 = [];
$('classListOne.li').each(function(i, elem) {
list1.push($(elem).text());
});
Then at that point since you need the next drop down's to reflect what a user implemented on the first drop down. Your going to need to create a pretty hariy IF/else and or CASE statement in Jquery. Once you find the array you need create a another drop-down and append it to where you need it to go like so:
var data = {
'foo': 'bar',
'foo2': 'baz'
}
var s = $('<select />');
for(var val in data) {
$('<option />', {value: val, text: data[val]}).appendTo(s);
}
s.appendTo('body');
This again is a horrible why to do this, but I understand sometimes you can't always use the best technologies. Let me know if that helps at all.
I have a table consisting of rows with inputs. Rows are cloned and added dynamically whenever an autocomplete value is selected in the first input of each row.
Each time a new row is added, I want to apply .autocomplete to the first input. Normally this is easy, as seen in this jsfiddle.
I have a somewhat different approach, where I'm changing the ID of the input where a selection is made. I think that's why I'm unable to apply autocomplete to the cloned line, but I can't figure out why??
Here's the code in question (jsfiddle here)
// Make new line. (I have additional code for improved functionality in my production code)
function newLine() {
// Send the line to backend for updating mysql. Data returned is
// the mysql id for the "autocompleted" line. Emulated here by a random number
var randomNumber = Math.floor(Math.random() * 100) + 1
$("#idLine0").attr("id", "idLine" + randomNumber)
//Make clone of the last line
var row = $("#test tr:last").clone(true);
//Give the ID "idLine0" (which I've reserved for the bottom line) to the new line.
$(".AC", row).val("").attr({
"id": "idLine0",
"placeholder": "Autocomplete does not work here"
})
row.insertAfter("#test tr:last");
//$(".AC").autocomplete("destroy")
applyAutocomplete("#idLine0")
}
function applyAutocomplete(id) {
$(id).autocomplete({
source: [{
value: "ActionScript",
type: "type 1",
comment: "none"
}, {
value: "TestScript",
type: "type 2",
comment: "lots"
}, {
value: "AlphaScript",
type: "type 3",
comment: "even more"
}, {
value: "BravoScript",
type: "type 4",
comment: "lots and lots"
}, {
value: "CharlieScript",
type: "type 5",
comment: "comment"
}, {
value: "DeltaScript",
type: "type 6",
comment: "no comment"
}],
minLength: 1,
open: function (event, ui) {
var header = "<li style='border-bottom: 1px solid black; padding-top: 10px;'>" +
"<a style='font-size:1em;font-weight:bold; display:inline-block;'>" +
"<span class='ui-span'>Product</span><span class='ui-span'>Type</span>" +
"<span class='ui-span'>Comment</span></a></li>"
$("ul.ui-autocomplete[style*='block']").find("li:first").before(header);
},
select: function (event, ui) {
console.log($(this.element))
newLine()
}
}).data("ui-autocomplete")._renderItem = function (ul, item) {
return $("<li>")
.data("ui-autocomplete-item", item)
.append("<a><span class='ui-span'>" + item.value +
"</span><span class='ui-span'>" + item.type +
"</span><span class='ui-span' style='width:250px;'>" + item.comment + "</span></a>")
.appendTo(ul);
};
}
After working on your problem a bit, i've seen this line:
var row = $("#test tr:last").clone(true);
And this line is the problem, more specifically the "true" bool parametter.
As you can see on jquery .clone docs:
A Boolean indicating whether event handlers should be copied along with the elements...
This basically means that everything on that element will be clonned, handdlers, triggers, etc... Every time you use your first input element, you will be able to see the autocomplete working and cloning lines.
So, change this:
var row = $("#test tr:last").clone(true);
To this:
var row = $("#test tr:last").clone();
I've made a more "clean" version of your jsfiddle: http://jsfiddle.net/JuanHB/8uhNq/3/
I have the following JSON:
var questions = {
section: {
"1": question: {
"1": {
"id" : "1a",
"title": "This is question1a"
},
"2": {
"id" : "1b",
"title": "This is question2a"
}
},
"2": question: {
"1": {
"id" : "2a",
"title": "This is question1a"
},
"2": {
"id" : "2b",
"title": "This is question2a"
}
}
}
};
NOTE: JSON changed based on the answers below to support the question better as the original JSON was badly formatted and how it works with the for loop below.
The full JSON will have 8 sections and each section will contain 15 questions.
The idea is that the JS code will read what section to pull out and then one by one pull out the questions from the list. On first load it will pull out the first question and then when the user clicks on of the buttons either option A or B it will then load in the next question until all questions have been pulled and then do a callback.
When the button in the appended list item is clicked it will then add it to the list below called responses with the answer the user gave as a span tag.
This is what I have so far:
function loadQuestion( $section ) {
$.getJSON('questions.json', function (data) {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item === $section) {
$('#questions').append('<li id="' + item.section.questions.question.id + '">' + item.section.questions.question.title + ' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>');
}
}
});
}
function addResponse( $id, $title, $response ) {
$('#responses').append('<li id="'+$id+'">'+$title+' <span>'+$response+'</span></li>');
}
$(document).ready(function() {
// should load the first question from the passed section
loadQuestion( $('.section').data('section') );
// add the response to the list and then load in the next question
$('button.btn').live('click', function() {
$id = $(this).parents('li').attr('id');
$title = $(this).parents('li').html();
$response = $(this).data('response');
addResponse( $id, $title, $response );
loadQuestion ( $('.section').data('section') );
});
});
and the HTML for the page (each page is separate HTML page):
<div class="section" data-section="1">
<ul id="questions"></ul>
<ul id="responses"></ul>
</div>
I've become stuck and confused by how to get only the first question from a section and then load in each question consecutively for that section until all have been called and then do a callback to show the section has been completed.
Thanks
Do not have multiple id's in html called "section."
Do not have multiple keys in your JSON on the same level called "section". Keys in JSON on the same level should be unique just as if you are thinking about a key-value hash system. Then you'll actually be able to find the keys. Duplicate JSON keys on the same level is not valid.
One solution can be section1, section2, etc. instead of just section. Don't rely on data-section attribute in your HTML - it's still not good if you have "section" as the duplicate html id's and as duplicate JSON keys.
If you have only one section id in HTML DOM, then in your JSON you must also have just one thing called "section" e.g.:
var whatever = {
"section" : {
"1": {
"question" : {
"1" : {
"id" : "1a",
"title" : "question1a"
},
"2" : {
"id" : "2a",
"title" : "question2a"
}
}
},
"2": {
"question" : {
"1" : {
"id" : "1a",
"title" : "aquestion1a"
},
"2" : {
"id" : "2a",
"title" : "aquestion2a"
}
}
}
}
}
console.log(whatever.section[1].question[1].title); //"question1a"
To get question, do something like this:
function loadQuestions(mySectionNum) {
$.getJSON('whatever.json', function(data){
var layeriwant = data.section[mySectionNum].question;
$.each(layeriwant, function(question, qMeta) {
var desired = '<div id="question-' +
qMeta.id +
'"' +
'>' +
'</div>';
$("#section").append(desired);
var quest = $("#question-" + qMeta.id);
quest.append('<div class="title">' + qMeta.title + '</div>');
//and so on for question content, answer choices, etc.
});
});
}
then something like this to actually get the questions:
function newQuestion(){
var myHTMLSecNum = $("#section").attr('data-section');
loadQuestions(myHTMLSecNum);
}
newQuestion();
//below is an example, to remove and then append new question:
$('#whatevernextbutton').on('click',function(){
var tmp = parseInt($("#section").attr('data-section'));
tmp++;
$("#section").attr('data-section', tmp);
$("#section").find('*').remove();
newQuestion();
});
Technically your getJSON function always retrieves the same data. Your code never compares the id given to the id you're extracting.
Your getJSON should look something like:
function loadQuestion( $section ) {
for (var i = 0; i < questions.section.length; i++) {
var item = questions.section[i];
if (item.id === $section) {
for (var j = 0; j < item.questions.length; j++) {
$('#questions').append('<li id="' +
item.questions[i].id + '">' +
item.questions[i].title +
' <button class="btn" data-response="a">A</button><button class="btn" data-response="b">B</button></li>'
);
}
}
}
}
Modify your JSON to:
var questions = {
section: [{
id: 1,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a",
title: "This is question2a"
}]},{
id: 2,
questions: [{
id: "1a",
title: "This is question1a"
},{
id: "2a"
title: "This is question2a"
}]
}]
};
Edit: your first parameter of getJSON is the URL of the JSON returning service.
You don't need getJSON at all if your JSON is already defined on the client. I have modified the code above.