简体   繁体   中英

Asp Net Core. Multiple partial views in one page. Passing Models and Calling Actions

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 class="accordion">
    <div class="accordion-item">
        <h2 class="accordion-header" id="headingOne">
            <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
                Choose Date
            </button>
        </h2>
        <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
            <div class="accordion-body">
                <partial name="Sittings" model="Model.sittingVM" />
            </div>
        </div>
    </div>
    <div class="accordion-item">
        <h2 class="accordion-header" id="headingTwo">
            <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                Choose Time
            </button>
        </h2>
        <div id="collapseTwo" class="accordion-collapse collapse show" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
            <div class="accordion-body" 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 class="form-group row bg-info bg-gradient p-3">
        <div class="col-md-4">
            <label asp-for="Date" class="control-label">Choose the Date</label>
            <input class="form-control" id="datefield" type="date" min="" value="" asp-for="Date" />
            <span asp-validation-for="Date" style="color: red;"></span>

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

        </div>

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

        </div>
        <div class="col-md-2 mt-4">
            <button type="submit" class="btn btn-primary">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; }


    }
    
}

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;)

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) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM