vtfuture / BForms

Bootstrap Forms for ASP.NET MVC
MIT License
62 stars 33 forks source link

Loading remote data in Dropdown List #235

Closed meister-d closed 8 years ago

meister-d commented 9 years ago

Hello BForms-Team, first of all thank you for this powerfull piece of work ;-) As i didn't see where i could add a Feature Request i use this way to file one... Is there a simple way to load remote data to a Dropdown List, like in the examples on the select2 Website (https://select2.github.io/examples.html) ? I miss a bit the ability to interact while in the editable forms. If its possible an example would be also very usefull.

Regards meister-d

cristipufu commented 9 years ago

Hello,

First of all, please update to the latest package version. We just added a new BsControlType.DropdownListRemote.

You will find an example in the demo register page (the countries list).

Quick demo:

Model:

[Required(ErrorMessageResourceName = "RequiredField", ErrorMessageResourceType = typeof(Resource))]
[Display(Name = "Location", Prompt = "PromptLocation", ResourceType = typeof(Resource))]
[BsControl(BsControlType.DropDownListRemote)]
public BsSelectList<string> CountriesList { get; set; }

View:

<div class="col-sm-6 col-md-6 col-lg-6 form-group">
        @Html.BsLabelFor(m => m.CountriesList)
        <div class="input-group">
            @Html.BsSelectFor(m => m.CountriesList, null, new 
                            { 
                                url = Url.Action("GetCountriesPaged", "Login", new { area = "Demo" })
                            })
            @Html.BsValidationFor(m => m.CountriesList)
        </div>
    </div>

As you can see, you need to specify the remote data url.

Controller:

public BsJsonResult GetCountriesPaged(int page, string search)
        {
            var pageSize = 10;
            var ddlWithSelected = Lists.AllCounties<string>();

            var q = ddlWithSelected.Items
                .Where(x => x.Text.ToLower().Contains(search.ToLower()));

            var items = q.Skip((page - 1) * pageSize)
                .Take(pageSize)
                .ToList();

            return new BsJsonResult(new
            {
                PageSize = pageSize,
                Count = q.Count(),
                Items = items
            });
        }

The remote data controller action must return the total elements count, the page size and the list of items that match the search term, paginated, in the form of a List<BsSelectListItem>.

Javascript:

No need to do anything else, just the old $form.bsInitUI().


Hope it helps!

PS: ListBoxRemote will be coming soon (multiple choices remote data dropdown list).

meister-d commented 9 years ago

Hi Cristi, many thanx for your fast reply! Today I have integrated the DropDownListRemote into my project and it works like a charm :-)

During the Implementation some suggestions / questions came up:

Is there a possibility to show kind of error message if the remote call is unsuccessful (eg "Server is unavailable, please try again later...") ?

What also would be nice is if the initialization could be more simple for the initial values. Something like :

@Html.BsSelectFor(m => m.CountriesList, null, new 
                            { 
                                initUrl = Url.Action("GetInitialUser/m.UserId", "Login",  ),
                                url = Url.Action("GetCountriesPaged", "Login", new { area = "Demo" })
                            })

In the select2 js they provide such a possibility:

initSelection: function (element, callback) {
                // the input tag has a value attribute preloaded that points to a preselected repository's id
                // this function resolves that id attribute to an object that select2 can render
                // using its formatResult renderer - that way the repository name is shown preselected
                var id = $(element).val();
                if (id !== "") {
                    $.ajax("http://localhost:8090/api/User/" + id, {
                        dataType: "json"
                    }).done(function (data) { callback(data); });
                }
            },

Another question that came up is whether it is possible to have a custom formatResult with BForms?

            formatResult: function (user) {
                var markup = '<div class="row">' +
                   '<div class="col-lg-2"><i class="fa fa-user"/></div>' +
                   '<div class="col-lg-10">' +
                      '<div class="row-fluid">' +
                         '<div class="col-lg-6">' + user.UserId + '</div>' +
                         '<div class="col-lg-3"><i class="fa fa-code-fork"></i> ' + user.FirstName + '</div>' +
                         '<div class="col-lg-3"><i class="fa fa-star"></i> ' + user.LastName + '</div>' +
                      '</div>';

                if (user.description) {
                    markup += '<div>' + user.description + '</div>';
                }

                markup += '</div></div>';

                return markup;
            }, // omitted for brevity, see the source of this page

Btw, I'm really looking forward to test the ListBoxRemote ;-) Can you say when that this feature would be available?

Thank you for your reply

Regards meister-d

meister-d commented 9 years ago

Hi Cristi, one more Question...

Is it possible to get the actual Values of the Editable Model and to pass them to the Remote Call? Like this it would be possible to interact with the other controls on the form and to make the search filter more granular and dependent of the values of the EditableModel.

Something like :

public BsJsonResult GetCountriesPaged(int page, string search, EditableModel model)
        {
            var pageSize = 10;
            var ddlWithSelected = Lists.AllCounties<string>();

            var q = ddlWithSelected.Items
                .Where(x => x.Text.ToLower().Contains(search.ToLower()) && x.Property == model.Property);

            var items = q.Skip((page - 1) * pageSize)
                .Take(pageSize)
                .ToList();

            return new BsJsonResult(new
            {
                PageSize = pageSize,
                Count = q.Count(),
                Items = items
            });
        }

Regards meister-d

cristipufu commented 8 years ago

Error message in case the ajax request fails. Allow formatResult option - templating based on {{id}}, {{text}} for now