ASP.Net MVC Update ViewModel on DropDown Selection changed
Asked Answered
T

2

5

At first I'm absolutely new on web development. I'm trying to develop a Web application which consists of a single page (I started with an empty project trying to follow the mvc pattern).

To populate my View I pass a ViewModel through my HomeController to my "Home"View.

Now I want to change a few Label-Texts depending on a DropDown selection.

ViewModel:

public IEnumerable<Models.Language> AvailableLanguages;
public Models.Language SelectedLanguage
Public IEnumerable<Models.Text> Content;

Language:

public int ID;
public string LanguageText;

Text:

public Language Language;
public string Description;

HTML: @model ViewModels.MyViewModel

<div>
    @Html.DropDownFor(x => x.AvailableLanguages, 
    new SelectList(Model.AvailableLanguages, 
    "ID", 
    "LanguageText", 
    new {@onchange= ... })) 
</div>

<div>
    @{
        @:@Model.MyViewModel.Content
        .Where(o => o.Language.Equals(Model.SelectedLanguage)
        .First())
        .Description
     }
</div>

I read something about this "@onchange" attribute (Ajax, JQuery) - but to be honest It'd be great if there would be any ASP/MVC/HTML solution to achive my goal - to update my SelectedLanguage Property everytime the selected item of the dropdown gets changed.

Additionaly: Is there a tutorial for webdevelopment (asp, html, ajax, jquery, js) you can recommend?

Thanx!

EDIT

Now I tried to implement the code provided but it seems that nothing happens when changing the selected item...

Script:

<div class="LanguageSelection">
        @{
            @Html.DropDownList("SelectedLanguage", new SelectList(Model.AvailableLanguages, "ID", "Description"))
            <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript">
                var url = '@Url.Action("ChangeLanguage", "Home")';
                $('#SelectedLanguage').change() {
                    $.getJSON(url, {
                        ID: $(this).val() 
                    }, function(response){
                        $('#Title').text(response.Title);   
                    });
                };
            </script>
        }
    </div>

JsonResult:

public JsonResult ChangeLanguage(int id) {
        var data = new {
            Title = HVM.Title.Where(o => o.Language.ID.Equals(id)).First(),
        };
        return Json(new { success = true });
    }

The problem should be located somewhere in the script, the ChangeLanguage Method doesn't even get executed.

Tubulate answered 25/3, 2015 at 13:33 Comment(6)
Have you tried the javascript/jquery solution?Aunt
It a little unclear exactly what you want to do. You cannot bind a dropdownlist to a complex object (IEnumerable<Models.Language>). If your wanting to identify the selected language on post back, you need a property to bind to (say int SelectedLanguage { get; set; }) and then @Html.DropDownFor(x => x.SelectedLanguage, new SelectList(Model.AvailableLanguages ...).Gelhar
The second part of your view makes no sense. Razor code is parsed on the server before is sent to the view so MyViewModel.Content would only ever be the initial value of the SelectedLanguage. If your wanting to update something in the DOM based on the selected language, then you need to use ajax to call a controller, passing the selected language and returning the new new values you want to display. Note also your models only have fields (no get/set) so nothing will bind when you post back.Gelhar
That's why I said that I'm pretty new on the web development sector. So you mean there is no way to bind a SelectedValue to a List<object> without using advanced technologies such as ajax? If so, could you recommend some tutorials?Tubulate
@Chill-X. You can bind a dropown to a value type (int, string etc), but not to a complex object (a <select> posts back a single value and has no concept of what IEnumerable<Language> is. If you explain what it is you want to do (i.e. what is the purpose of handling the .change event), I can give you an answer.Gelhar
@Stephen Muecke - Thanks for your reply. The dropdown should hold different languages. If the selected value changes the page should notice and update every "Frontend-Control" (eg. Labels etc.) to correspond the selected language. In short: OnSelectedValueChanged => translage my page. Values the user typed in in some textboxes should not be deleted. Thanks in advanceTubulate
G
7

From the comments, you want to be able to update labels based on the selected language. In order to do this you will need to use ajax to post the selected language to a controller method that return json and update the DOM. Your view model should be

public SelectList AvailableLanguages { get; set; }
public int SelectedLanguage { get; set; }

and in the controller

public ActionResult YourMethod()
{
  var model = new yourModel();
  model.SelectedLanguage = // set this if you want a default
  var availableLanguages = // get you list of languages
  model.AvailableLanguages = new SelectList(availableLanguages, "ID", "LanguageText")
  return View(model);
}

View

@Html.DropDownListFor(m => m.SelectedLanguage, Model.AvailableLanguages)

<script>
  var url = '@Url.Action("GetLanguageLabels", "yourControllerName")';
  $('#SelectedLanguage').change() {
    $.getJSON(url, { ID: $(this).val() }, function(response) {
      // Note you will need to give your labels an id attribute
      $('#Label1').text(response.Label1);
      $('#Label2').text(response.Label2);
    })
  });
</script>

And the method to get the labels based on the selected language

public JsonResult GetLanguageLabels(int ID)
{
  // Build a object of label values based on the selected language ID
  var data = new
  {
    Label1 = someValue,
    Label2 = anotherValue,
    ....
  };
  return Json(data, JsonRequestBehavior.AllowGet);
}

Side note: Some issues with your current code. (1) Your models have fields only, not properties (no get/set) so nothing would be bound on post back. (2) You cannot bind a html control to a complex object (only an value type, or in the case of <select multiple>, an array of value types).

Gelhar answered 27/3, 2015 at 7:29 Comment(7)
Thanks, I'll implement this as soon as possible. Could you explain the code between the <script>-Tags? At the moment I'm writing my code with the Razor-Syntax - Do I have to change something in your code? You see, I'm pretty new on that web development stuff...Tubulate
OK, You will need to include the jquery.{version}.js file (either using bundling or from the Scripts folder). and you will need to update a few thing to match your requirements (e.g. yourControllerName and the id's of your labels because you did not give enough information). If you have any problems post the code you tried. And you should not mark an answer as accepted until you try it :)Gelhar
I added some more code - maybe you can help one more time? Thanks in advance!Tubulate
Your going to need to ask a new question if your having prolems with your new code. There are numerous problems - place the script inside a <script> tag at the bottom of the page. The jquery reference needs to be a separate script tag. Your method is returning return Json(new { success = true }); but it needs to be return Json(data, JsonRequestBehavior.AllowGet). Place breakpoints on the script and the controller method debug you code to understand whats actually happeningGelhar
Thanks anyway, finally you did it :) Now it works (nearly) as expected. Am I allowed to ask a last question? I want to use my HomeViewModel inside my ChangeLanguage Method - but the reference in there is null although I'm creating an instance in my Index Method (this.ViewModel = new HomeViewModel();)Tubulate
Without seeing all the relevant code, there is no way to give you an answer. You will need to ask a new question explaining the issue and showing the relevant code.Gelhar
nicely explainedFranciscafranciscan
C
1

You would make sure the elements are in a form and just and the name of the function after the onchange...

@onchange="submitdata();"

Then you would add the script.

function submitdata()
{
  $('form').submit();
}

For a more "MVC" approach you would start with a strongly typed view using a model.

@model My.Path.To.Model

You would also wrap the form data on your razor page with...

using (@Html.BeginForm("myMethod", "Home", FormMethod.Post)){
     //form and inputs here, ect
     <form method="POST" action="" >
         //properties bound to inputs to change your model, or html helpers like display for...
         <input type="Submit" name="Submit" value="Submit"/>
     </form>
}

You would then pass the model as a parameter in the Controller action, this is called on the submit of the form:

[HttpPost]
 public FileStreamResult myMethod(Model model)
 {
     string str = model.imapropertyonthemodel;

 }

If you are new to MVC I would recommend starting with the basics from W3 schools, or if you have pluralsight, there are some great tutorials there.

Chrisom answered 25/3, 2015 at 13:57 Comment(2)
If I understand your snippet the form (btw. when do I have to use a form?) gets submitted after a button on the form is clicked. What I want to do is to update my complete View after the selection of my Dropdown is changed (if possible without clearing input fields on my page).Tubulate
Sorry I wasn't more clear. The first few lines answers the question. You would have the javascript function called from the @onchange. So when the dropdown changed the form would be "submitted" which would then give you access to whatever values you wanted from there. You wouldn't have to use a button at all. In addition to having access to all the values, the event is captured in javascript so you can do whatever you want to the view.Chrisom

© 2022 - 2024 — McMap. All rights reserved.