1

I am currently working on a Nodejs Project and I am trying to grab the information inputted into a form to redisplay in the form after a failed submit occurs. However, I am confused as to how exactly to perform this. From researching around, I've learned that accomplishing this through an Ajax request would be my best option. I have looked at other posts as well as Googled around but have had no luck. Would anyone be able to assist me? This is the link to the project repo: https://github.com/halsheik/RecipeWarehouse.git. I have also posted any relevant code that may or may not be updated in this repo.

$(document).ready(function(){
    $("#createRecipeForm").submit(function(e) {

        $.ajax({
             type: "POST",
             url: "/recipes/createRecipe",
             data: $(this).serialize(), // serializes form input
             success: function(data){
                console.log(data);
             },
             error: function(data){
                console.log(data);
             }
        });

        console.log(data);
    });

});
<!DOCTYPE html>
<html lang="en">
    <head>
        <!-- Required meta tags -->
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Homemade</title>

        <!-- Required program scripts -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
        
        <!-- Style Sheets-->
        <link rel="stylesheet" href="/styles/navBarStyle.css">
        <link rel="stylesheet" href="/styles/myRecipesStyle.css">
        <link rel="stylesheet" href="/styles/createRecipeStyle.css">
    </head>
    <body>
        <!-- Background image -->
        <img id="background" src="/images/foodBackground.jpg" alt="">

        <div id="newRecipeContainer">
            <div id="closeButtonContainer">
                <div id="backButton"><a id="back" href="/recipes/myRecipes">&larr; My Recipes</a></div>
            </div>
            
            <form id="createRecipeForm" action="/recipes/createRecipe" method="POST" enctype="multipart/form-data">
                <label id="formSubHeading">Create Your Homemade Recipe</label>

                <div id="recipeNameContainer">
                    <label id="recipeNameLabel">Title</label>
                    <input id="recipeNameInput" type="text" name="recipeName">
                </div>

                <div id="recipeImage">
                    <label id="recipeImageLabel">Add An Image of Your Meal</label>
                    <input id="recipeImageInput" type="file" accept="image/*" name="recipeImage"/> 
                    <label id="recipeImageInputLabel" for="recipeImageInput" name="recipeImage">Choose A File</label>
                </div>

                <div id="recipeDescription">
                    <label id="recipeDescriptionLabel">Description</label>
                    <textarea id="recipeDescriptionInput" name="recipeDescription" cols="30" rows="10" maxlength="2000"></textarea>
                </div>

                <div class="ingredientsContainer">
                    <label id="ingredientsLabel">Ingredients</label>
                    <button id="addIngredientButton" type="button" @click="addIngredientForm">Add Another Ingredient</button>
            
                    <div class="allIngredients" v-for="(ingredient, ingredientIndex) in ingredients">
                        <label class="ingredientLabel">{{ ingredientIndex + 1 }}.)</label>
                        <input class="ingredientInput" type="text" name="ingredients" v-model="ingredient.ingredient">
                        
                        <button class="deleteIngredientButton" type="button" v-if="ingredientIndex > 0" @click="deleteIngredientForm(ingredientIndex)">X</button>
                    </div>
                </div>

                <div class="directionsContainer">
                    <label id="directionsLabel">Directions</label>
                    <button id="addDirectionButton" type="button" @click="addDirectionForm">Add Another Direction</button>
            
                    <div class="allDirections" v-for="(direction, directionIndex) in directions">
                        <label class="directionLabel">{{ directionIndex + 1 }}.)</label>
                        <input class="directionInput"type="text" name="directions" v-model="direction.direction">
                        
                        <button class="deleteDirectionButton" type="button" v-if="directionIndex > 0" @click="deleteDirectionForm(directionIndex)">X</button>
                    </div>
                </div>
                
                <div id="createRecipeButtonContainer">
                    <button id="createRecipeButton" type="submit">Create Recipe</button>
                </div>
                
            </form>
        </div>
    </body>
    
    <script src="/controls/newRecipeControl.js"></script>
</html>

Again, thanks for any help.

EDIT 1:

Errors from using jquery code

EDIT 2: My current code. I console.log in order to check that the form info is being received. Before moving it into the form submit call, it would not receive any of the form data. Currently, it does not redisplay the form info upon failed submissions.

$(document).ready(function(){
    $("#createRecipeForm").submit(function(e) {
        const data = {
            title: $('#recipeNameInput').val(), // this syntax is for grabbing input data from jquery
            image: $('imageNameInput').val(), // where the # sign indicates an id is being used to grab the value
            description: $('#recipeDescriptionInput').val(),
            ingredients: $('#ingredientInput').val(),
            directions: $('#directionInput').val(), // in the cases of ingredients and directions, you are using Vue's `v-model` but I am going to assume you have text id's of `ingredientInput` and `directionInput` for them respectively
        };
    
        console.log(data);

        localStorage.setItem('data', JSON.stringify(data)); // data is assumed to be an array or an object

        $.ajax({
             type: "POST",
             url: "/recipes/createRecipe",
             data: $(this).serialize(), // serializes form input
             success: function(data){
                  localStorage.removeItem('data') // clear the data from localStorage as it won't be necessary again
                  // do another thing 

             },
             error: function(data){
               
                // throw or return error message
             }
        });
    });

    if (localStorage.getItem('data') !== null) { // The getItem(key) method must return the current value associated with the given key. If the given key does not exist in the list associated with the object then this method must return null.
        const data = JSON.parse(localStorage.getItem('data')); // parse the retrieve JSON object from localStorage. Data should be exactly the way you put it earlier
  
       $('#recipeNameInput').val(data.title); // grab the title form input and populate it with the data.title value.
       $('#imageNameInput').val(data.image);
       $('#recipeDescriptionInput').val(data.description);
       $('#ingredientInput').val(data.ingredients);
       $('#directionInput').val(data.directions);
    }
});

EDIT 3: Image 1 JavaScript Image 1 console

Image 2 Javascript Image 2 console

halsheikh
  • 43
  • 4

1 Answers1

2

You could use localStorage to set form details before the request is made and then clear the request if the request is successful or get the data if the request fails.

Try this

$(document).ready(function(){
// You have form inputs of title, image, description, ingredients, directions
// Grabbing the input from the form will be something like this

const data = {
  title: $('#recipeNameInput').val(), // this syntax is for grabbing input data from jquery
  image: $('#recipeNameInput').val()), // where the # sign indicates an id is being used to grab the value
  description: $('#recipeDescriptionInput').val()),
  ingredients: $('#ingredientInput').val()),
  directions: $('#directionInput').val()), // in the cases of ingredients and directions, you are using Vue's `v-model` but I am going to assume you have text id's of `ingredientInput` and `directionInput` for them respectively
}
    localStorage.setItem('data', JSON.stringify(data)) // data is assumed to be an array or an object
    $("#createRecipeForm").submit(function(e) {
      
        $.ajax({
             type: "POST",
             url: "/recipes/createRecipe",
             data: $(this).serialize(), // serializes form input
             success: function(data){
                  localStorage.removeItem('data') // clear the data from localStorage as it won't be necessary again
                  // do another thing 

             },
             error: function(data){
               
                // throw or return error message
             }
        });
    });

});

You can find out more about getting form field values using jQuery here

Then, onLoad of the form, you check if there is data in localStorage.

$( document ).ready(function() {
    if (localStorage.getItem('data') !== null) { // The getItem(key) method must return the current value associated with the given key. If the given key does not exist in the list associated with the object then this method must return null.
      const data = JSON.parse(localStorage.getItem('data'); // parse the retrieve JSON object from localStorage. Data should be exactly the way you put it earlier

       data = {
        title: ....., //all fields will be populated with data from the previous attempt
        image: .....,
        description: ....,
        ingredients: ....,
        directions: .....
      }

     $('#recipeNameInput').val(data.title) // grab the title form input and populate it with the data.title value.

// Do the same with the rest of the form inputs
    } else {
      // continue to fresh form in a situation where the previous form request were successful
    }
});

You can find out more about populating form fields using jQuery here

Tony
  • 1,414
  • 3
  • 9
  • 22
  • I see where your logic stems from and it has clarified a few things to me. However, when I attempt to use the first chunk of jquery code above, my console displays an error, which I have linked on the bottom of the post above. – halsheikh Jul 30 '20 at 04:22
  • 1
    I am sorry I didn't make myself clear enough. `data` is the variable you save your form data as. You can name it anything you like. I was just using "data" for the purpose of this example. Do you understand now? The same thing applies to the localStorage key I used. You don't have to name it 'data'. You can use any name you like. – Tony Jul 30 '20 at 04:27
  • I am sorry for the trouble, I am new to this. I have a couple questions. How exactly do I save the form data? And, after saving it into the variable, would I now be able to access the information stored into it as an array? Thank you – halsheikh Jul 30 '20 at 04:31
  • I understand, @halsheikh. I have updated my answer. I have noticed that you are using Vue and jQuery together. That's not a great practice as Vue and jQuery can be used to achieve practically the same thing. I will advice that you desist from using js frameworks such as React.js, Vue.js etc. for now as you are new to this. Try to use vanilla javascript and understand what's happening under the hood before using a framework like Vue. – Tony Jul 30 '20 at 05:26
  • Thanks for the input. I have realized now later in my coding that using both Due and jQuery is bad practiced and have already planned to remove my use of Vue. I am trying my best to use vanilla, however, there are just some things I can't accomplish using vanilla alone. I do appreciate all the help. Right now, I have been able to use the code you have shared with me to retrieve form information, however, i moved the data variable and storage of that variable into the form submit call because it was not receiving the variables unless I did so. My problem now is I am unable to redisplay the... – halsheikh Jul 30 '20 at 23:00
  • ...form inputs into the form. I will update how I have everything in the above post. Thank you again for all the help. – halsheikh Jul 30 '20 at 23:00
  • Could you show the results of console.log('data') after your form submission has failed. Could you also check your localStorage? To do that, `type shift(option) + ctrl(cmd for mac) + i` to open chrome dev tools, then click on the `Application` tab and under that, you will see the `Storage` option. Click on the `Local Storage` option. You will see that of your app. Click on the `data` property to see if you are retrieving anything. – Tony Jul 31 '20 at 03:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/218947/discussion-between-tony-and-halsheikh). – Tony Jul 31 '20 at 03:53