locked
Call action from select tag "onchange" event RRS feed

  • Question

  • User1255309776 posted

    Hello,

    On my web app, while creating post, I need user to see relevant features after selecting subcategories/nestedcategories from dropdown menu. Main two ways often used for this - 1) getting Json result from action then call with ajax 2) adding @Url.Action for onchange to call relevant action.

    In my case, I want to realize the second one - but it doesn't work. Though I don't get any error, on selecting any nestedcategory, action is not stared as I don't see new coming table which must bring relevant features names to add for post.  Here is the details:

    The higlighted ones are the main codes that need to be adjusted in order to make getFeatures action work after selecting any Nestedcategory from selectlist items.

    ViewModel

     public class MenuViewModel
        {
            public int Id { get; set; }
            public Category Category { get; set; }
            public IEnumerable<Category> Categories { get; set; }
            public Region Region { get; set; }
            public IEnumerable<Region> Regions { get; set; }
            public Subcategory Subcategory { get; set; }
            public IEnumerable<Subcategory> Subcategories { get; set; }
            public NestedCategory NestedCategory { get; set; }
            public IEnumerable<NestedCategory> NestedCategories { get; set; }
            public List<SelectListItem> CategoryList { get; set; }
            public List<SelectListItem> SubcategoryList { get; set; }
            public Feature Feature { get; set; }
            public IEnumerable<Feature> Features { get; set; }
            public Option Option { get; set; }
            public IEnumerable<Option> Options { get; set; }
            public List<SelectListItem> FeatureList { get; set; }
            public Post Post { get; set; }
            public IEnumerable<Post> Posts { get; set; }
            public IEnumerable<FeatureSubcategory> FeatureSubcategories { get; set; }
            public FeatureSubcategory FeatureSubcategory { get; set; }
        }

    View

    @model Samirad.Models.ViewModels.MenuViewModel
    
    <section class="container-fluid">
        <section class="buttonpanel">
            <h5 style="font-weight:bold">New Post</h5>
        </section>
        <section class="posts">
            <div class="post-container">
                <div class="row">
                    <div class="col-lg-4 col-md-4 col-sm-6 col-12">
                        <form method="post" asp-action="CreatePost" asp-controller="User" enctype="multipart/form-data">
                            <div asp-validation-summary="ModelOnly"></div>
                            <label asp-for="Post.Title" style="width: 45px">Title</label>
                            <input asp-for="Post.Title" class="postinput" type="text" maxlength="55" id="ptitle"><br>
                            <span asp-validation-for="Post.Title"></span>
                            <label asp-for="Post.Description" style="width: 45px">Description</label><br>
                            <textarea asp-for="Post.Description" class="texbox" type="text" maxlength="145" id="pdesc"></textarea><br>
                            <span asp-validation-for="Post.Description"></span>
                            <br>
                            <label asp-for="Post.CreatedDate" style="width:80px">Start Date</label>
                            <input asp-for="Post.CreatedDate" class="postinput" type="date" name="startDate"><br>
                            <span asp-validation-for="Post.CreatedDate"></span>
                            <label asp-for="Post.ExpirationDate" style="width: 80px">End Date</label>
                            <input asp-for="Post.ExpirationDate" class="postinput" type="date" name="endDate"><br>
    
                            <label asp-for="Category.Name">Category</label>
                            <select id="CatId" asp-for="Category.Id" asp-items="@Model.CategoryList">
                                <option value="">Select Category</option>
                            </select>
                            <br />
                            <label asp-for="Post.Subcategory.Name">Subcategory</label>
                            <select id="SubId" asp-for="Post.SubcategoryId" asp-items="@(new SelectList(String.Empty, "Id", "Name"))">
                                <option value="">Select Subcategory</option>
                            </select>
                            <br>
                            <label asp-for="Post.Nestedcategory.Name">Subcategory</label>
                            <select id="NestedId" asp-for="Post.NestedCategoryId" asp-items="@(new SelectList(String.Empty, "Id", "Name"))" onchange="@Url.Action("GetFeatures","User", new { Id = Model.NestedCategory.Id })" >
                                <option value="">Select Nested</option>
                            </select>
                            <br />
                            <table id="ftable">
                                <tr>
                                    <th>Xususiyyet</th>
                                </tr>
                                @if (ViewBag.Nestedcategories != null && ViewBag.Nestedcategories.Count() > 0)
                                {
                                    foreach (SelectListItem element in ViewBag.Nestedcategories)
                                    {
                                        if (element.Selected)
                                        {
                                            foreach (Feature item in Model.Features)
                                            {
                                                <tr>
                                                    <td>@item.Name</td>
                                                </tr>
                                            }
                                        }
                                    }
                                }
    
                            </table>
                            <button class="push" type="submit">Create</button>
                        </form>
    
                    </div>
                    <div class="col-lg-4 col-md-4 col-sm-6 col-12">
    
                    </div>
                    <div class="col-lg-4 col-md-4 col-sm-6 col-12">
    
                    </div>
    
                </div>
            </div>
        </section>
    </section>
    
    
    @section Script{
    
        <script>
    //for getting subcategory list after relevant category select
            $(document).ready(function () {
                $("#CatId").on("change", function () {
                    $list = $("#SubId");
                    $.ajax({
                        url: "/User/getSubItems",
                        type: "GET",
                        data: { id: $("#CatId").val() }, 
                        traditional: true,
                        success: function (result) {
                            console.log(result);
                            $("#SubId").empty();
                            $("#SubId").append($('<option/>', { value: -1, text: 'Select sub' }));
                            $("#NestedId").prop('disabled', true);
                            $.each(result, function (i, item) {
                                $("#SubId").append('<option value="' + item.value + '"> ' + item.text + ' </option>');
                            });
                        },
                        error: function () {
                            alert("Something went wrong");
                        }
                    });
                });
            });
    
    //for getting nestedcategory list after relevant subcategory select
            $(document).ready(function () {
                $("#SubId").on("change", function getNested() {
                    $sublist = $("#NestedId");
                    $.ajax({
                        url: "/User/getNestedItems",
                        type: "GET",
                        data: { id: $("#SubId").val() }, 
                        traditional: true,
                        success: function (newresult) {
                            console.log(newresult);
                            $("#NestedId").prop('disabled', false);
                            $("#NestedId").empty();
                            $.each(newresult, function (i, item) {
                                $("#NestedId").append('<option value="' + item.value + '"> ' + item.text + ' </option>');
                            });
                        },
                        error: function () {
                            alert("Something went wrong");
                        }
                    });
                });
            });
    
        </script>
    
    }
    

    Controller

        public class UserController : Controller
        {
                private readonly UserManager<AdUser> _userManager;
                private readonly SignInManager<AdUser> _signInManager;
                private readonly SamirDbContext _samirDbContext;
                private static int _catId;
                private static int _subId;
    
                public UserController(UserManager<AdUser> userManager, SignInManager<AdUser> signInManager, SamirDbContext samirDbContext)
                {
                    _userManager = userManager;
                    _signInManager = signInManager;
                    _samirDbContext = samirDbContext;
                }
            
            [HttpGet]
            public IActionResult UserAccount()
            {
                return View();
            }
    
            [HttpGet]
            public async Task<IActionResult> CreatePost()
            {
                MenuViewModel menuModel = new MenuViewModel();
                menuModel.Categories = await _samirDbContext.Categories.ToListAsync();
                menuModel.NestedCategory = await _samirDbContext.NestedCategories.FirstOrDefaultAsync();
                menuModel.CategoryList = await _samirDbContext.Categories.Select(a => new SelectListItem()
                {
                    Value = a.Id.ToString(),
                    Text = a.Name
                }).ToListAsync();
                return View(menuModel);
            }
    
            [HttpGet]
            public IActionResult getSubItems(int Id)
            {
                _catId = Id;
                List<Subcategory> list = new List<Subcategory>();
                list = _samirDbContext.Subcategories.Where(a => a.CategoryId == Id).ToList();
                return Json(new SelectList(list, "Id", "Name"));
            }
    
            [HttpGet]
            public async Task<IActionResult> getNestedItems(int Id)
            {
                _subId = Id;
                List<NestedCategory> sublist = new List<NestedCategory>();
                sublist = _samirDbContext.NestedCategories.Where(b => b.SubcategoryId == Id && b.Subcategory.CategoryId == _catId).ToList();
                ViewBag.Nestedcategories = await _samirDbContext.NestedCategories.Where(c => c.SubcategoryId == Id).Select(x => new SelectListItem()
                {
                    Value = x.Id.ToString(),
                    Text = x.Name
                }).ToListAsync();
    
                return Json(new SelectList(sublist, "Id", "Name"));
            }
    
            [HttpGet]
            public async Task<IActionResult> GetFeatures(int Id)
            {
                MenuViewModel menuModel = new MenuViewModel();
                menuModel.NestedCategory = await _samirDbContext.NestedCategories.Where(n => n.Id == Id).SingleOrDefaultAsync();
               
                // List<Feature> flist = new List<Feature>();
                if (menuModel.NestedCategory.FeaturesNesteds.Any())
                { 
                     menuModel.Features = _samirDbContext.FeaturesNesteds.Where(a => a.NestedCategoryId == Id).Include(b => b.Feature).Select(c => new Feature()
                    {
                        Id = c.FeatureId,
                        Name = c.Feature.Name
                    }).ToList();
    
                }
                else
                {  
                    menuModel.Features = _samirDbContext.FeaturesSubcategories.Where(d => d.SubcategoryId == _subId).Include(e => e.Feature).Select(f => new Feature()
                    {
                        Id = f.FeatureId,
                        Name = f.Feature.Name
                    }).ToList();
                }
                return View("CreatePost", menuModel);
            }
        }
    }
    

    Please, assist in solving this issue. Please, do not offer using Html.Dropdown helper tag as long as you cannot find solution according to my View code (using select tag with SelectListItem class).

    Thanks in advance

    Thursday, September 10, 2020 8:04 PM

