Food Ordering System Part 26 | Add new Item in Menu in ASP.NET MVC Core


 

Step-by-Step Explanation

  1. Attribute Definition ([HttpGet]): This attribute ensures that the method only responds to GET requests. It is triggered when the admin clicks the "Add New Item" button or navigates to the URL to load the blank form.

  2. Security Authorization Check: if (!IsAdmin()) return RedirectToAction("Index", "Home"); This is a crucial security gate. It calls a helper method IsAdmin() to verify the user's identity. If the user is not an administrator, they are redirected to the Home page to prevent unauthorized access to the menu management system.

  3. Data Preparation for the UI: ViewBag.Categories = _context.Categories.ToList(); To add a new food item, the admin needs to select a category (e.g., Pizza, Burgers, Drinks). This line fetches all existing categories from the database via the database context and stores them in a ViewBag. This allows the dropdown list in the frontend View to be populated dynamically.

  4. Rendering the View: return View(); Finally, the controller returns the corresponding View file. Since we haven't passed a specific model object, it loads an empty form ready for user input.


[HttpGet]
public IActionResult AddFoodItem()
{
    if (!IsAdmin()) return RedirectToAction("Index", "Home");

    ViewBag.Categories = _context.Categories.ToList();
    return View();
}

Step-by-Step Explanation

  1. Model & Data Setup:

    • @model FoodItem: Binds the page to your data model so fields like Name and Price are handled automatically.

    • ViewBag.Categories: Extracts the list of categories we passed from the Controller to fill the dropdown menu.

  2. Form Configuration:

    • <form asp-action="AddFoodItem" method="post">: This tells ASP.NET Core to send the data to the POST version of the AddFoodItem method when the button is clicked.

  3. Input Fields & Validation:

    • Tag Helpers (asp-for): Automatically generates the correct HTML id, name, and value for each property.

    • Validation (asp-validation-for): Displays error messages if the user enters invalid data (e.g., leaving a required field empty).

  4. The Category Dropdown:

    • A @foreach loop iterates through the categories list to create <option> tags. It uses the category Id as the value and the Name for the display text.

  5. Dynamic Image Preview (The Script):

    • At the bottom, there is a JavaScript event listener. Whenever the "Image URL" input changes, it immediately updates the src of the preview image so the admin can see if the link works before saving.


@model FoodItem
@{
    ViewData["Title"] = "Add Food Item";
    var categories = ViewBag.Categories as List<Category> ?? new List<Category>();
}

<div class="container my-4">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h4 class="mb-0"><i class="bi bi-plus-circle"></i> Add New Food Item</h4>
                </div>
                <div class="card-body">
                    <form asp-action="AddFoodItem" method="post">
                        <div class="row">
                            <div class="col-md-8">
                                <div class="mb-3">
                                    <label asp-for="Name" class="form-label">Item Name</label>
                                    <input asp-for="Name" class="form-control" required />
                                    <span asp-validation-for="Name" class="text-danger"></span>
                                </div>

                                <div class="mb-3">
                                    <label asp-for="Description" class="form-label">Description</label>
                                    <textarea asp-for="Description" class="form-control" rows="3"></textarea>
                                </div>

                                <div class="row">
                                    <div class="col-md-6">
                                        <div class="mb-3">
                                            <label asp-for="Price" class="form-label">Price ($)</label>
                                            <input asp-for="Price" class="form-control" type="number" step="0.01" min="0.01" required />
                                        </div>
                                    </div>
                                    <div class="col-md-6">
                                        <div class="mb-3">
                                            <label asp-for="CategoryId" class="form-label">Category</label>
                                            <select asp-for="CategoryId" class="form-select" required>
                                                @foreach (var cat in categories)
                                                {
                                                    <option value="@cat.Id">@cat.Name</option>
                                                }
                                            </select>
                                        </div>
                                    </div>
                                </div>

                                <div class="mb-3">
                                    <label asp-for="ImageUrl" class="form-label">Image URL</label>
                                    <input asp-for="ImageUrl" class="form-control" placeholder="/images/food.jpg" />
                                    <small class="text-muted">Example: /images/pizza.jpg</small>
                                </div>

                                <div class="mb-3 form-check">
                                    <input asp-for="IsAvailable" class="form-check-input" checked />
                                    <label asp-for="IsAvailable" class="form-check-label">Available</label>
                                </div>
                            </div>

                            <div class="col-md-4">
                                <div class="card">
                                    <div class="card-header">Preview</div>
                                    <div class="card-body text-center">
                                        <img id="imagePreview" src="/images/placeholder-food.jpg" alt="Preview"
                                             style="max-width: 100%; height: 150px; object-fit: cover;" />
                                    </div>
                                </div>
                            </div>
                        </div>

                        <hr />

                        <div class="d-flex justify-content-between">
                            <a href="/Admin/ManageMenu" class="btn btn-secondary">
                                <i class="bi bi-arrow-left"></i> Back
                            </a>
                            <button type="submit" class="btn btn-primary">
                                <i class="bi bi-plus-circle"></i> Add Item
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@section Scripts {
    <script>
        document.querySelector('input[name="ImageUrl"]').addEventListener('input', function(e) {
            document.getElementById('imagePreview').src = e.target.value || '/images/placeholder-food.jpg';
        });
    </script>
}

