MVC update Dropdownlistfor with jquery - asp.net-mvc

I have a Dropdownlistfor connected to my model. When the page is loaded the model is empty, but I have a button on the page that updates the model. My problem is that my dropdownlist doesn't update.
Markup:
#Html.DropDownList("ddlRaces", new SelectList(ViewBag.Races, "RaceId", "Name"))
<input type="button" id="btnChangeRace" class="btnGo" value=" " />
#Html.DropDownListFor(m => m.Timers, new SelectList(Model.Timers, "TimerId", "StartTime"), "Velg timer:")
Script:
btnChangeRace.click(function () {
url = "/TimeMerger/GetTimers/?raceId=" + ddlRaces.val();
$.get(url);
});
Codebehind:
[HttpGet]
public ActionResult GetTimers(int raceId)
{
var timeMergeModel = new TimeMergerModel();
timeMergeModel.Timers = TimerModel.GetTimers(raceId);
return View(timeMergeModel);
}

$.get(url);
Here you are sending an AJAX request but you are doing nothing in the success callback so nothing will update. There is not even a success callback. So you need to define a success callback:
$.get(url, function(result) {
// result here will represent the value returned by the server
// which in your case is HTML. So here you might need to update
// the relevant portion of your page.
});
Also your DropDownListFor definition is wrong. You are using the same model variable as first and second argument (Model.Timers). The first first argument of this helper should be a scalar property to which you are binding and not a list. It should be:
#Html.DropDownListFor(
m => m.SelectedTimerValue,
new SelectList(Model.Timers, "TimerId", "StartTime"),
"Velg timer:"
)
where SelectedTimerValue would be a property on your view model that will hold the selected value. Also why you are using DropDownList instead of DropDownListFor for the first drop down? The whole idea of a view model is that it will contain all the necessary information so that the view would simply display it.

Related

MVC 4 #HTML.DropdownlistFor onchange event needs to send SelectedIndex value

I am using MVC 4 and have an #HTML.DropdownlistFor() which loads the rest of the page based on it's selection. On change of the listbox, I want to reload the page so that it load the correct data. As well there are two other parameters that are needed to load the page correctly.
In Create.cshtml view
#Html.DropDownListFor(model => model.SelectedMissionID, Model.MissionsToDisplay, new { onchange = "ReloadPage();" })
function ReloadPage() {
window.location = '#Html.Raw(Url.Action("CreateEdit", "DailyLog", new { ID = 1, ID2 = 0, dailyLogDate = Model.LogDate }))';
}
Where it says ID = 1, I want the selected index of the DropdownlistFor(SelectedMissionID), how do I get this?
I'm not sure if this is the best way to go to the controller, or if I should use a JQUERY .ajax post, is there a better way?
I seems something ideal for an ajax post.
What you have done is OK, inside the ReloadPage() function, just get the selected value in the DropDown, do the Ajax call passing the parameters, and in the success callback put your returned HTML in some container.
The idea is that you replace a part of your view with the return of your Ajax call, not all the page.
To get the selected value, using jQuery:
var selectedValue = $("select[name='SelectedMissionID']").val();
And that can be placed in your ReloadPage() function.
$.post( "your action URL", { ID: selectedValue, OtherParam: "xxxxx" })
.done(function( data ) {
alert( "Data Loaded: " + data );
//here you need to get the HTML, and put in a container
});

MVC Remote Validation With Additional bool Fields

I am trying to use Remote Validation with an additional bool checkbox field
[Remote("IsStorageConnectionValid", "TenantManagement", AdditionalFields = "CreateStorage")]
public String StorageConnectionString { get; set; }
Validation code
public JsonResult IsStorageConnectionValid(string storageConnectionString, bool createStorage){
It works perfectly in terms of it hitting the validator. However createStorage is always true irrespective of the value of the checkbox. If I use additional fields that aren't check boxes they are supplied perfectly.
Checkbox created as standard:
#Html.CheckBoxFor(m => m.CreateStorage)
Is this a bug? Or am I doing it wrong?
Fiddle Is here (Is MVC4 I think but does the same thing)
It does appear that this is a bug when used with #Html.CheckBoxFor. The problem is that CheckBoxFor renders 2 elements, a checkbox with value="true" and a hidden input with value="false" (Unchecked checkboxes do not post back so the second hidden input ensures a value is posted back for use by the DefaultModelBinder)
Looking at the relevant section of the jquery.validate.unobtrusive.js file
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
return $(options.form).find(":input[name='" + escapeAttributeValue(paramName) + "']").val();
};
});
setValidationValues(options, "remote", value);
});
the return statement returns (in your case) .find(':input[name="CreateStorage"]').val(); which returns the value of the first input with the name="CreateStorage" which will always be true (the value of the checkbox)
As a test, if you render the value using HiddenFor rather that CheckBoxFor you will receive the correct value in your IsStorageConnectionValid method (but of course this does help since you cant change the value)
Not sure of the best solution, but the unobtrusive script should be first checking if .find(..) returns more than one element, then if the first is a checkbox which is unchecked, returning the value of the second element.
Edit
I have reported this as an issue at Codeplex
Edit 2
I have been advised the the issue has now been fixed here

missunderstanding mvc default binding

I have multiselect jquery plagin (Choosen) and when I use it in 'Multiple Select' mode I expect in controller next values:
posted string = 'value1,value2...'
really have
posted string = 'value2'
only if I reffer directly to FormCollection I'll get expected values as below:
[HttpPost]
public ActionResult TagSearech(/*string tagSelect*/FormCollection c)
{
// only one value here
// string[] names = tagSelect.Split(',');
// as expected: value1,....
string expectedValue = c['tagSelect'];
return View();
}
I cant understand what might cause this behavior.
EDIT
Here is View:
#using (Html.BeginForm("TagSearech", "Tag"))
{
#Html.DropDownList("tagSelect", Model, new { #class = "chzn-select", data_placeholder = "tag names", multiple = "" })
<input type="submit"/>
}
MVC will attempt to bind the input data on the URL into the model. I haven't seen how Chosen.js posts the data back to the server, but essentially its coming in in the wrong format, so MVC binds the first element it sees to the string Model.
The FormsCollection retrieves all of the data that was posted in the URL, which is why all of your selected values can be seen there.
Did you try changing the incoming model from string to string[], and see if all of the items are bound to the array?

MVC - Data back from controller to view

My question : If we already have made view -a strongly typed, then why do we need to return model object back from controller post method to view - MVC 4 asp.net ?
For example : I have calculator view :
#using (Html.BeginForm())
{
<p>Number One : #Html.TextBoxFor(m => m.numberOne)</p>
<p>Number Two : #Html.TextBoxFor(m => m.numberTwo)</p>
<input type="submit" value ="Addition" name="calculateOperation" />
<input type="submit" value ="Subtraction" name="calculateOperation" />
<input type="submit" value ="Multiplication" name="calculateOperation" />
<input type="submit" value ="Division" name="calculateOperation" />
}
#using (Html.BeginForm())
{
<p>Output : #Html.TextBoxFor(m => m.result)</p>
}
and controller :
public ActionResult Calculate(Calculator model, string calculateOperation)
{
if (calculateOperation.Equals("Addition"))
{
int[] array = { 1, 12, 5, 26, 7, 14, 3, 7, 2 };
model.result = model.numberOne + model.numberTwo;
}
if (calculateOperation.Equals("Subtraction"))
{
model.result = model.numberOne - model.numberTwo;
}
if (calculateOperation.Equals("Multiplication"))
{
model.result = model.numberOne * model.numberTwo;
}
if (calculateOperation.Equals("Division"))
{
model.result = model.numberOne / model.numberTwo;
}
return View(model);
}
If I don't return the model object, I don't get value of model.result.
Looking for a valid reason.
HTTP is a stateless protocol. Hence, when you do work on the server, if you want it to display something on the client, you have to send it back down. An MVC strongly-typed view is really just an abstraction on top of the rendering engine.
When you "Submit" the form you are just doing an HTTP POST back to your controller action (an http request).
Calling
return View(model)
means that you are sending an HTTP response that returns a rendered html page (using your view). In your case you're simply passing in the model as a parameter.
Well, you don't have to send back a model, you could just use the FormCollection parameter, but then you would have to fetch the values and cast them to the correct type your self.
public ActionResult Calculate(FormCollection form, string calculateOperation)
{
// Need to check if form["numberOne"] is null or empty or do a int.TryParse()
int numberOne = int.Parse(form["numberOne"]);
}
With a strongly typed model you get that for free by the model binders in asp.net mvc. The code looks much cleaner and it's easier to use.
With a model you also get the power of attributes, like validation and scaffolding. It's much cleaner and easier to validate most scenarios using a model with validation attributes.
In this case you need to send a model to the view simply because the view requires it. That's how it is designed. How would the model or the view know that you have made an calculation if you don't store it somewhere? Of course you could also use ViewBag:
ViewBag["result"] = model.numberOne + model.numberTwo;
And in your view:
<p>Output :#Html.TextBox("result", (string)ViewBag["result"])</p>
I always figured that this was to cover cases when there was some kind of explanation or response type data.
For example. You submit an address to be added to the database and you have a service which checks the address for correctness. If it is correct, it gets persisted, otherwise it gets corrected, added to a special field in the original object and sent back for confirmation.
There's no actual requirement for your controllers method to return anything that consumes that or any other model. As a result you still need to be explicit with what View and the data associated with it that you want to return.
They could add some sort of overload to View that would implicitly assume it should use some ViewModel in the method parameters, but that's non-intuitive and unnecessary.

ASP.NET MVC - Html.TextBox - Value not set via ViewData dictionary

I have a search box on a page (actually in a partial view though not sure that is relevant) with an Html.TextBox control.
<%= Html.TextBox("query", ViewData["query"], new { style = "width: 90%;" })%>
The action method takes "query" as a parameter, and I edit this value to clean up the string that is passed in:
public ActionResult SearchQuery(string query) {
ViewData["query"] = StringFunctions.ProperCasing(query.Replace("_", " "));
However, when it gets to the Html.TextBox the original query value (in this case with underscores) is preserved. I can see that the edited value is in the ViewData field, so for example, if:
query == "data_entry"
then, after being passed into the action method
ViewData["query"] == "data entry"
but the value, when it reaches the view, in the Html.TextBox is still "data_entry". It seems like there is a collision between the action method parameter "query" and the search box form parameter "query". Anyone know what is going on here or if there is another way to pass the value?
This action method is separate from the action that results from posting the search box data.
Html.Textbox helper looks for ModelState first (ASP.NET MVC source, InputExtensions.cs line 183, HtmlHelper.cs line 243). The simplest solution would be removing the ModelState for "query":
public ActionResult SearchQuery(string query)
{
ViewData["query"] = StringFunctions.ProperCasing(query.Replace("_", " "));
ModelState.Remove("query");
return View();
}
Dont know if this is the problem but my first thought is is to pass the view data back in the controller.
public ActionResult SearchQuery(string query)
{
ViewData["query"] = StringFunctions.ProperCasing(query.Replace("_", " "));
return view(ViewData):
}

Resources