Home > Software engineering >  Asp Net Core. Multiple partial views in one page. Passing Models and Calling Actions
Asp Net Core. Multiple partial views in one page. Passing Models and Calling Actions

Time:05-05

I'm a student and new to working with MVC Asp.net.

I'm trying to create a booking system and would like to have all of the steps on one page, by using an accordion of sorts.

I'm trying to understand if I will be able to achieve it by using several different models and calling asp-actions from different partial views.

At the moment if i set model attribute on Partial view of SittingTimes, it comes up as null reference, as SittingTimeVM has to be set after Sitting action is performed.But if i dont set it its just returns me a partial view in a completely separate page.

What can I do about that? Or should I just look into a different options for creating One Page system?

Controller:

        public async Task<IActionResult> Restaurants()
        {
            var company = await _context.Companies.Include(c => c.Restaurants).FirstAsync(c => c.Id == 1);
            return View(company);
        }
        public async Task<IActionResult> SittingOne(int restaurantId)
        {
            var restaurant = await _context.Restaurants.FirstOrDefaultAsync(s => s.Id == restaurantId);
            var parent = new Models.ParentModel
            {
                sittingVM = CreateNewSittingVM(restaurantId)
               
            };
            return View(parent);
        }



        public Models.Sittings.SittingVM CreateNewSittingVM(int restaurantId) => new 
        Models.Sittings.SittingVM
        {
            RestaurantId = restaurantId,
            SittingType = new SelectList(_context.SittingTypes, "Id", "Description")
        };
        [HttpPost]
        public async Task<IActionResult> SittingTimes(Models.Sittings.SittingVM s)
        {

            var allSittings = await _context.Sitings.Where(st => st.StartTime.Day == 
            s.Date.Day && st.SittingTypeId == s.SittingTypeId).FirstOrDefaultAsync();

            if (allSittings == null)
            {
                s.ErrorNumber = 1;
                return RedirectToAction("ErrorNoSitting", s);
            }
            if (allSittings.isClosed == true)
            {
                s.ErrorNumber = 2;
                return RedirectToAction("ErrorNoSitting", s);
            }
            var sittimes = new SittingTimesVM
            {
                
                    SittingId = allSittings.Id,
                    NumberOfGuests = s.NumberOfGuests,
                    Date = s.Date,
                    RestaurantId = s.RestaurantId,
                    SittingsStart = allSittings.StartTime,
                    SittingsEnd = allSittings.EndTime,
                    CutOffTime = allSittings.CutOff,
                
            };

      

            var sitting = await _context.Sitings.FirstOrDefaultAsync(r => r.Id == sittimes.SittingId);
            if (sitting.Capacity < sittimes.NumberOfGuests)
            {
                s.ErrorNumber = 3;
                return RedirectToAction("ErrorNoSitting", s);
            }


            return PartialView("SittingTimes",sittimes);
            }

Main View with Partial Views in it:

@model ReservationSystemTeamD.Models.ParentModel;



<div >
    <div >
        <h2  id="headingOne">
            <button  type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
                Choose Date
            </button>
        </h2>
        <div id="collapseOne"  aria-labelledby="headingOne" data-bs-parent="#accordionExample">
            <div >
                <partial name="Sittings" model="Model.sittingVM" />
            </div>
        </div>
    </div>
    <div >
        <h2  id="headingTwo">
            <button  type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                Choose Time
            </button>
        </h2>
        <div id="collapseTwo"  aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
            <div  id="div2">
               
                       <partial name="SittingTimes"/>
                  
            </div>
        </div>
    </div>
</div>


Parent Model:

using ReservationSystemTeamD.Models.Sittings;

namespace ReservationSystemTeamD.Models
{
    public class ParentModel
    {
        public SittingVM sittingVM { get; set; }
        public SittingTimesVM sittingTimesVM { get; set; }

    }
}

PartialView of Sitting:

@model ReservationSystemTeamD.Models.Sittings.SittingVM




<form asp-action="SittingTimes" method="post">
    <div >
        <div >
            <label asp-for="Date" >Choose the Date</label>
            <input  id="datefield" type="date" min="" value="" asp-for="Date" />
            <span asp-validation-for="Date" style="color: red;"></span>

        </div>
        <div >
            <label asp-for="NumberOfGuests" >Number of Guests</label>
            <input type="number" asp-for="NumberOfGuests" id="NumberofGuest"  min=1 max=10 />
            <span asp-validation-for="NumberOfGuests" style="color: red;"></span>

        </div>

        <div >
            <label asp-for=SittingTypeId >Sitting Type</label>
            <select asp-for=SittingTypeId asp-items=Model.SittingType type="text" >
                <option value="" data-val="true">Please Select</option>
            </select>
            <span asp-validation-for="SittingTypeId" style="color: red;"></span>

        </div>
        <div >
            <button type="submit" >Submit</button>

        </div>
        </div>
   
    <input type="hidden" asp-for=RestaurantName />
    <input type="hidden" asp-for=RestaurantId />
    <input type="hidden" asp-for=SittingType />
    <input type="hidden" asp-for=SittingTypeId />

