Asp.net MVC core, posting previous ViewModel from PopupView

50 views Asked by At

Maybe I'm looking at this the wrong way, maybe the fact that the browser is showing the view as a pop up doesn't change the fact that for MVC this is just a different View with it's own ViewModel. Since this is a form inside a form in a way, maybe there are better ways to do the following;

The initial view (CreateTimeslot.cshtml) is a form with properties of a workshop to be scheduled. name, description,.., And a speaker multiselect list:

@model MDFrontend.Models.Timeslots.TimeslotManagementViewModel
<div class="form-group">
            <label asp-for="StartTime" class="control-label"></label>
            <input asp-for="StartTime" type="datetime" class="form-control" value="@startTime" />
            <span asp-validation-for="StartTime" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="EndTime" class="control-label"></label>
            <input asp-for="EndTime" type="datetime" class="form-control" value="@startTime.Add(Model.WorkshopDuration)" readonly />
            <span asp-validation-for="EndTime" class="text-danger"></span>
        </div>

        <!--------------------------------------------------------------SpeakerBox---------------------------------------------------------------------->
        <div class="form-group">
            <label asp-for="Speakers" class="control-label"></label>
            <select asp-for="SpeakerIDs" id="speakerBox" name="SpeakerIDs[]" asp-items="@Model.Speakers" multiple="multiple">
            </select>
            <span asp-validation-for="SpeakerIDs" class="text-danger"></span> <!--This is not showing, asp-validation-summary does-->
        </div>

        <button onclick="showFormInPopup('@Url.Action("CreateSpeaker","SpeakerAdmin",Model,Context.Request.Scheme)',
                                                        'New Speaker')" type="button" id="btnAddSpeaker" class="btn btn-primary"> @Localizer["Add_Speaker"]
        </button>

I'm passing the TimeslotManagementViewModel in the Url.Action method, which I'm mapping to the CreateSpeakerViewModel

public class CreateSpeakerViewModel
{
    public string Firstname { get; set; }

    public string Lastname { get; set; }

    public TimeslotManagementViewModel oldModel { get; set; }
}

This view is shown as a popup:

<!-------------------------------------------Hidden Add Speaker Popup--------------------------------------------------->

    <div class="modal" tabindex="-1" role="dialog" id="form-modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">

                </div>
            </div>
        </div>
    </div>

<!-------------------------------------------Hidden Add Speaker Popup--------------------------------------------------->

The body of this CreateSpeaker View:

@model MDFrontend.Models.Speakers.CreateSpeakerViewModel
<form asp-action="CreateSpeaker" asp-controller="SpeakerAdmin">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Firstname" class="control-label"></label>
            <input asp-for="Firstname" class="form-control" />
            <span asp-validation-for="Firstname" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="Lastname" class="control-label"></label>
            <input asp-for="Lastname" class="form-control" />
            <span asp-validation-for="Lastname" class="text-danger"></span>
        </div>
        
        <div class="form-group" >
            <input type="submit" value="Save" asp-action="CreateSpeaker" asp-controller="SpeakerAdmin" 
                    formmethod="post" class="btn btn-primary" />
        </div>
    </form>

The CreateSpeaker Post method is receiving this simple form, adding them to the db, redirecting to the initial CreateTimeslot view with an updated multiselect.

[HttpPost]
    [Authorize(Roles = RoleConstant.Admin)]
    public async Task<IActionResult> CreateSpeaker(CreateSpeakerViewModel vm, 
   TimeslotManagementViewModel model)
    {
    //The idea would be to have TimeslotManagementViewModel model posted back with the set values by the user before "AddSpeaker" was clicked.
 }

However with this solution the previous set inputs are lost to the user. So atm I'm thinking either to use map every property of the TimeslotManagementViewModel to the CreateSpeakerViewModel to pass them between controllers or maybe an Ajax call could work or drop the popup all togheter. Or better yet someone here knows a better option?

Many thanks!

1

There are 1 answers

0
user1638340 On

After some trail and error realized the best, maybe only solution comes by using some simple Javascript.

function SaveSpeaker(e) {

var firstname = $('#txtFirstname').val();
var lastname = $('#txtLastname').val();

$.ajax({
    url: '/SpeakerAdmin/CreateSpeaker',
    dataType: 'Json',
    type: "POST",
    data: { firstname: firstname, lastname: lastname },
    success: function (data, status, jqXHR) {
        console.log('success');
        if (data.valFirstname == false) {
            $('#valFirstname').text('Firstname not complete');
        }
        if (data.valLastname == false) {
            $('#valLastname').val('Lastname not complete')
        }
        if (data.valSpeaker == true) {
            $('#form-modal').modal('hide');
            $('#valSpeaker').text('Speaker added');
            $('#speakerBox').append(new Option(firstname + " "  + lastname, data.speakerID))
        }
        
    },
    error: function (jqXHR, status, err) {
        
    },
    complete: function (jqXHR, status) {
        
    }
});

So instead of posting the form just using an Ajax call to post to the controller and return Json to populate the new select option.