In the final step of Part 26, we handle the POST request. This is the logic that actually takes the data entered by the admin in the form and saves it permanently to the database.


Step-by-Step Explanation

  1. Attribute Definition ([HttpPost]): This specifies that the method only runs when the form is submitted (sent via a POST request). It prevents accidental data creation via a simple URL visit.

  2. Model Binding (FoodItem item): ASP.NET Core automatically maps the data from your HTML form fields (Name, Price, CategoryId, etc.) into a FoodItem object. This saves you from having to extract every field manually.

  3. Final Security Check: if (!IsAdmin()) return RedirectToAction("Index", "Home"); Even though the UI might be hidden, we check for Admin status again on the server side to ensure a malicious user hasn't tried to bypass the frontend and send a direct POST request to your database.

  4. Database Interaction:

    • _context.FoodItems.Add(item);: This adds the new object to the FoodItems collection in your Entity Framework context. At this point, it is only "tracked" in memory.

    • _context.SaveChanges();: This is the most important line. It executes the actual SQL command to insert the row into your database.

  5. Redirection: return RedirectToAction("ManageMenu"); After the save is successful, we send the admin back to the Menu Management list so they can see their newly added item.


[HttpPost]
public IActionResult AddFoodItem(FoodItem item)
{
    if (!IsAdmin()) return RedirectToAction("Index", "Home");

    _context.FoodItems.Add(item);
    _context.SaveChanges();
    return RedirectToAction("ManageMenu");
}

Step-by-Step Explanation

  1. Layout Wrapper (<div class="col-md-6 text-end">):

    • col-md-6: This Bootstrap class ensures the button container takes up half of the row's width on medium-sized screens and larger.

    • text-end: This aligns the button to the far right of its container, which is a standard design practice for "Action" buttons like "Add New" or "Create."

  2. The Anchor Tag (<a href="...">):

    • Instead of a standard button, we use an anchor tag styled as a button.

    • href="/Admin/AddFoodItem": This is the destination. It points directly to the HttpGet method in the Admin controller that we explained earlier.

  3. Bootstrap Styling (class="btn btn-success"):

    • btn: Applies the basic Bootstrap button padding and behavior.

    • btn-success: This gives the button its green color, which visually signals a "positive" or "addition" action to the user.

  4. Icon and Text:

    • <i class="bi bi-plus-circle"></i>: This uses Bootstrap Icons to display a small "plus" symbol inside a circle, making the UI more intuitive.

    • Add New Item: The clear, concise label telling the admin exactly what will happen when they click.


<div class="col-md-6 text-end">
    <a href="/Admin/AddFoodItem" class="btn btn-success">
        <i class="bi bi-plus-circle"></i> Add New Item
    </a>
</div>

Comments