Cascada desplegables en MVC 3 de vistas Razor

Estoy interesado en cómo implementar en cascada listas desplegables para las direcciones en una maquinilla de Afeitar de vista. Mi Sitio entidad tiene un SuburbId de la propiedad. Suburbio tiene un CityId, y la Ciudad ha ProvinceId. Me gustaría mostrar desplegables para todos los del Barrio, de la Ciudad y a la Provincia en el Sitio de la vista, que, por ejemplo, el barrio de lista desplegable mostrará inicialmente «Primero seleccione una Ciudad», y la Ciudad desplegable «seleccione una provincia». En la selección de una provincia, las ciudades de la provincia se rellenan etc.

¿Cómo puedo lograr esto? ¿Por dónde empiezo?

InformationsquelleAutor ProfK | 2010-12-16

5 Kommentare

  1. 87

    Vamos a ilustrar con un ejemplo. Como siempre empezar con un modelo:

    public class MyViewModel
    {
        public string SelectedProvinceId { get; set; }
        public string SelectedCityId { get; set; }
        public string SelectedSuburbId { get; set; }
        public IEnumerable<Province> Provinces { get; set; }
    }
    
    public class Province
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

    Siguiente un controlador:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var model = new MyViewModel
            {
                //TODO: Fetch those from your repository
                Provinces = Enumerable.Range(1, 10).Select(x => new Province
                {
                    Id = (x + 1).ToString(),
                    Name = "Province " + x
                })
            };
            return View(model);
        }
    
        public ActionResult Suburbs(int cityId)
        {
            //TODO: Fetch the suburbs from your repository based on the cityId
            var suburbs = Enumerable.Range(1, 5).Select(x => new
            {
                Id = x,
                Name = "suburb " + x
            });
            return Json(suburbs, JsonRequestBehavior.AllowGet);
        }
    
        public ActionResult Cities(int provinceId)
        {
            //TODO: Fetch the cities from your repository based on the provinceId
            var cities = Enumerable.Range(1, 5).Select(x => new
            {
                Id = x,
                Name = "city " + x
            });
            return Json(cities, JsonRequestBehavior.AllowGet);
        }
    }

    Y finalmente una vista:

    @model SomeNs.Models.MyViewModel
    
    @{
        ViewBag.Title = "Home Page";
    }
    
    <script type="text/javascript" src="/scripts/jquery-1.4.4.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#SelectedProvinceId').change(function () {
                var selectedProvinceId = $(this).val();
                $.getJSON('@Url.Action("Cities")', { provinceId: selectedProvinceId }, function (cities) {
                    var citiesSelect = $('#SelectedCityId');
                    citiesSelect.empty();
                    $.each(cities, function (index, city) {
                        citiesSelect.append(
                            $('<option/>')
                                .attr('value', city.Id)
                                .text(city.Name)
                        );
                    });
                });
            });
    
            $('#SelectedCityId').change(function () {
                var selectedCityId = $(this).val();
                $.getJSON('@Url.Action("Suburbs")', { cityId: selectedCityId }, function (suburbs) {
                    var suburbsSelect = $('#SelectedSuburbId');
                    suburbsSelect.empty();
                    $.each(suburbs, function (index, suburb) {
                        suburbsSelect.append(
                            $('<option/>')
                                .attr('value', suburb.Id)
                                .text(suburb.Name)
                        );
                    });
                });
            });
        });
    </script>
    
    <div>
        Province: 
        @Html.DropDownListFor(x => x.SelectedProvinceId, new SelectList(Model.Provinces, "Id", "Name"))
    </div>
    <div>
        City: 
        @Html.DropDownListFor(x => x.SelectedCityId, Enumerable.Empty<SelectListItem>())
    </div>
    <div>
        Suburb: 
        @Html.DropDownListFor(x => x.SelectedSuburbId, Enumerable.Empty<SelectListItem>())
    </div>

    Como una mejora en el código javascript puede ser acortada por escrito un plugin de jquery para evitar la duplicación de algunas partes.


    ACTUALIZACIÓN:

    Y hablando de un plugin que podría haber algo entre las líneas:

    (function ($) {
        $.fn.cascade = function (options) {
            var defaults = { };
            var opts = $.extend(defaults, options);
    
            return this.each(function () {
                $(this).change(function () {
                    var selectedValue = $(this).val();
                    var params = { };
                    params[opts.paramName] = selectedValue;
                    $.getJSON(opts.url, params, function (items) {
                        opts.childSelect.empty();
                        $.each(items, function (index, item) {
                            opts.childSelect.append(
                                $('<option/>')
                                    .attr('value', item.Id)
                                    .text(item.Name)
                            );
                        });
                    });
                });
            });
        };
    })(jQuery);

    Y, a continuación, simplemente conéctelo:

    $(function () {
        $('#SelectedProvinceId').cascade({
            url: '@Url.Action("Cities")',
            paramName: 'provinceId',
            childSelect: $('#SelectedCityId')
        });
    
        $('#SelectedCityId').cascade({
            url: '@Url.Action("Suburbs")',
            paramName: 'cityId',
            childSelect: $('#SelectedSuburbId')
        });
    });
    • Yo iba a escribir un comentario diciendo «¿por Qué ir en este esfuerzo? El uso de un plugin de jquery» – luego de leer tu última frase. 🙂 +1
    • + sólo por el alcance de su respuesta, gracias. Yo no he usado en mi código todavía. pero se ve como un ganador.
    • Acabo de escribir mi función en javascript, a continuación, desplazarse hacia abajo para ver una función :/ +1 para ti.
    • Que por fin puedo usar esto en el código, gracias de nuevo, sin embargo, me pregunto cómo habría que tratar con, por ejemplo, para un determinado barrio, y de la ciudad de IDENTIFICACIÓN, obtención de la lista inicial de los ejidos de la cityId, por lo que una vista de edición se abre con la correcta ciudad y suburbio seleccionado. Actualmente estoy almacenar la suburbId en un oculto, y llamando $('#SelectedCityId').change() una vez a la carga, a continuación, ajuste el suburbio valor seleccionado, pero eso no es una solución de producción.
    • Todavía me pregunto cómo hacer esto de una manera más eficaz así. Parece que debe haber una mejor MVC-ish manera de arreglar la unión inicial de este.
    • Dimitrov +1 para una respuesta integral. Muchas muchas gracias !!! Soy nuevo en MVC , me pregunto cómo esto se podría hacer con javascript desactivado, lo he probado volviendo PartialView() , pero supongo que m no hacerlo de una manera correcta ya que no funciona 🙁
    • Dimitrov, hey, sólo quería pasar por aquí y decirte lo mucho que yo (y todos los desarrolladores estoy seguro) agradecemos su disposición a ayudar a los de aquí ASÍ. He sido desarrollador desde hace varios años, aunque es nuevo para ENTONCES, yo creo que eres un muy impresionante individuo para tomar tiempo de su día para ayudar a resolver importante (a veces trabajo-dependiente) de los problemas.
    • esto es excelente. Una cosa más: todas las solicitudes serán almacenados en caché. Para arreglar eso, cambie esta línea en el plugin: $.getJSON(opts.url, params, function (items) { a: $.getJSON(opts.url + "?" + new Date().getTime(), params, function (items) { .||. Yo normalmente no en línea todos los que (en vez de poner la URL en una var). Si haces esto, asegúrate de que sea EN el cambio de controlador: $(this).change(function () {

  2. 5

    Gracias Darin para su conducen a la solución. Mucho me ayudaron a llegar a la point. Pero como ‘xxviktor’ mencionado, hice consiguió circular ref. error. Para deshacerse de él, que yo lo he hecho de esta manera.

        public string GetCounties(int countryID)
        {
            List<County> objCounties = new List<County>();
            var objResp = _mastRepo.GetCounties(countryID, ref objCounties);
            var objRetC = from c in objCounties
                          select new SelectListItem
                          {
                              Text = c.Name,
                              Value = c.ID.ToString()
                          };
            return new JavaScriptSerializer().Serialize(objRetC);
        }

    Y para lograr auto en cascada, he ligeramente extendida jQuery extensión de esta manera.

            $('#ddlCountry').cascade({
                url: '@Url.Action("GetCounties")',
                paramName: 'countryID',
                childSelect: $('#ddlState'),
                childCascade: true
            });

    Y el real de JS es el uso de este parámetro de la siguiente manera (en el interior de petición JSON).

                    //trigger child change
                    if (opts.childCascade) {
                        opts.childSelect.change();
                    }

    La esperanza de que esto ayude a alguien con un problema similar.

  3. 0

    A implementar en cascada listas desplegables que el apoyo MVC construido en la validación y vinculante, deberá hacer algo un poco diferente de lo que se hace en las otras respuestas aquí.

    Si su modelo tiene la validación, esto la va a apoyar. Un extracto de un modelo de validación:

    [Required]
    [DisplayFormat(ConvertEmptyStringToNull = false)]    
    public Guid cityId { get; set; }

    En el controlador que necesita para añadir un método get, por lo que su punto de vista será capaz de obtener los datos relevantes posteriores:

    [AcceptVerbs(HttpVerbs.Get)]
    public JsonResult GetData(Guid id)
    {
        var cityList = (from s in db.City where s.stateId == id select new { cityId = s.cityId, name = s.name }); 
        //simply grabbing all of the cities that are in the selected state 
    
        return Json(cityList.ToList(), JsonRequestBehavior.AllowGet);  
    }

    Ahora, a la Vista de que he mencionado anteriormente:

    En su opinión, tiene dos listas desplegables similar a este:

    <div class="editor-label">
        @Html.LabelFor(model => model.stateId, "State")
    </div>
    <div class="editor-field">
        @Html.DropDownList("stateId", String.Empty)
        @Html.ValidationMessageFor(model => model.stateId)
    </div>
    
    <div class="editor-label">
        @Html.LabelFor(model => model.cityId, "City")
    </div>
    <div class="editor-field">
        @*<select id="cityId"></select>*@
        @Html.DropDownList("cityId", String.Empty)
        @Html.ValidationMessageFor(model => model.cityId)
    </div>

    El contenido de los menús desplegables están obligados por el controlador, y se rellenan de forma automática. Nota: en mi experiencia, la eliminación de esta unión y de depender de java script para rellenar las listas desplegables de hacer perder la validación. Además, la forma en que son vinculantes aquí juega bien con la validación, por lo que no hay razón para cambiarlo.

    Ahora en nuestro plugin de jQuery:

    (function ($) {
    $.fn.cascade = function (secondaryDropDown, actionUrl, stringValueToCompare) {
        primaryDropDown = this; //This doesn't necessarily need to be global
        globalOptions = new Array(); //This doesn't necessarily need to be global
        for (var i = 0; i < secondaryDropDown.options.length; i++) {
            globalOptions.push(secondaryDropDown.options[i]);
        }
    
        $(primaryDropDown).change(function () {
            if ($(primaryDropDown).val() != "") {
                $(secondaryDropDown).prop('disabled', false); //Enable the second dropdown if we have an acceptable value
                $.ajax({
                    url: actionUrl,
                    type: 'GET',
                    cache: false,
                    data: { id: $(primaryDropDown).val() },
                    success: function (result) {
                        $(secondaryDropDown).empty() //Empty the dropdown so we can re-populate it
                        var dynamicData = new Array();
                        for (count = 0; count < result.length; count++) {
                            dynamicData.push(result[count][stringValueToCompare]);
                        }
    
                        //allow the empty option so the second dropdown will not look odd when empty
                        dynamicData.push(globalOptions[0].value);
                        for (var i = 0; i < dynamicData.length; i++) {
                            for (var j = 0; j < globalOptions.length; j++) {
                                if (dynamicData[i] == globalOptions[j].value) {
                                    $(secondaryDropDown).append(globalOptions[j]);
                                    break;
                                }
                            }
    
                        }
                    },
                    dataType: 'json',
                    error: function () { console.log("Error retrieving cascading dropdown data from " + actionUrl); }
                });
            }
            else {
                $(secondaryDropDown).prop('disabled', true);
            }
            secondaryDropDown.selectedindex = 0; //this prevents a previous selection from sticking
        });
        $(primaryDropDown).change();
    };
    } (jQuery));

    Puede copiar el anterior jQuery que he creado, en <script>...</script> etiquetas en la vista, o en un archivo de script independiente si usted lo desea (nota: he actualizado este para que sea multi-navegador, sin embargo, el escenario en el que yo estaba usando ya no es necesaria, se debe trabajar, sin embargo).

    En esas mismas etiquetas de secuencia de comandos, (no en un archivo independiente) puede llamar al plugin mediante el siguiente javascript:

    $(document).ready(function () {
        var primaryDropDown = document.getElementById('stateId');
        var secondaryDropdown = document.getElementById('cityId');
        var actionUrl = '@Url.Action("GetData")'
        $(primaryDropDown).cascade(secondaryDropdown, actionUrl);
    });

    Recuerde agregar el $(document).ready parte, la página debe estar completamente cargada antes de intentar hacer las listas desplegables de la cascada.

  4. 0

    JS:

    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    
    
    <script type="text/javascript">
        $(document).ready(function () {
            //Dropdownlist Selectedchange event
            $("#country").change(function () {
                $("#State").empty();
                $.ajax({
                    type: 'POST',
                    url: '@Url.Action("State")', //we are calling json method
    
                    dataType: 'json',
    
                    data: { id: $("#country").val() },
                    //here we are get value of selected country and passing same value
                  
    
                    success: function (states) {
                        //states contains the JSON formatted list
                        //of states passed from the controller
    
                        $.each(states, function (i, state) {
                            $("#State").append('<option value="' + state.Value + '">' +
                                 state.Text + '</option>');
                            //here we are adding option for States
    
                        });
                    },
                error: function (ex) {
                    alert('Failed to retrieve states.' + ex);
                }
            });
            return false;
        })
        });
    </script>

    HTML:

    <div>
        @Html.DropDownList("country", ViewBag.country as List<SelectListItem>, "CountryName", new { style = "width: 200px;" })
    </div>
    <div>
    
    </div>
    <div>
        @Html.DropDownList("State", ViewBag.country as List<SelectListItem>)
    
    </div>

    De controlador me estoy poniendo de los valores

     public async Task<ActionResult> Country()
        {
    
            Country co = new Country();
            List<SelectListItem> li = new List<SelectListItem>();
            li.Add(new SelectListItem { Text = "Select", Value = "0" });
            li.Add(new SelectListItem { Text = "India", Value = "1" });
            li.Add(new SelectListItem { Text = "Nepal", Value = "2" });
            li.Add(new SelectListItem { Text = "USA", Value = "3" });
            li.Add(new SelectListItem { Text = "Kenya", Value = "4" }); ;
            ViewBag.country= li;
            return View();
        }
        public JsonResult  state(string id)
        {
            List<SelectListItem> states = new List<SelectListItem>();
            states.Add(new SelectListItem { Text = "--Select State--", Value = "0" });
            switch (id)
            {
                case "1":
    
    
                    states.Add(new SelectListItem { Text = "MP", Value = "1" });
                    states.Add(new SelectListItem { Text = "UP", Value = "2" });
                    break;
                case "3":
    
                    states.Add(new SelectListItem { Text = "USA1", Value = "3" });
                    states.Add(new SelectListItem { Text = "USA2", Value = "4" });
                    break;
            }
    
            return Json(new SelectList(states, "Value", "Text", JsonRequestBehavior.AllowGet));
        }

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea