Getting contents of a JSON array into PHP as part of a $_POST array

What I want is to be able to access the two JSON arrays with my PHP method, and that is where I am drawing a blank.

I tried sending the entire form as a FormData object, as @m3g4p0p suggested, but it only sends the original form data, not the values from the dynamically created form elements, which is what happens normally when you submit the form. That’s why I converted the JS-created elements into a JSON array to grab and keep the data from them, separately from the regular part of the form.

Originally, I had done this all with PHP. So I submitted the form, along with the number of ingredients and directions, and the new form elements were created in a different form after a page refresh. Then I had to submit that to get the ingredients and directions. I found that to be very clunky, which is why I am trying to learn how to integrate JavaScript into the process.

That sounds more like what I would like to have happen, but I have had no practical experience with AJAX.

Well, you were putting together a formdata, which was going to use AJAX to send it :wink:

If you want to use FormData to send the AJAX request, take a look at the MDN examples for a general idea of how the flow goes. Also at the bottom of that page is another link to explain just using the XMLHttpRequest object (The thing that actually DOES the AJAX)

1 Like

To be brutally honest I still don’t get why you want to do this. It sounds like you’ve found a solution but can’t define the problem it solves.

What’s wrong with plain old forms? Why does it have to be JSON?

I have a form for adding a recipe to my application. Every recipe has a different number of ingredients and directions, so I wanted to make that part dynamic. Most of the form is just a plain old form, but the dynamic number of elements for ingredients and directions (which will go in a database table of their own, because it is a one-to-many relationship) is the JavaScript part of it. And when I add those elements dynamically, my $_POST array won’t pick up their values along with the rest of the form values. So I’m trying to figure out how to get them separately to my PHP for processing.

I used JSON because I know that both JavaScript and PHP can handle it - so that was going to be my bridge between the two, but I’m missing a number of steps.

Well, you start with a single field

<input type="text" name="ingredient[]" />

And then when you want add another ingredient you clone that field and put it below the first one.

When you then submit the form $_POST['ingredient'] will contain an array of all ingredients.

No need for any JSON at all.

But I have all that. See my first post to get a list of what I have already done. Because the inputs are dynamically added using JavaScript, when I submit my form, only the original form elements (e.g. name, description, preparation time, cooking time, etc) send their values to the $_POST array, not these ones. So I used JavaScript to grab their values and put them in two arrays - one for ingredients, and one for directions. And it is these two arrays that I can’t figure out how to get into my controller to be read and processed by PHP. I’m sorry if the description in my first post was not clear. I thought it described what I had accomplished and what I was trying to accomplish as my next steps…

That’s weird. I’ve done this a gazillion times and never had any problems with it. Could you post the HTML and Javascript please?

Here is my add-recipe.php code:

<?php require_once INC_ROOT . '/app/views/inc/header.php'; ?>

	<div id="main-content">
		<h1>Add a New Recipe</h1>
		<?php displayMessage(); ?>
		<div class="left-content">
		
			<form action="/recipes/add" method="post">
				
				<div class="form-section">
					<label for="title">
						Name:
					</label>
					<input type="text" name="title" id="title" class="long-textbox" value="<?php echo (isset($recipe->title)) ? escape($recipe->title) : ''; ?>">
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="description">
						Description:
					</label>
					<textarea name="description" id="description"><?php echo (isset($recipe->description)) ? $recipe->description : ''; ?></textarea>
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="category">
						Category:
					</label>
					<select name="categories[]" id="category" multiple>
						<?php if (NULL != $parent_categories) : ?>
							<?php foreach ($parent_categories as $parent_category) : ?>
								<option class="parent" value="<?php echo $parent_category->id; ?>">
									<?php echo $parent_category->category; ?>
								</option>
								<?php $child_categories = $this->category_model->get_child_categories($parent_category->id); ?>
								<?php foreach ($child_categories as $child_category) : ?>
									<option class="child" value="<?php echo $child_category->id; ?>">
										<?php echo $child_category->category; ?>
									</option>
								<?php endforeach; ?>
							<?php endforeach; ?>	
						<?php endif; ?>
					</select>
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="prep_time">
						Preparation Time:
					</label>
					<input type="text" name="prep_time" id="prep_time" class="short-textbox" value="<?php echo (isset($recipe->prep_time)) ? $recipe->prep_time : ''; ?>"> minutes
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="cook_time">
						Cooking Time:
					</label>
					<input type="text" name="cook_time" id="cook_time" class="short-textbox" value="<?php echo (isset($recipe->cook_time)) ? $recipe->cook_time : ''; ?>"> minutes
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="num_calories">
						Number of Calories (per serving):
					</label>
					<input type="text" name="num_calories" id="num_calories" class="short-textbox" value="<?php echo (isset($recipe->num_calories)) ? $recipe->num_calories : ''; ?>">
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="num_servings">
						Number of Servings:
					</label>
					<input type="text" name="num_servings" id="num_servings" class="short-textbox" value="<?php echo (isset($recipe->num_servings)) ? $recipe->num_servings : ''; ?>">
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="num_ingredients">
						Number of Ingredients:
					</label>
					<input type="text" name="num_ingredients" id="num_ingredients" class="short-textbox" value="<?php echo (isset($recipe->num_ingredients)) ? $recipe->num_ingredients : ''; ?>">
				</div><!-- end .form-section -->
					
				<div class="form-section">
					<label for="num_directions">
						Number of Directions:
					</label>
					<input type="text" name="num_directions" id="num_directions" class="short-textbox" value="<?php echo (isset($recipe->num_directions)) ? $recipe->num_directions : ''; ?>">
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="rating">
						Rating (1 to 5):
					</label>
					<select name="rating">
						<?php for ($i = 0; $i <= 5; $i += 0.5) : ?>
							<option value = "<?php echo $i; ?>"><?php echo $i; ?></option>
						<?php endfor; ?>
					</select>
				</div><!-- end .form-section -->
				
				<div class="form-section">
					<label for="source">
						Source:
					</label>
					<input type="text" name="source" id="source" class="long-textbox" value="<?php echo (isset($recipe->source)) ? escape($recipe->source) : ''; ?>">
				</div><!-- end .form-section -->
			
			<div class="clear"></div>
			
		</div><!-- end .left-content -->

		
		<div class="right-content">
		
			<h3>Ingredients</h3>

			<ol id="ingredients"></ol>
			
			<h3>Directions</h3>

			<ol id="directions"></ol>
			
			<div class="form-section">
				<input id="submit" type="submit" name="submit" value="Save Recipe">
			</div><!-- end .form-section -->
		</div><!-- end .right-content -->
		
	</form>

	<div class="right-content">
		<h3>Upload Recipe Image</h3>
		
		<form id="upload" action="/recipes/upload_image" enctype="multipart/form-data" method="post">
			<div class="form-section">
				<input type="hidden" name="MAX_FILE_SIZE" value = "<?php echo $max_file_size; ?>">
				<label for="file">Image to upload: </label>
				<input id="file" type="file" name="recipe_image">
			</div><!-- end .form-section -->
			<div class="form-section">
				<label for="upload">Press to ...</label>
				<input id="upload" type="submit" name="submit" value="Upload image">
			</div><!-- end .form-section -->
		</form>

	</div><!-- end .right-content -->
		
		<div class="clear"></div>
	</div><!-- end #main-content -->

<?php require_once INC_ROOT . '/app/views/inc/footer.php'; ?>

and my add-recipe.js script:

const numIngredients= document.getElementById("num_ingredients");
let numIngred;

const numDirections = document.getElementById("num_directions");
let numDir;

let submitBtn = document.getElementById("submit");

numIngredients.addEventListener('input', (event) => {
		
		// dynamically add inputs to ingredients based on number of ingredients entered
		let ingredientInputs = "";
		numIngred = numIngredients.value;
		let counter = 0;
		
		for (let i = 0; i < numIngred; i++) {
			counter = i + 1;
			ingredientInputs += '<li><input type="text" name="ingredients[]" id="ingredients' + counter + '" class="medium-textbox"></li>';
		}
		
		document.getElementById("ingredients").innerHTML = ingredientInputs;
		event.preventDefault();
		
		// Add all the ingredients from the form inputs into a JS array
		let ingredArr = addIngredientsToArray();
		
});

numDirections.addEventListener('input', (event) => {
		
		// dynamically add textareas to directions based on number of directions entered
		let directionInputs = "";
		numDir = numDirections.value;
		let counter = 0;
		
		for (let i = 0; i < numDir; i++) {
			counter = i+1;
			directionInputs += '<li><label>' + counter +'. </label> <textarea name="directions[]" id="directions' + counter + '"></textarea></li>';
		}
		
		document.getElementById("directions").innerHTML = directionInputs;
		event.preventDefault();

		let dirArr = addDirectionsToArray();

});

// add ingredients form values to a JS array
// ingredients ordered list has id of 'ingredients'
function addIngredientsToArray() {
	
	let ingredientsArray = [];
	let jsonIngredients = {};
	
	let ingredientsInputs = document.getElementById("ingredients")
													.getElementsByTagName('input');
	
	for (let i = 0; i < ingredientsInputs.length; i++) {
		
		ingredientsInputs[i].addEventListener('change', (event) => {
			ingredientsArray.push(ingredientsInputs[i].value);
		});
		
	}

	// add all the ingredients from the form inputs into a JS array
	submitBtn.addEventListener('change', (event) => {
		
		jsonIngredients = JSON.stringify(ingredientsArray);
		
	});
	
	 sendJsonArrays(jsonIngredients);
	// return jsonIngredients;
	
}

// add directions form values to a JS array
// directions ordered list has id of 'directions'
function addDirectionsToArray() {
	
	let directionsArray = [];
	let jsonDirections = {};
	
	let directionsTextareas = document.getElementById("directions")
													.getElementsByTagName('textarea');
	
	
	for (let i = 0; i < directionsTextareas.length; i++) {
		
		directionsTextareas[i].addEventListener('change', (event) => {
			directionsArray.push(directionsTextareas[i].value);
		});
		
	}

	
	// add all the directions from the form textareas into a JS array
	submitBtn.addEventListener('change', (event) => {
		
		jsonDirections = JSON.stringify(directionsArray);
	
		
		
	});
	
	 sendJsonArrays(jsonDirections);
	 
	// return jsonDirections;
	
}

// call the functions that convert the ingredients, directions array to JSON
let jsonIngredients = addIngredientsToArray();
let jsonDirections = addDirectionsToArray();

// Use formData to send JSON to php controllers
function sendJsonArrays(jsonArray) {
	
	let formData = new formData();
	
	formData.append(jsonArray);
	console.log(formData);
	
	let request = new XMLHttpRequest();
	
}

The last function is a work in progress - my attempt at trying to follow some suggestions provided here - it is not finished.

Your HTML is incorrect. It basically looks like this:

<div class="left-content">
    <form action="/recipes/add" method="post">
    <!-- lots of form fields here -->
</div>
<div class="right-content">
    <!-- ingredients and directions here -->
</div>
</form>

Browsers will see: okay, so we start a div, then we start a form, then we close a div - hey hold on, there is form still open here, I can’t just leave that hanging, so I’ll close that as well. So it’s basically interpreted as

<div class="left-content">
    <form action="/recipes/add" method="post">
    <!-- lots of form fields here -->
    </form> <!-- Form closed implicitly by browser here -->
</div>
<div class="right-content">
    <!-- ingredients and directions here -->
</div>
</form>

So the ingredients and the directions are not part of the form, and will not be sent to the server.

So what you should do instead is:

<form action="/recipes/add" method="post">
    <div class="left-content">
        <!-- lots of form fields here -->
    </div>
    <div class="right-content">
        <!-- ingredients and directions here -->
    </div>
</form>

And the form closes around your ingredients and directions as well, and you will receive them in $_POST when you submit the form.

Hope that helps :slight_smile:

Oops! I didn’t even see that. That is left over from when I had the separate form to just deal with the ingredients and directions. I removed that and put the two together and left the one closing form tag in by mistake. Thank you for seeing that. So I went through all that JavaScript and led everyone down the proverbial garden path for nothing? I’m feeling a bit dumb right now. :slight_smile:

It did work now. :sigh Well, I did learn a lot from all the contributors to this thread, and intend to look further into Ajax and the XMLHttpRequest object (after I come out from hiding).

No worries, glad I could help :slight_smile:

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.