This is a migrated thread and some comments may be shown as answers.

DropDownListFor with Nullable Int best practice?

5 Answers 171 Views
ComboBox
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Jeff
Top achievements
Rank 1
Jeff asked on 28 Jul 2011, 01:02 PM

I've got a very basic question, and I'm hoping someone out there already has a nice solution.   In my model, I have a property defined as:

public int? LocationId { get; set; }

What I'd like to do, is have a dropdown list with items similar to the following...

Text: "--Please Select--", Value: null
Text: "United States", Value:"1",
Text: "Other", Value:"2"

UPDATE:  Please see my second post below with the example and updated (correct) error message.  Thanks!

5 Answers, 1 is accepted

Sort by
0
Jatin
Top achievements
Rank 1
answered on 31 Jul 2011, 03:50 PM
Hi,
I have used Telerik DropDownList with int? recently and it works well. The MVC passes the null value (equivalent) to the nullable int, if the option with null value is choosen. If your LocationId is of nullable int, there should'nt be any validation error in first place. When is the validation error thrown in your case ?

regards,
Nirvan.
0
Jeff
Top achievements
Rank 1
answered on 01 Aug 2011, 03:17 PM
Hi Nirvan - Thanks for the help.   I did a little more research and put together a sample that shows the problem.  The original error message in my post was incorrect.  You asked when the validation error occurs.  Specifically, what seems to happen is that the browser or drop down doesn't recognize the null value, and sends back the text of "-- Please Select --".  The server side validation fires and returns the error "The value '-- Please Select --' is not valid for LocationId. "  

Here's the code and flow:

Model:
public class TestEntity
{
    [Key]
    public int TestEntityId { get; set; }
    public int? LocationId { get; set; }
}

ViewModel:
public class TestViewModel
{
    public IEnumerable<SelectListItem> LocationList { get; set; }
    public TestEntity MyEntity { get; set; }
    public string Result { get; set; }
}

Controller:
public class HomeController : Controller
{
    public ActionResult Index()
    {
        TestViewModel model = new TestViewModel { MyEntity = new TestEntity() };
        BuildSelectList( model );
        return View( model );
    }
    [HttpPost]
    public ActionResult Index( TestViewModel model )
    {
        model.Result = "Model state valid = " + TryValidateModel( model );
        BuildSelectList( model );
        return View( model );
    }
    private void BuildSelectList( TestViewModel model )
    {
        List<SelectListItem> locationList = new List<SelectListItem>();
        locationList.Add( new SelectListItem { Text = "-- Please Select --", Value = null } );
        locationList.Add( new SelectListItem { Text = "US", Value = "1" } );
        locationList.Add( new SelectListItem { Text = "Other", Value = "2" } );
        model.LocationList = locationList;
    }
}

View:
@model TelerikMvcApplication2.ViewModels.TestViewModel
@{
    ViewBag.Title = "Home Page";
}
  
@using ( Html.BeginForm() )
{
<p>
    Location: @(Html.Telerik().DropDownListFor( model => model.MyEntity.LocationId ).BindTo( Model.LocationList ))
              @Html.ValidationMessageFor( model => model.MyEntity.LocationId )
</p>
<br />
<input type="submit" value="Save" class="btn-save" />
<p>
@Model.Result
</p>
}

Main html output:
<p>
    Location: <div class="t-widget t-dropdown t-header"><div class="t-dropdown-wrap t-state-default"><span class="t-input">-- Please Select --</span><span class="t-select"><span class="t-icon t-arrow-down">select</span></span></div><input data-val="true" data-val-number="The field LocationId must be a number." id="MyEntity_LocationId" name="MyEntity.LocationId" style="display:none" type="text" value="-- Please Select --" /></div>
              <span class="field-validation-valid" data-valmsg-for="MyEntity.LocationId" data-valmsg-replace="true"></span>
</p>

jQuery for choices (showing "Please Select" mapping to null):
jQuery('#MyEntity_LocationId').tDropDownList({data:[{"Text":"-- Please Select --","Value":null},{"Text":"US","Value":"1"},{"Text":"Other","Value":"2"}]});

When selecting "Please Select" and submitting, Fiddler shows that the browser (ie 8) is sending the string literal to the server:
MyEntity.LocationId=--+Please+Select+--

Which results in this validation error being returned:
The value '-- Please Select --' is not valid for LocationId.

I'm assuming somewhere that I'm doing something wrong, but I just don't know what it is.  :-)   Hopefully seeing the code, you'll spot what I'm missing.   I can also email the sample solution if you're interested in reproducing it.

Thanks again,

Jeff
0
Jatin
Top achievements
Rank 1
answered on 01 Aug 2011, 06:45 PM
Jeff,
     I had used a different approach as indicated by code below. I tried to test your code and it is indeed throwing validation error. Here is what I have used. 

Entity
public class State {
 
    public int? Id { get; set; }
 
    [Required(ErrorMessage = "State is Required")]
    public string Name { get; set; }
}


View
@(Html.Telerik().DropDownListFor(m => m.SelectedStateId)
               .BindTo(new SelectList(Model.States, "Id", "Name"))
               .Effects(f => f.Toggle()))

Controller
using (var context = new LocationContext()) {
    viewModel.States.Add(new State { Name = "Select State" }); //Leave the Id Null
    viewModel.States.AddRange(context.States.ToList());
}

ViewModel
public class HomeViewModel {
    public List<State> States { get; set; }
 ....
 }

View Success
<div>@(Model.SelectedStateId == null ? -100 : Model.SelectedStateId)</div> <!-- Show -100 because MVC will print nothing for null -->


One more thing. You are receiving ViewModel as parameter to your post method(Index); So by the time its first statement is executed, the ViewModel is already been validated when MVC tried to push the values to the ViewModel. So instead of calling TryValidateModel() I think you should just use ModelState.IsValid property of Model to see if the validation has failed or not.

cheers,
Nirvan.
0
Jeff
Top achievements
Rank 1
answered on 01 Aug 2011, 07:42 PM
Thanks Nirvan -

I updated my code to match what you have (I believe), but I'm still seeing validation errors.  Can you try adding in a check in your project for ModelState.IsValid (thanks for that suggestion vs. TryUpdateModel) and a validation error message?  I do get the -100 value displayed in the output, but it looks like the model update actually failed, and null is just the default value for SelectedStateId.

Controller:
public class HomeController : Controller
{
    public ActionResult Index()
    {
        TestViewModel model = new TestViewModel();
        BuildSelectList( model );
        return View( model );
    }
    [HttpPost]
    public ActionResult Index( TestViewModel model )
    {
        model.Result = "Model state valid = " + ModelState.IsValid;
        BuildSelectList( model );
        return View( model );
    }
    private void BuildSelectList( TestViewModel model )
    {
        model.States = new List<State>();
        model.States.Add( new State { Name = "-- Please Select --" } );
        model.States.Add( new State { Name = "US", Id = 1 } );
        model.States.Add( new State { Name = "Other", Id = 2 } );          
    }
}

ViewModel:
public class TestViewModel
{
    public string Result { get; set; }
    public int? SelectedStateId { get; set; }
    public List<State> States { get; set; }
}

View:
@using ( Html.BeginForm() )
{
    <p>    
    State: @(Html.Telerik().DropDownListFor(m => m.SelectedStateId)
               .BindTo(new SelectList(Model.States, "Id", "Name"))
               .Effects(f => f.Toggle()))
           @Html.ValidationMessageFor( m => m.SelectedStateId )
    </p>
<br />
<input type="submit" value="Save" class="btn-save" />
  
<div>@Model.Result</div>
<br />
<div>@(Model.SelectedStateId == null ? -100 : Model.SelectedStateId)</div> <!-- Show -100 because MVC will print nothing fornull-->
}

Thanks again,

Jeff
0
Jatin
Top achievements
Rank 1
answered on 02 Aug 2011, 03:08 AM
Jeff,
     I am afraid I didn't test the code properly in hurry. I don't think it would be possible to use null in this case. I apologise for misguiding you. The LocationId seems to be a positive value, so you could try using a negative value for the first option. I am relatively new to MVC and Microsoft Technologies so I won't comment on the best practice, but if I were in a similar situation, I would certainly try using the negative value.

regards,
Nirvan.
Tags
ComboBox
Asked by
Jeff
Top achievements
Rank 1
Answers by
Jatin
Top achievements
Rank 1
Jeff
Top achievements
Rank 1
Share this question
or