Answers

  • User-474980206 posted

    if you want a partial update of a page you use ajax. any browser navigation will replace the page with the new html. a common approach is to use ajax to call a partial view an update the dom via jquery  .html()

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, September 11, 2020 7:36 PM
  • User711641945 posted

    Hi FaridGN,

    For partial update,did you consider using jquery-ajax-unobtrusive.js?

    Here is a sample about how to use it:

    View:

    <a href="" data-ajax="true" data-ajax-url="/Home/update" data-ajax-update="#panel">Click here</a>
    <div id="panel"></div>
    @section Scripts
    {
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.min.js" integrity="sha512-DedNBWPF0hLGUPNbCYfj8qjlEnNE92Fqn7xd3Sscfu7ipy7Zu33unHdugqRD3c4Vj7/yLv+slqZhMls/4Oc7Zg==" crossorigin="anonymous"></script>
    }

    Controller:

    public IActionResult Update()
    {
        var model = new Model()
        {
            Date = DateTime.Now
        };
        return PartialView("PartialViewName", model);
    }

    My Partial view:

    @model Mvc3_0.Controllers.HomeController.Model
    <h2>Partial update @Model.Date</h2>

    Result:

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, September 14, 2020 9:39 AM
  • User585649674 posted

    Add a div with id "divData" to your html.

    <div id="divData"></div>

    Add one more javascript function in you section as below. The below function should make the url call, get the html and populate the div "divData" with resulting html.

            $(document).ready(function () {
                $("#NestedId").on("change", function () {            
                    $.ajax({
                        url: "/User/GetFeatures",
                        type: "GET",
                        data: { id: $("#NestedId").val() }, 
                        traditional: true,
                        success: function (newresult) {
                            console.log(newresult);
                           $('#divData').html(newresult)
                        },
                        error: function () {
                            alert("Something went wrong");
                        }
                    });
                });
            });

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, September 16, 2020 6:59 AM

