Reputation: 3803
I have already spent hours with this and it's getting frustrating:
One of my ViewModel properties is a list of Allocations. For each allocation, I show a jQueryUI slider. On sliding, a DisplayFor element is updated with a new value (containing the slider's new value).
Here is the code:
js:
var slider = someDiv.find(".sliderInitial");
slider.each(function () {
$(this).slider(
{
min: 0,
max: 10,
value: $(this).parent().find(".pointsForSliderInitial").text(),
orientation: "vertical",
slide: function (event, ui)
{
var thisDiv = $(this).parent().find('.pointsForSliderInitial');
thisDiv.text(ui.value);
thisDiv.find('#pointsForSliderInitial').val(ui.value); //this line does nothing
calculatePointsSumInitial();
}
}
);
partialview (uses a ViewModel):
@for (int i = 0; i < Model.Allocations.Count(); i++)
{
<td>
<div class="hidCategoryDescriptionInitial">
@Html.(alloc => alloc.Allocations[i].CategoryName)
- @Html.DisplayFor(alloc => alloc.Allocations[i].CategoryDescription)
</div>
<div class="pointsForSliderInitial round label">
@Html.HiddenFor(alloc => alloc.Allocations[i].AllocationID, new { id = "pointsForSliderInitial" + i }) //this hidden isn't working as expected
@Html.DisplayFor(alloc => alloc.Allocations[i].Points)
</div>
<div class="sliderInitial" />
</td>
}
This is a partial view, which is contained in a Html.BeginForm(). The form is submitted through a input type submit.
This works. But now I need to also submit the newly slided values to the database. Here is the difficulty - how do I submit the value contained by Html.DisplayFor() from my pointsForsliderInitial to the database?
I need to have a submit where my Allocation property is filled with values taken from the HiddenFor()'s, which are supposed to contain the values that I updated through using the sliders.
Every time I do the submit, the model Allocations property comes as null.
What am I doing wrong here? Let me know if the info is incomplete.
edit:
Viewmodel definition for Allocations property is a list of type AllocationsViewModel (thats a viewmodel which puts together data from multiple tables in the DB:
public List<AllocationsViewModel> Allocations { get; set; }
Output html for div "pointsForSliderInitial":
<div class="pointsForSliderInitial round label">
<input data-val="true" data-val-number="The field AllocationID must be a number."
data-val-required="The AllocationID field is required."
id="pointsForSliderInitial0"
name="Allocations[0].AllocationID"
type="hidden" value="75" />
0
</div>
edit 2
I made some progress following the helpful comments and answer. First, I updated the slider creation and slide event :
$(this).slider(
{
animate:true,
min: 0,
max: 10,
value: $(this).parent().find("input.valueHolder").val(),
orientation: "vertical",
slide: function (event, ui)
{
var thisDiv = $(this).parent().find('.pointsForSliderInitial');
var newValue = ui.value;
thisDiv.text(newValue);
thisDiv.find('.valueHolder').val(newValue);
}
second, I updated the AllocationsViewModel by adding the attribute [HiddenInput] to AllocationID and Points properties:
public class AllocationsViewModel
{
[HiddenInput]
public int AllocationID { get; set; }
[HiddenInput]
public int Points { get; set; }
public DateTime LastUpdated { get; set; }
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
}
Finally, I updated the view:
<div class="pointsForSliderInitial round label">
@Html.HiddenFor(alloc => alloc.Allocations[i].AllocationID)
@Html.HiddenFor(alloc => alloc.Allocations[i].Points,new {@class="valueHolder"})
</div>
After doing all this, when submitting the form with a button, the controller correctly passes the objects to the action (populating the Allocations list as it should). However, that happens only if I dont use the sliders. If I use the sliders (which update the hidden inputs), the action again, receives the Allocations as null. So it works as long as I dont interfere with the sliders.
Somehow, this jQuery line breaks things:
thisDiv.find('.valueHolder').val(newValue);
I guess I will have to dig deeper, because in Firebug, when I debug, after this line executes, when I check its val() , it gives me "undefined".
edit 3:
I found the problem with chrome debugging! This is really interesting: I switched the order of the slider events on sliding:
slide: function (event, ui)
{
var thisDiv = $(this).parent().find('.pointsForSliderInitial');
var newValue = ui.value;
thisDiv.find('.valueHolder').val(newValue);
thisDiv.text(newValue);
}
The value was being set properly, when calling val(newValue). But then the next line, setting .text(newValue) was destroying the hidden and confusing my model making it return null to the action. I just removed thisDiv.text(newValue); -> all works ok now, my model receives the correct points updated from the sliders.
Upvotes: 1
Views: 11156
Reputation: 4624
@NunoCarmo is right, also .val(ui.value)
wont work for divs its intended for input elements, use .text() instead...
But anyway, you should store that slider value in an input not a div, because div content is not posted on form submit.
Im not sure about using
@Html.DisplayFor(alloc => alloc.Allocations[i].Points)
Because the output is a plain 0
.
You must use an input, like with AllocationID use a hidden, something like
@Html.HiddenFor(alloc => alloc.Allocations[i].Points,new {@class="valueHolder"})
Then in your JS you can do:
thisDiv.find('input.valueHolder').val(ui.value);
You also need to change at slider setup:
value: $(this).parent().find("input.valueHolder").val(),
Upvotes: 4