Base solution for your next web application
Open Closed

How to add a multi-select drop-down in Modal? #8725


User avatar
0
ISTeam created

I did not find any documentation or tutorial to add a dropdown in 'ASP.NETCore MVC & jQuery' template. I need to add a multi select dropdown in the project to map multiple clients with organization unit inbuilt entity of the template.

I have extended OraganizationUnit entity with many to many relationship with 'EnterpriseClient' entity. In Create OrganizationUnit modal pop-up, there is only one input 'Name'. I have added a multi-select dropdown in that modal to allow user to select one or more EnterpriseClients which I can map from the backend.

The multiselect dropdown is basic and has plain text only. Currently with code similar as below in X.Dashboard.Web.Mvc\Areas\App\Views\OrganizationUnits\ _CreateModal.cshtml:

 <div class="form-group">
        <select class="form-control selectpicker" multiple data-max-options="5" title="Choose Enterprise Client(s)" data-selected-text-format="count"  data-live-search="true" id="EnterpriseClients" name="EnterpriseClients">
            @foreach (var item in @Model.EnterpriseClients)
            {
                <option value="@item.Key" title="@item.Value" data-tokens="@item.Value">@item.Value</option>
            }
        </select>
</div>

Added below code in the init method of X.Dashboard.Web.Mvc\wwwroot\view-resources\Areas\App\Views\OrganizationUnits\ _CreateModal.js

_$OUECCombobox = _modalManager.getModal().find('#EnterpriseClients');
_$OUECCombobox.selectpicker({
    iconBase: "fa",
    tickIcon: "fa fa-check"
});

To setup dropdown text and value, I added below code in X.Dashboard.Web.Mvc\Areas\App\Models\OrganizationUnits\CreateOrganizationUnitModalViewModel.cs

public CreateOrganizationUnitModalViewModel(long? parentId, Dictionary<string, string> enterpriseClients)
{
    ParentId = parentId;
    EnterpriseClients = enterpriseClients;
}
public Dictionary<string, string> EnterpriseClients { get; set; }

Updated code in the controller method to show the dropdown correctly in the create phase : X.Dashboard.Web.Mvc\Areas\App\Controllers\OrganizationUnitsController.cs

[AbpMvcAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
public PartialViewResult CreateModal(long? parentId)
{
    var enterpriseClients = _enterpriseClientRepository.GetAllList().ToDictionary(ec => ec.Id.ToString(), ec => ec.ClientCode);
    return PartialView("_CreateModal", new CreateOrganizationUnitModalViewModel(parentId , enterpriseClients));
}

Added below property which seems wrong : X.Dashboard.Application.Shared\Organizations\Dto\OrganizationUnitDto.cs public Dictionary<string, string> EnterpriseClientIds { get; set; } X.Dashboard.Application.Shared\Organizations\Dto\CreateOrganizationUnitInput.cs public List<int> EnterpriseClients { get; set; }

I need all the selected EnterpriseClients in the AppService but it was null initially and after making adding two property or some other trial and error to fix the problem I am getting an error in UI when 'Save' button is clicked. X.Dashboard.Application\Organizations\OrganizationUnitAppService.cs

[AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
public async Task<OrganizationUnitDto> CreateOrganizationUnit(CreateOrganizationUnitInput input)
{
    var organizationUnit = new OrganisationUnit(AbpSession.TenantId, input.DisplayName, input.ParentId);
    if (input.EnterpriseClients != null && input.EnterpriseClients.Count > 0)
    {
        ....
    }
}

No idea how to properly define Dtos for dropdown and how to get those multiple selected values of the dropdown in the backend service call. I also need to make changes in the edit modal, but not sure how and what changes are required.

Below is the error screenshot.

Any suggestions to solve it?

Thanks


3 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    hi ISTeam

    Can you share the full code for _CreateModal.js? And class code for CreateOrganizationUnitInput.

    It looks like the parameters of your request are incorrect.

    If possible please share screenshot of http request for CreateOrganizationUnit operation.

    eg:

  • User Avatar
    0
    ISTeam created

    Thanks @maliming for your response. But fortunately by changing the dropdown DOM element name in _CreateModal.cshtml fixed one of the issues : name="EnterpriseClients[]"

    Now I can see the dropdown and associate OU with EnterpriseClients as well. Both models are as below :

    public class OrganisationUnit : OrganizationUnit
    {
        // https://forum.aspnetboilerplate.com/viewtopic.php?f=5&t=11109&hilit=extend
        public virtual bool HasMultipleClients { get; set; }
        public OrganisationUnit()    {    }
        public OrganisationUnit(int? tenantId, string displayName, long? parentId = null) : base(tenantId, displayName, parentId)    {    }
        public IList<OrganisationUnitEnterpriseClient> OrganisationUnitEnterpriseClients { get; set; }
    }
    
    // Third entity that contains mapping between OrganizationUnit(OU) and EnterpriseClient(EC)
    public class OrganisationUnitEnterpriseClient
    {
        public long OrganisationUnitId { get; set; }
        public OrganisationUnit OrganisationUnit { get; set; }
        public int EnterpriseClientId { get; set; }
        public EnterpriseClient EnterpriseClient { get; set; }
    }
    
    

    DashboardDbContext.cs => OnModelCreating method to define many to many relationship for both entities:

    modelBuilder.Entity<OrganisationUnitEnterpriseClient>()
        .HasKey(ouec => new { ouec.OrganisationUnitId, ouec.EnterpriseClientId });
    

    With code in original section and above model setup, I am able to save an OU with one or many clients in the database like below:

    X.Dashboard.Application\Organizations\OrganizationUnitAppService.cs

    public async Task<OrganizationUnitDto> CreateOrganizationUnit(CreateOrganizationUnitInput input)
    {
        var organizationUnit = new OrganisationUnit(AbpSession.TenantId, input.DisplayName, input.ParentId);
        await _organizationUnitManager.CreateAsync(organizationUnit);
        
        if (input.EnterpriseClients != null && input.EnterpriseClients.Count > 0)
        {
            if (input.EnterpriseClients.Count > 1)        {            organizationUnit.HasMultipleClients = true;        }
            else        {            organizationUnit.HasMultipleClients = false;        }
            organizationUnit.OrganisationUnitEnterpriseClients = new List<OrganisationUnitEnterpriseClient>();
            // Set mapping between OrganizationUnit and selected EnterpriseClient(s)
            foreach (int enterpriseClientId in input.EnterpriseClients)
            {
                var link = new OrganisationUnitEnterpriseClient()
                {
                    EnterpriseClientId = enterpriseClientId,
                    OrganisationUnitId = organizationUnit.Id,
                    EnterpriseClient = await _enterpriseClientRepository.GetAsync(enterpriseClientId),
                    OrganisationUnit = organizationUnit
                };
                organizationUnit.OrganisationUnitEnterpriseClients.Add(link);
            }
        }
        await CurrentUnitOfWork.SaveChangesAsync();
        return ObjectMapper.Map<OrganizationUnitDto>(organizationUnit);
    }
    

    Here, my extended class has 's' in the name : OrganisationUnit and the Abp class is OrganizationUnit. For the edit modal I am not sure about the required code change. How to update Dtos and Input models etc. to first show existing relationship between OU and EC - EnterpriseClient and then how to update it? If it was a regular dropdown then using premitive property it could be done hopefully.

    But as its a multiselect dropdown plus no example found on the internet or this forum unfortunately that can give some hint on how to achieve that?

  • User Avatar
    0
    maliming created
    Support Team

    hi

    You can add/remove OrganizationisationEnterpriseClients based on the parameters in the dto in the UpdateOrganizationUnit method.

    This requires you to load organizationUnit's OrganisationUnitEnterpriseClients in advance. Then you can determine what needs to be removed and what needs to be added.

    Hope I understood your question correctly. : )