All replies

  • User-474980206 posted

    this line of code will not work:

                           <select id="NestedId" asp-for="Post.NestedCategoryId" asp-items="@(new SelectList(String.Empty, "Id", "Name"))" onchange="@Url.Action("GetFeatures","User", new { Id = Model.NestedCategory.Id })" >
     

    onchange calls javascript. in your case its not valid JavaScript but a url. only anchors support navigating to a url via an href. it also make little sense to navigate on a select, as no matter what is selected, the navigation is the same. you may want a form post, so the selected value is included, then it just:

      onchange="this.form.submit()"

    Thursday, September 10, 2020 8:25 PM
  • User1255309776 posted

    Yes, but my action here is get, I need to get the table on selecting any item from that dropdown. Do you know right syntax on how onchange works with @url.Action?

    Because if I write  onchange="this.form.submit()", this means I'll need to put it into form again and write method="get", would it work in such case?

    Thursday, September 10, 2020 9:00 PM
  • User711641945 posted

    Hi FaridGN,

    For how to use onchange function to call relevant get action,you could refer to:

    <select id="NestedId" asp-for="Post.NestedCategoryId" asp-items="@(new SelectList(String.Empty, "Id", "Name"))" 
    onchange="location.href=' @Url.Action("GetFeatures","User", new { Id = Model.NestedCategory.Id })'"> <option value="">Select Nested</option> </select>

    Best Regards,

    Rena

    Friday, September 11, 2020 5:11 AM
  • User-474980206 posted

    If there is only one value in the select, what isn’t it an anchor? If there is more than 1 value it will not be included in the get.

    Friday, September 11, 2020 2:55 PM
  • User1255309776 posted

    This way starts the action, but refreshes the page on which selected categories/subcategories/nestedcategories come back to default option("select category", for ex.).

    Do you know better way say, getting Json result from getFeatures() action then call with ajax? I'm not very good at Json/ajax, so I avoid it, but seems that way will not refresh page as this method worked for cascading dropdown choices.

    Thanks in advance

    Friday, September 11, 2020 5:29 PM
  • User-474980206 posted

    if you want a partial update of a page you use ajax. any browser navigation will replace the page with the new html. a common approach is to use ajax to call a partial view an update the dom via jquery  .html()

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, September 11, 2020 7:36 PM
  • User1255309776 posted

    Dear Bruce,

    How would you implement Ajax to call a partial view on select of any nestedcategory/subcategory?

    Friday, September 11, 2020 8:06 PM
  • User711641945 posted

    Hi FaridGN,

    For partial update,did you consider using jquery-ajax-unobtrusive.js?

    Here is a sample about how to use it:

    View:

    <a href="" data-ajax="true" data-ajax-url="/Home/update" data-ajax-update="#panel">Click here</a>
    <div id="panel"></div>
    @section Scripts
    {
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.min.js" integrity="sha512-DedNBWPF0hLGUPNbCYfj8qjlEnNE92Fqn7xd3Sscfu7ipy7Zu33unHdugqRD3c4Vj7/yLv+slqZhMls/4Oc7Zg==" crossorigin="anonymous"></script>
    }

    Controller:

    public IActionResult Update()
    {
        var model = new Model()
        {
            Date = DateTime.Now
        };
        return PartialView("PartialViewName", model);
    }

    My Partial view:

    @model Mvc3_0.Controllers.HomeController.Model
    <h2>Partial update @Model.Date</h2>

    Result:

    Best Regards,

    Rena

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, September 14, 2020 9:39 AM
  • User585649674 posted

    Add a div with id "divData" to your html.

    <div id="divData"></div>

    Add one more javascript function in you section as below. The below function should make the url call, get the html and populate the div "divData" with resulting html.

            $(document).ready(function () {
                $("#NestedId").on("change", function () {            
                    $.ajax({
                        url: "/User/GetFeatures",
                        type: "GET",
                        data: { id: $("#NestedId").val() }, 
                        traditional: true,
                        success: function (newresult) {
                            console.log(newresult);
                           $('#divData').html(newresult)
                        },
                        error: function () {
                            alert("Something went wrong");
                        }
                    });
                });
            });

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, September 16, 2020 6:59 AM
  • User1255309776 posted

    Thanks Rena, it works, but I could write easier way using partial view and ajax.

    Wednesday, September 16, 2020 7:29 PM
  • User1255309776 posted

    Thanks nideeshm,

    It's also not a bad way of staing in the same view and getting new part on change without page refresh.

    Wednesday, September 16, 2020 7:31 PM