简体   繁体   English

Javascript在If语句中错误地执行MVC代码

[英]Javascript executing MVC code in If statement incorrectly

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. 它在Windows 7上的VS2010中运行良好,现在我已经将硬件升级到Windows 8和VS 2012,但事实并非如此。

I have the following JavaScript code in my MVC application: 我的MVC应用程序中有以下JavaScript代码:

<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: Model正在从具有如下属性的ViewModel中提取:

    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. 它返回“Nullable对象必须具有值”,如果它在该行中跳转以执行它应该返回。 But, my if statement is returning false. 但是,我的if语句返回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. 如果我删除该行并只是放入一个警告语句,它永远不会执行该行或显示警报,因为Birthday属性为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. 似乎JS在执行MVC代码方面发生了变化,似乎无论if语句如何,它都会评估整个代码块。 I've also tried the following, but to no avail: 我也试过以下,但无济于事:

  • Tested in Chrome for W8 在Chrome for W8中测试过
  • Tested in a try / catch block. 在try / catch块中测试。 Interestingly, it doesn't catch the exception (I guess JS won't catch .NET exceptions) 有趣的是,它没有捕获异常(我猜JS不会捕获.NET异常)
  • Tested by explicitly stating @Model.Birthday.HasValue == true 通过明确声明@ Model.Birthday.HasValue == true进行测试
  • Tested by changing it to @Model.Birthday.Value != null 通过将其更改为@ Model.Birthday.Value!= null进行测试
  • Tested in Release mode over Debug Mode 通过调试模式在释放模式下测试

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. 这应该很简单 - 测试一个值是否为null,如果不是,则从.NET属性创建一个JS Date对象,如果是,则创建一个新的JS Date对象,但由于某种原因,它想要评估并执行该行,即使HasValue为false。

Really stumped. 真的很难过。 Has anyone seen something like this? 有没有人见过这样的东西?

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 我正在Win 7上运行VS 2010.解决方案可能是以这种方式更改代码

<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. 只是呈现HTML代码。 Let's see it step by step 让我们一步一步看

I. HasValue I. HasValue

@Model.Birthday = new Date(2012,11,4) @ Model.Birthday =新日期(2012,11,4)

1) Razor is sending to Response stream string until the first @ operator 1)Razor发送到Response流字符串,直到第一个@运算符

<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 2)这里Razor将此部分评估为@ Model.Birthday.HasValue作为布尔值并将其转换为字符串,因此代码的下一部分将是

True

3) Append next direct string 3)附加下一个直接字符串

"){
    var today = new Date("

4) evaluat the @Model.Birthday.Value.Year and inject its string value 4)评估@ Model.Birthday.Value.Year并注入其字符串值

2012

5) 6) 7) ... and so on the final result sent to Response is: 5)6)7)......等发送给Response的最终结果是:

<script language="javascript" type="text/javascript">
    var today;

    if ("True"){
        var today = new Date("2012", "11" - 1, "4");
    } else{
        today = new Date();
    }
</script>

II. II。 Birthdate is NULL Birthdate为NULL

In case that the @Model.Birthday = null the first steps 1), 2) and 3) are the same: 如果@ Model.Birthday = null,则第一步1),2)和3)是相同的:

<script language="javascript" type="text/javascript">
    var today;

    if ("True"){
        var today = new Date("

4) Exception Nullable object must have a value 4) 异常Nullable对象必须具有值

Finally, there is a place where we get the Nullable exception. 最后,还有一个我们得到Nullable异常的地方。

@Model.Birthday.Value.Year @ Model.Birthday.Value.Year

is called while 被称为

@Model.Birthday == null @ Model.Birthday == null

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. 首先,在服务器端处理MVC变量。 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. 您当前的实现总是尝试在Javascript中为@Model.Birthday.Value属性呈现值,以生成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. 无论当前示例中的属性是true还是false,都会发生这种情况,因为它依赖于客户端Javascript来执行条件而不是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. 现在显然,代码在Javascript部分中重复,以便显示它适用于同一控制器操作中的Null和Non-null值。

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. 正如您在View中看到的,我们确保使用Razor语法检查Model和Javascript以设置实际的客户端变量。 Also, I wonder if your '- 1' was working properly. 另外,我想知道你的' - 1'是否正常工作。 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. 为了在这个例子中进行减法,我不得不从Javascript中将该值转换为Int,但这是一个小细节。

For reference, this is an MVC 4 project on VS2012, Windows 8 Professional tested with Chrome. 作为参考,这是VS2012上的MVC 4项目,使用Chrome测试的Windows 8 Professional。

The problem is that you're mixing up client-side code and server-side code. 问题是你混淆了客户端代码和服务器端代码。 The javascript is run client-side, but only after all the server-side code has been completed. javascript在客户端运行,但仅在所有服务器端代码完成后才运行。

So @Model.Birthday.HasValue, @Model.Birthday.Value.Year etc. will all be evaluated on the server-side, before it ever gets anywhere near the browser. 所以@ Model.Birthday.HasValue,@ Model.Birthday.Value.Year等都将在服务器端进行评估,然后才能在浏览器附近进行评估。 The javascript code (and therefore in this case, the if statement) will never get to the browser as the exception is occurring server-side, trying to evaluate Model.Birthday.Value.Year on a null object. javascript代码(因此在这种情况下,if语句)将永远不会到达浏览器,因为异常发生在服务器端,尝试在null对象上评估Model.Birthday.Value.Year。

You need to move the conditional server-side, eg 您需要移动条件服务器端,例如

@if(Model.Birthday.HasValue){
    @:today = new Date(@(Model.Birthday.Value.Year), @(Model.Birthday.Value.Month) - 1, @(Model.Birthday.Value.Day));
} else {
    @:today = new Date();
}

Multi-line Code 多行代码

@if ( Model.SomeProp == true)
{
  <text>
    <Your java script Multi-line  code>
  </text>
}

Single-line code 单行代码

@if ( Model.SomeProp == true)
{  
    @:<Your java script single-line code>  
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM