I am a bit stumped with the following code. It worked fine in VS2010 on Windows 7, and now that I've upgraded the hardware to Windows 8 and VS 2012, it does not.
I have the following JavaScript code in my MVC application:
<script language="javascript" type="text/javascript">
var today;
if("@Model.Birthday.HasValue"){
var today = new Date("@Model.Birthday.Value.Year", "@Model.Birthday.Value.Month" - 1, "@Model.Birthday.Value.Day");
}else{
today = new Date();
}
The Model is pulling from a ViewModel that has a property that looks like this:
public System.DateTime? Birthday
{
get { return user.Birthday; }
set { user.Birthday = value; }
}
The exception is thrown in the line:
var today = new Date("@Model.Birthday.Value.Year", "@Model.Birthday.Value.Month" - 1, "@Model.Birthday.Value.Day");
It comes back with "Nullable object must have value", which it should if it jumps in that line to execute. But, my if statement is returning false. If I remove the line and just put in an alert statement, it never executes that line or shows the alert, because the Birthday property is null. Something seems to have shifted in how JS executes MVC code, and it seems to evaluate the entirety of the code block, regardless of the if statement. I've also tried the following, but to no avail:
This should be simple - test to see if a value is null, and if it's not, create a JS Date object from the .NET property, if it is, create a new JS Date object, but for some reason, it want's to evaluate and execute that line, even though HasValue is false.
Really stumped. Has anyone seen something like this?
I can see a couple of things going on here that are impacting your ability to render the correct data.
First, the MVC variables are processed on the server side. Your current implementation is always trying to render a value for the @Model.Birthday.Value
properties in your Javascript in order to generate the HTML. This will happen regardless if the property is true or false in your current example since it is relying on the client-side Javascript to do the conditional and not Razor. Below is a complete working example of your issue.
View Model
namespace MvcApplication1.Models
{
public class TestViewModel
{
public DateTime? NullDate { get; set; }
public DateTime? DateWithValue { get; set; }
}
}
Controller
public ActionResult Index()
{
return View(new TestViewModel{DateWithValue = DateTime.Now,
NullDate = null});
}
View
@model MvcApplication1.Models.TestViewModel
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<script type="text/javascript">
var today;
var anotherDay;
@{if(Model.NullDate.HasValue)
{
@: alert('Null date had a value!');
@: today = new Date('@Model.NullDate.Value.Year', parseInt('@Model.DateWithValue.Value.Month') - 1, '@Model.NullDate.Value.Day');
}else
{
@: alert('Null date did not have a value');
@: today = new Date();
}}
@{if (Model.DateWithValue.HasValue)
{
@: alert('DateWithValue had a value!');
@: anotherDay = new Date('@Model.DateWithValue.Value.Year', parseInt('@Model.DateWithValue.Value.Month') - 1, '@Model.DateWithValue.Value.Day');
@: alert(anotherDay);
}
else
{
@: alert('DateWithValue date did not have a value');
@: anotherDay = new Date();
}}
</script>
Now obviously, the code is duplicated in the Javascript section in order to show it works for both Null and Non-null values in the same controller action.
As you can see in the View, we are ensuring that we are using the Razor syntax for the checking of the Model and Javascript for setting the actual client-side variable. Also, I wonder if your '- 1' was working properly. In order to do the subtraction in this example, I had to cast that value to an Int from the Javascript, but this is a minor detail.
For reference, this is an MVC 4 project on VS2012, Windows 8 Professional tested with Chrome.
Solution in a nutshell:
I tested your code and could say, there is no issue with your HW/SW update. I am running VS 2010 on Win 7. The solution could be Change your code for example this way
<script language="javascript" type="text/javascript">
@{ // C# server side part to get the dateParameters
var dateParameters = string.Empty;
if (Model.Birthday.HasValue)
{
dateParameters = "" + @Model.Birthday.Value.Year
+ ", " + (@Model.Birthday.Value.Month - 1)
+ ", " + @Model.Birthday.Value.Day;
}
}
// JS client side, later working with just created dateParameters
var today = new Date(@dateParameters);
alert(today);
</script>
Detailed explanation:
to find the answer let split what is the snippet above doing. It is just rendering an HTML code. Let's see it step by step
@Model.Birthday = new Date(2012,11,4)
1) Razor is sending to Response stream string until the first @ operator
<script language="javascript" type="text/javascript">
var today;
if("
2) here Razor evaluates this part @Model.Birthday.HasValue as a boolean and converts it to string so the next part of a code would be
True
3) Append next direct string
"){
var today = new Date("
4) evaluat the @Model.Birthday.Value.Year and inject its string value
2012
5) 6) 7) ... and so on the final result sent to Response is:
<script language="javascript" type="text/javascript">
var today;
if ("True"){
var today = new Date("2012", "11" - 1, "4");
} else{
today = new Date();
}
</script>
In case that the @Model.Birthday = null the first steps 1), 2) and 3) are the same:
<script language="javascript" type="text/javascript">
var today;
if ("True"){
var today = new Date("
4) Exception Nullable object must have a value
Finally, there is a place where we get the Nullable exception.
@Model.Birthday.Value.Year
is called while
@Model.Birthday == null
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With