</form>
            
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script>
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth()   1;
    var yyyy = today.getFullYear();
    if (dd < 10) {
       dd = '0'   dd;
    }
    if (mm < 10) {
       mm = '0'   mm;
    }
    today = yyyy   '-'   mm   '-'   dd;
    document.getElementById("datefield").setAttribute("min", today).setAttribute("value", today);
</script>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}

SittingVM:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.ComponentModel.DataAnnotations;

namespace ReservationSystemTeamD.Models.Sittings
{
    public class SittingVM
    {
        [Required(ErrorMessage = "Please enter a date")]
        [DataType(DataType.Date)]
        public DateTime Date { get; set; }
        public int RestaurantId { get; set; }
        public string RestaurantName { get; set; }     
        public int NumberOfGuests { get; set; }     
        public int? SittingTypeId { get; set; }
        public SelectList SittingType { get; set; }
        public List<SittingTimesVM>? SittingTimes { get; set; }
        public int ErrorNumber { get; set; }
    }

  
}

SittingTimesVM:

using System.ComponentModel.DataAnnotations;

namespace ReservationSystemTeamD.Models.Sittings
{
    public class SittingTimesVM
    {
        public int SittingId { get; set; }
        public int SittingTypeId { get; set; }
        public DateTime Date { get; set; }
        public int RestaurantId { get; set; }
        public int NumberOfGuests { get; set; }
        [DataType(DataType.Time)]
        [DisplayFormat(DataFormatString = "{0:HH:mm tt}")]
        public DateTime ChosenTime { get; set; }
        public DateTime SittingsStart { get; set; }
        public DateTime SittingsEnd { get; set; }
        public int CutOffTime { get; set; }
        public string Email { get; set; }


    }
    
}

CodePudding user response:

A partial view is - as the name states - just a part of another view.

In MVC you create a Model, a Controller with an action and a View that is served via this action. The view is now completely build up, it's view model is created and everything will be served to the requester.

In your case you just wrote

<partial name="SittingTimes"/>

which indicates "render this partial in this current main view and then serve it to the requesting party". Everything is done in one single controller action.

If you want to use data in your partial you will have to use something like this:

@await Html.PartialAsync("_PartialName", model)

Where model holds an object.

If you want to use different controller actions within one page you will have to use some AJAX look here.

You were on the right path of separating the concerns but just had a misconception about MVC. Just keep learning ;)

CodePudding user response:

You can try to create settingTimesVM in SittingOne(int restaurantId),and pass ParentModel.sittingTimesVM to partial view like this:

public async Task<IActionResult> SittingOne(int restaurantId)
        {
            var restaurant = await _context.Restaurants.FirstOrDefaultAsync(s => s.Id == restaurantId);
            var parent = new Models.ParentModel
            {
                sittingVM = CreateNewSittingVM(restaurantId)

            };
            parent.SittingTimesVM = CreateNewSittingTimesVM(parent.SittingVM);
            return View(parent);
        }

        public Models.Sittings.SittingVM CreateNewSittingVM(int restaurantId) => new
         Models.Sittings.SittingVM
        {
            RestaurantId = restaurantId,
            SittingType = new SelectList(_context.SittingTypes, "Id", "Description")
        };
        public async Models.Sittings.SittingTimesVM CreateNewSittingTimesVM(Models.Sittings.SittingVM s)
        {

            var allSittings = await _context.Sitings.Where(st => st.StartTime.Day ==
            s.Date.Day && st.SittingTypeId == s.SittingTypeId).FirstOrDefaultAsync();

            if (allSittings == null)
            {
                s.ErrorNumber = 1;
                return RedirectToAction("ErrorNoSitting", s);
            }
            if (allSittings.isClosed == true)
            {
                s.ErrorNumber = 2;
                return RedirectToAction("ErrorNoSitting", s);
            }
            var sittimes = new SittingTimesVM
            {

                SittingId = allSittings.Id,
                NumberOfGuests = s.NumberOfGuests,
                Date = s.Date,
                RestaurantId = s.RestaurantId,
                SittingsStart = allSittings.StartTime,
                SittingsEnd = allSittings.EndTime,
                CutOffTime = allSittings.CutOff,

            };


            return sittimes;
        }

View:

@await Html.PartialAsync("SittingTimes", Model.sittingTimesVM) 
  • Related