---
title: "Converting Create/Edit Modal to Page (Mvc)"
description: "ASP.NET Zero is the base solution for building robust and scalable web applications. Unlock your full potential today!"
url: "https://aspnetzero.com/blog/converting-create-edit-modal-to-page"
image: "https://aspnetzero.com/Images/Blog/converting-create-edit-modal-to-page.png"
---

[Blog](https://aspnetzero.com/blog)

# Converting Create/Edit Modal to Page (Mvc)

02 March 2022 7 min read [MVC](https://aspnetzero.com/blog/topics/mvc) [How To](https://aspnetzero.com/blog/topics/how-to)

![Converting Create/Edit Modal to Page (Mvc)](https://aspnetzero.com/Images/Blog/converting-create-edit-modal-to-page.png)

Share [X](https://twitter.com/intent/tweet?url=https%3A%2F%2Faspnetzero.com%2Fblog%2Fconverting-create-edit-modal-to-page&text=Converting+Create%2FEdit+Modal+to+Page+%28Mvc%29) [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Faspnetzero.com%2Fblog%2Fconverting-create-edit-modal-to-page) [Reddit](https://reddit.com/submit?url=https%3A%2F%2Faspnetzero.com%2Fblog%2Fconverting-create-edit-modal-to-page&title=Converting+Create%2FEdit+Modal+to+Page+%28Mvc%29) [Hacker News](https://news.ycombinator.com/submitlink?u=https%3A%2F%2Faspnetzero.com%2Fblog%2Fconverting-create-edit-modal-to-page&t=Converting+Create%2FEdit+Modal+to+Page+%28Mvc%29)

# Converting Create & Edit Tenant Modal to Page in Mvc

When developing applications with ASP.NET Zero, one common requirement is to **create** and **edit** tenants. Traditionally, many developers rely on **modals** to handle these operations, providing a convenient overlay for the user interface. However, there's an alternative approach that can enhance the user experience and simplify the development process: using pages instead of modals.

In this blog post, we'll provide step-by-step instructions on how to implement this technique in your own project, enabling you to make the most out of the ASP.NET Zero framework.

## Create Tenant

### Create Action Result

Create action result named `Create`. Copy `CreateModal` partial view result into that and change necessary parts as seen below:

```csharp
[AbpMvcAuthorize(AppPermissions.Pages_Tenants_Create)]
public async Task<ActionResult> Create()
{
    var editionItems = await _editionAppService.GetEditionComboboxItems();
    var defaultEditionName = _commonLookupAppService.GetDefaultEditionName().Name;
    var defaultEditionItem = editionItems.FirstOrDefault(e => e.DisplayText == defaultEditionName);
    if (defaultEditionItem != null)
    {
        defaultEditionItem.IsSelected = true;
    }

    var viewModel = new CreateTenantViewModel(editionItems)
    {
        PasswordComplexitySetting = await _passwordComplexitySettingStore.GetSettingsAsync()
    };
    return View(viewModel);
}

```

### Create View File

Then create view named `Create` in `Areas/[AppAreaName]/Views/Tenants` folder.

Copy `_CreateModel.cshtml` into your new `Create.cshtml` .

**Remove** modal header, footer partialviews and modal body tag. Add a portlet that surrounds the form tag.

The result will be like seen below:

```html
@using Abp.Json
@using MyCompanyName.AbpZeroTemplate.MultiTenancy
@using MyCompanyName.AbpZeroTemplate.Web.Areas.AppAreaName.Models.Tenants
@model CreateTenantViewModel
@section Scripts
{
    <script src="~/view-resources/Areas/AppAreaName/Views/Tenants/Create.js"></script>
    <script>
        window.passwordComplexitySetting = @Html.Raw(Model.PasswordComplexitySetting.ToJsonString(indented: true));
    </script>
}

<div class="kt-content  kt-grid__item kt-grid__item--fluid kt-grid kt-grid--hor">
    <div class="kt-subheader kt-grid__item">
        <div class="@(await GetContainerClass())">
            <div class="kt-subheader__main">
                <h3 class="kt-subheader__title">
                    <span>@L("CreateNewTenant")</span>
                </h3>
            </div>
        </div>
    </div>
    <div class="@(await GetContainerClass()) kt-grid__item kt-grid__item--fluid">
        <div class="kt-portlet">
            <div class="kt-portlet__body">
                <form name="TenantInformationsForm">
                    <div class="form-group">
                        <label for="TenancyName">@L("TenancyName")</label>
                        <input id="TenancyName" class="form-control" type="text" name="TenancyName" required maxlength="@Tenant.MaxTenancyNameLength" regex="@Tenant.TenancyNameRegex">
                    </div>

                    <div class="form-group no-hint">
                        <label for="Name">@L("Name")</label>
                        <input id="Name" type="text" name="Name" class="form-control" required maxlength="@Tenant.MaxNameLength">
                    </div>

                    <div class="kt-checkbox-list">
                        <label class="kt-checkbox">
                            <input id="CreateTenant_UseHostDb" type="checkbox" name="UseHostDb" value="true" checked="checked">
                            @L("UseHostDatabase")
                            <span></span>
                        </label>
                    </div>

                    <div class="form-group no-hint" style="display: none">
                        <label for="ConnectionString">@L("DatabaseConnectionString")</label>
                        <input id="ConnectionString" type="text" name="ConnectionString" class="form-control" required maxlength="@Tenant.MaxConnectionStringLength">
                    </div>

                    <div class="form-group">
                        <label for="AdminEmailAddress">@L("AdminEmailAddress")</label>
                        <input id="AdminEmailAddress" type="email" name="AdminEmailAddress" class="form-control" required maxlength="@MyCompanyName.AbpZeroTemplate.Authorization.Users.User.MaxEmailAddressLength">
                    </div>

                    <div class="kt-checkbox-list">
                        <label class="kt-checkbox">
                            <input id="CreateTenant_SetRandomPassword" type="checkbox" name="SetRandomPassword" value="true" checked="checked" />
                            @L("SetRandomPassword")
                            <span></span>
                        </label>
                    </div>

                    <div class="form-group no-hint tenant-admin-password" style="display: none">
                        <label for="CreateTenant_AdminPassword">@L("Password")</label>
                        <input id="CreateTenant_AdminPassword" type="password" name="AdminPassword" class="form-control" maxlength="@MyCompanyName.AbpZeroTemplate.Authorization.Users.User.MaxPlainPasswordLength" autocomplete="new-password">
                    </div>

                    <div class="form-group tenant-admin-password" style="display: none">
                        <label for="AdminPasswordRepeat">@L("PasswordRepeat")</label>
                        <input id="AdminPasswordRepeat" type="password" name="AdminPasswordRepeat" class="form-control" maxlength="@MyCompanyName.AbpZeroTemplate.Authorization.Users.User.MaxPlainPasswordLength" equalto="#CreateTenant_AdminPassword" autocomplete="new-password">
                    </div>

                    <div class="form-group no-hint">
                        <label for="EditionId">@L("Edition")</label>
                        <select class="form-control" id="EditionId" name="EditionId">
                            @foreach (var edition in Model.EditionItems)
                            {
                                <option value="@edition.Value" data-isfree="@edition.IsFree">@edition.DisplayText</option>
                            }
                        </select>
                    </div>

                    <div class="kt-checkbox-list subscription-component">
                        <label for="CreateTenant_IsUnlimited" class="kt-checkbox">
                            <input id="CreateTenant_IsUnlimited" type="checkbox" name="IsUnlimited" />
                            @L("UnlimitedTimeSubscription")
                            <span></span>
                        </label>
                    </div>

                    <div class="form-group subscription-component">
                        <label for="SubscriptionEndDateUtc">@L("SubscriptionEndDateUtc")</label>
                        <input id="SubscriptionEndDateUtc" type="datetime" name="SubscriptionEndDateUtc" class="form-control date-time-picker" required>
                    </div>

                    <div class="kt-checkbox-list subscription-component">
                        <label for="CreateTenant_IsInTrialPeriod" class="kt-checkbox">
                            <input id="CreateTenant_IsInTrialPeriod" class="md-check" type="checkbox" name="IsInTrialPeriod" value="true" />
                            @L("IsInTrialPeriod")
                            <span></span>
                        </label>
                    </div>

                    <div class="kt-checkbox-list">
                        <label for="CreateTenant_ShouldChangePasswordOnNextLogin" class="kt-checkbox">
                            <input id="CreateTenant_ShouldChangePasswordOnNextLogin" type="checkbox" name="ShouldChangePasswordOnNextLogin" value="true" checked="checked">
                            @L("ShouldChangePasswordOnNextLogin")
                            <span></span>
                        </label>
                        <label for="CreateTenant_SendActivationEmail" class="kt-checkbox">
                            <input id="CreateTenant_SendActivationEmail" type="checkbox" name="SendActivationEmail" value="true" checked="checked">
                            @L("SendActivationEmail")
                            <span></span>
                        </label>
                        <label for="CreateTenant_IsActive" class="kt-checkbox">
                            <input id="CreateTenant_IsActive" type="checkbox" name="IsActive" value="true" checked="checked">
                            @L("Active")
                            <span></span>
                        </label>
                    </div>
                </form>
            </div>
            <div class="kt-portlet__foot">
                <div class="row align-items-center">
                    <div class="col-md-12 kt-align-right pr-5">
                        <a href="/AppAreaName/Tenants" class="kt-link kt-font-bold">Cancel</a>
                        <span class="kt-margin-left-10">or</span>  <button id="btnCreateTenant" class="btn btn-brand">Submit</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

```

### Create Javascript File

Create javascript file named `Create.js`.

Copy `_CreateModal.js` into `Create.js`.

Search `modal.find` and replace all with `$` .

Remove modal function and take their content.

The result will be like seen below:

```javascript
(function () {
    $(function () {
        //Custom validation type for tenancy name
        $.validator.addMethod("tenancyNameRegex", function (value, element, regexpr) {
            return regexpr.test(value);
        }, app.localize('TenantName_Regex_Description'));

        var _tenantService = abp.services.app.tenant;
        var _$tenantInformationForm = null;
        var _passwordComplexityHelper = new app.PasswordComplexityHelper();

        _$tenantInformationForm = $('form[name=TenantInformationsForm]');
        _$tenantInformationForm.validate({
            rules: {
                TenancyName: {
                    tenancyNameRegex: new RegExp(_$tenantInformationForm.find('input[name=TenancyName]').attr('regex'))
                }
            }
        });

        //Show/Hide password inputs when "random password" checkbox is changed.
        var passwordInputs = $('input[name=AdminPassword],input[name=AdminPasswordRepeat]');
        var passwordInputGroups = passwordInputs.closest('.form-group');

        _passwordComplexityHelper.setPasswordComplexityRules(passwordInputs, window.passwordComplexitySetting);

        $('#CreateTenant_SetRandomPassword').change(function () {
            if ($(this).is(':checked')) {
                passwordInputGroups.slideUp('fast');
                passwordInputs.removeAttr('required');
            } else {
                passwordInputGroups.slideDown('fast');
                passwordInputs.attr('required', 'required');
            }
        });

        //Show/Hide connection string input when "use host db" checkbox is changed.

        var connStringInput = $('input[name=ConnectionString]');
        var connStringInputGroup = connStringInput.closest('.form-group');

        $('#CreateTenant_UseHostDb').change(function () {
            if ($(this).is(':checked')) {
                connStringInputGroup.slideUp('fast');
                connStringInput.removeAttr('required');
            } else {
                connStringInputGroup.slideDown('fast');
                connStringInput.attr('required', 'required');
            }
        });

        $('.date-time-picker').datetimepicker({
            locale: abp.localization.currentLanguage.name,
            format: 'L'
        });

        var $subscriptionEndDateDiv = $('input[name=SubscriptionEndDateUtc]').parent('div');
        var $isUnlimitedInput = $('#CreateTenant_IsUnlimited');
        var subscriptionEndDateUtcInput = $('input[name=SubscriptionEndDateUtc]');
        function toggleSubscriptionEndDateDiv() {
            if ($isUnlimitedInput.is(':checked')) {
                $subscriptionEndDateDiv.slideUp('fast');
                subscriptionEndDateUtcInput.removeAttr('required');
            } else {
                $subscriptionEndDateDiv.slideDown('fast');
                subscriptionEndDateUtcInput.attr('required', 'required');
            }
        }

        $isUnlimitedInput.change(function () {
            toggleSubscriptionEndDateDiv();
        });

        var $editionCombobox = $('#EditionId');
        $editionCombobox.change(function () {
            var isFree = $('option:selected', this).attr('data-isfree') === "True";
            var selectedValue = $('option:selected', this).val();

            if (selectedValue === "" || isFree) {
                $('.subscription-component').slideUp('fast');
                if (isFree) {
                    $isUnlimitedInput.prop("checked", true);
                } else {
                    $isUnlimitedInput.prop("checked", false);
                }
            } else {
                $('.subscription-component').slideDown('fast');
            }
        });

        toggleSubscriptionEndDateDiv();
        $editionCombobox.trigger('change');

        function save() {
            if (!_$tenantInformationForm.valid()) {
                return;
            }

            var tenant = _$tenantInformationForm.serializeFormToObject();

            //take selected date as UTC
            if ($('#CreateTenant_IsUnlimited').is(':visible') && !$('#CreateTenant_IsUnlimited').is(':checked')) {
                tenant.SubscriptionEndDateUtc = $('.date-time-picker').data("DateTimePicker").date().format("YYYY-MM-DDTHH:mm:ss") + 'Z';
            } else {
                tenant.SubscriptionEndDateUtc = null;
            }

            if (tenant.SetRandomPassword) {
                tenant.Password = null;
                tenant.AdminPassword = null;
            }

            if (tenant.UseHostDb) {
                tenant.ConnectionString = null;
            }

            abp.ui.setBusy();
            _tenantService.createTenant(
                tenant
            ).done(function () {
                abp.notify.info(app.localize('SavedSuccessfully'));
                window.location.href = "/AppAreaName/Tenants";
            }).always(function () {
                abp.ui.clearBusy();
            });
        };

        $("#btnCreateTenant").click(save);//Now there is no modal button. Thats why you need to call save function with another button
    });
})();
```

And finally go `Index.cshtml` and change **Create new tenant** button as seen below

```html
<a href="/[AppAreaName]/Tenants/Create" class="btn btn-primary">
    <i class="fa fa-plus"></i> @L("CreateNewTenant")
</a>
```

*Result* ![converting-modal-to-page-tenant-create](https://aspnetzero.com/Images/Blog/converting-modal-to-page-tenant-create.png)

## Edit Tenant

Converting edit modal to edit page has same step with converting create modal to create page. The results will be as seen below.

### Create Action Result

*TenantsController.cs*

```csharp
[AbpMvcAuthorize(AppPermissions.Pages_Tenants_Edit)]
public async Task<ActionResult> Edit(int id)
{
    var tenantEditDto = await _tenantAppService.GetTenantForEdit(new EntityDto(id));
    var editionItems = await _editionAppService.GetEditionComboboxItems(tenantEditDto.EditionId);
    var viewModel = new EditTenantViewModel(tenantEditDto, editionItems);

    return View(viewModel);
}
```

### Create View File

*Edit.cshtml*

```html
@using Abp.Extensions
@using MyCompanyName.AbpZeroTemplate.MultiTenancy
@using MyCompanyName.AbpZeroTemplate.Web.Areas.AppAreaName.Models.Common.Modals
@using MyCompanyName.AbpZeroTemplate.Web.Areas.AppAreaName.Models.Tenants
@model EditTenantViewModel

@section Scripts
{
    <script src="~/view-resources/Areas/AppAreaName/Views/Tenants/Edit.js"></script>
}

<div class="kt-content  kt-grid__item kt-grid__item--fluid kt-grid kt-grid--hor">

    <div class="kt-subheader kt-grid__item">
        <div class="@(await GetContainerClass())">
            <div class="kt-subheader__main">
                <h3 class="kt-subheader__title">
                    <span>@L("EditTenant")</span>
                </h3>
                <span class="kt-subheader__separator kt-subheader__separator--v"></span>
                <span class="kt-subheader__desc">
                    @Model.Tenant.TenancyName
                </span>
            </div>
        </div>
    </div>
    <div class="@(await GetContainerClass()) kt-grid__item kt-grid__item--fluid">
        <div class="kt-portlet">
            <div class="kt-portlet__body">
                <form name="TenantInformationsForm">

                    <input type="hidden" name="Id" value="@Model.Tenant.Id" />
                    <input type="hidden" name="TenancyName" value="@Model.Tenant.TenancyName" />

                    <div class="form-group">
                        <label for="Name">@L("Name")</label>
                        <input id="Name" type="text" name="Name" value="@Model.Tenant.Name" class="form-control edited" required maxlength="@Tenant.MaxNameLength">
                    </div>

                    @if (!Model.Tenant.ConnectionString.IsNullOrEmpty())
                    {
                        <div class="form-group">
                            <label for="ConnectionString">@L("DatabaseConnectionString")</label>
                            <input id="ConnectionString" type="text" name="ConnectionString" class="form-control edited" value="@Model.Tenant.ConnectionString" required maxlength="@Tenant.MaxConnectionStringLength">
                        </div>

                        <div>
                            <span class="help-block text-warning">@L("TenantDatabaseConnectionStringChangeWarningMessage")</span>
                        </div>
                    }

                    <div class="form-group">
                        <label for="EditionId">@L("Edition")</label>
                        <select class="form-control" id="EditionId" name="EditionId">
                            @foreach (var edition in Model.EditionItems)
                            {
                                <option value="@edition.Value" data-isfree="@edition.IsFree" selected="@edition.IsSelected">@edition.DisplayText</option>
                            }
                        </select>
                    </div>

                    <div class="kt-checkbox-list subscription-component">
                        <label class="kt-checkbox">
                            <input id="CreateTenant_IsUnlimited" type="checkbox" name="IsUnlimited" @(!Model.Tenant.SubscriptionEndDateUtc.HasValue ? "checked=\"checked\"" : "") />
                            @L("UnlimitedTimeSubscription")
                            <span></span>
                        </label>
                    </div>

                    <div class="form-group position-relative">
                        <label for="SubscriptionEndDateUtc">@L("SubscriptionEndDateUtc")</label>
                        <input id="SubscriptionEndDateUtc" type="datetime" name="SubscriptionEndDateUtc" value="@(Model.Tenant.SubscriptionEndDateUtc)" class="form-control edited date-time-picker" @(!Model.Tenant.SubscriptionEndDateUtc.HasValue ? "required" : "")>
                    </div>

                    <div class="kt-checkbox-list subscription-component">
                        <label class="kt-checkbox">
                            <input id="EditTenant_IsInTrialPeriod" type="checkbox" name="IsInTrialPeriod" value="true" @(Model.Tenant.IsInTrialPeriod ? "checked=\"checked\"" : "") />
                            @L("IsInTrialPeriod")
                            <span></span>
                        </label>
                    </div>

                    <div class="kt-checkbox-list">
                        <label class="kt-checkbox">
                            <input id="EditTenant_IsActive" type="checkbox" name="IsActive" value="true" @Html.Raw(Model.Tenant.IsActive ? "checked=\"checked\"" : "")>
                            @L("Active")
                            <span></span>
                        </label>
                    </div>

                </form>
            </div>
            <div class="kt-portlet__foot">
                <div class="row align-items-center">
                    <div class="col-md-12 kt-align-right pr-5">
                        <a href="/AppAreaName/Tenants" class="kt-link kt-font-bold">Cancel</a>
                        <span class="kt-margin-left-10">or</span>  <button id="btnEditTenant" class="btn btn-brand">Submit</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

```

### Create Javascript File

*Edit.js*

```javascript
(function () {
    $(function () {
        var _tenantService = abp.services.app.tenant;
        var _$tenantInformationForm = null;

_$tenantInformationForm = $('form[name=TenantInformationsForm]');
        _$tenantInformationForm.validate();

        $('.date-time-picker').datetimepicker({
            locale: abp.localization.currentLanguage.name,
            format: 'L'
        });

        var $subscriptionEndDateDiv = $('input[name=SubscriptionEndDateUtc]').parent('div');
        var isUnlimitedInput = $('#CreateTenant_IsUnlimited');
        function toggleSubscriptionEndDateDiv() {
            if (isUnlimitedInput.is(':checked')) {
                $subscriptionEndDateDiv.slideUp('fast');
            } else {
                $subscriptionEndDateDiv.slideDown('fast');
            }
        }

        isUnlimitedInput.change(function () {
            toggleSubscriptionEndDateDiv();
        });

        var $editionCombobox = $('#EditionId');
        var $isInTrialCheckbox = $('#EditTenant_IsInTrialPeriod');
        $editionCombobox.change(function () {
            var isFree = $('option:selected', this).attr('data-isfree') === "True";
            var selectedValue = $('option:selected', this).val();
            if (isFree) {
                $isInTrialCheckbox.closest('div').slideUp('fast');
            } else {
                $isInTrialCheckbox.closest('div').slideDown('fast');
            }

            if (selectedValue <= 0) {
                $('.subscription-component').slideUp('fast');
                if (!isUnlimitedInput.is(':checked')) {
                    $subscriptionEndDateDiv.slideDown('fast');
                }
            } else {
                $('.subscription-component').slideDown('fast');
            }
        });

        $editionCombobox.trigger('change');
        toggleSubscriptionEndDateDiv();

function edit() {
            if (!_$tenantInformationForm.valid()) {
                return;
            }

            var tenant = _$tenantInformationForm.serializeFormToObject();

            //take selected date as UTC
            if ($('#CreateTenant_IsUnlimited').is(':visible') && !$('#CreateTenant_IsUnlimited').is(':checked')) {
                tenant.SubscriptionEndDateUtc = $('.date-time-picker').data('DateTimePicker').date().format("YYYY-MM-DDTHH:mm:ss") + 'Z';
            } else {
                tenant.SubscriptionEndDateUtc = null;
            }

            abp.ui.setBusy();
            _tenantService.updateTenant(
                tenant
            ).done(function () {
                abp.notify.info(app.localize('SavedSuccessfully'));
                location.href="/AppAreaName/Tenants";
            }).always(function () {
               abp.ui.clearBusy();
            });
        };

        $("#btnEditTenant").click(edit);
    });
})();
```

Then go `index.js` and change edit button on data table.

```javascript
{
    text: app.localize('Edit'),
    visible: function () {
        return _permissions.edit;
    },
    action: function (data) {
        location.href = "/AppAreaName/Tenants/Edit?id=" + data.record.id;//change that
    }
},
```

*Result* ![converting-modal-to-page-tenant-edit](https://aspnetzero.com/Images/Blog/converting-modal-to-page-tenant-edit.png)

## See the full documentation

Explore detailed guides, API references, and step-by-step tutorials for ASP.NET Zero.

[Browse documentation](https://aspnetzero.com/documents)

## Have questions before purchasing?

Schedule a free consultation with our team to find the right plan for your project.

[Schedule a meeting](https://aspnetzero.com/schedule-meeting)

## You might also like

### [Business Benefits of Using ASP.NET Zero for Enterprise Software Development](https://aspnetzero.com/blog/business-benefits-of-aspnetzero)

11 September 2026

### [Common Mistakes and Errors When Hosting ASP.NET Core Apps](https://aspnetzero.com/blog/common-mistakes-and-errors-hosting-aspnet-core-apps)

26 August 2026

### [Using AutoMapper After Migrating to Mapperly](https://aspnetzero.com/blog/using-automapper-after-migrating-to-mapperly)

04 August 2026

## Recent posts

### [Business Benefits of Using ASP.NET Zero for Enterprise Software Development](https://aspnetzero.com/blog/business-benefits-of-aspnetzero)

11 September 2026

### [Common Mistakes and Errors When Hosting ASP.NET Core Apps](https://aspnetzero.com/blog/common-mistakes-and-errors-hosting-aspnet-core-apps)

26 August 2026

### [Using AutoMapper After Migrating to Mapperly](https://aspnetzero.com/blog/using-automapper-after-migrating-to-mapperly)

04 August 2026

## Start building with ASP.NET Zero

Full source code, premium support, Angular, React & MVC UI options.

[View pricing](https://aspnetzero.com/pricing)

## Topics
