【问题标题】:Accessing MVC's model property from Javascript从 Javascript 访问 MVC 的模型属性
【发布时间】:2013-04-28 00:02:44
【问题描述】:

我的视图模型中包含以下模型

public class FloorPlanSettingsModel
{
    public int Id { get; set; }
    public int? MainFloorPlanId { get; set; }
    public string ImageDirectory { get; set; }
    public string ThumbnailDirectory { get; set; }
    public string IconsDirectory { get; set; }
}

如何从 Javascript 访问上述属性之一?

我试过这个,但我得到“未定义”

var floorplanSettings = "@Model.FloorPlanSettings";
alert(floorplanSettings.IconsDirectory);

【问题讨论】:

  • 要明确一点,发生的事情是您将 JavaScript 变量的值设置为 C# 变量“Model.FloorPlanSettings”的值,这将是 .ToString() 的值类(一个字符串)。然后,您尝试在刚刚创建的 JavaScript 字符串变量上提醒一个名为“IconsDirectory”的 JavaScript 属性。因为 JavaScript 字符串没有“IconsDirectory”属性,所以您会得到未定义。
  • 提供了一个完整的测试用例并解释了将模型数据分配给javascript变量的所有场景,
  • 这在视图 (cshtml) 之外不起作用。即在视图引用的外部 .js 文件中。

标签: c# javascript jquery asp.net-mvc model


【解决方案1】:

您可以通过执行以下操作将整个服务器端模型转换为 Javascript 对象:

var model = @Html.Raw(Json.Encode(Model));

如果您只想要 FloorPlanSettings 对象,只需将 Encode 方法传递给该属性:

var floorplanSettings = @Html.Raw(Json.Encode(Model.FloorPlanSettings));

【讨论】:

  • 只是为了确认,不需要添加;最后?因为我确实收到了来自 VS 的提示,说明该语句没有终止。但是当我尝试添加时;代码没有运行
  • 你知道吗,我在各种项目中也遇到了同样的错误。忽略它;这是 Visual Studio 试图提供帮助,但是在这种情况下是错误的。生成的 HTML 和发送到浏览器的脚本是正确的。
  • 对我来说这有效:var myModel = @{@Html.Raw(Json.Encode(Model));}
  • 如果模型是初始值(创建页面而不是编辑页面)并且遇到“ReferenceError:模型未定义”,则无法正常工作。
  • 在 ASP.Net Core 中,Json.Serialize()
【解决方案2】:

答案的内容

1) 如何在.cshtml文件中的Javascript/Jquery代码块中访问Model数据

2) 如何在.js文件中的Javascript/Jquery代码块中访问Model数据

如何在.cshtml文件中的Javascript/Jquery代码块中访问模型数据

有两种类型的 c# 变量 (Model) 分配给 JavaScript 变量。

  1. 属性分配 - 基本数据类型,例如 intstringDateTime(例如:Model.Name
  2. 对象分配 - 自定义或内置类(例如:ModelModel.UserSettingsObj

让我们来看看这两个任务的细节。

对于其余的答案,让我们以下面的 AppUser 模型为例。

public class AppUser
{
    public string Name { get; set; }
    public bool IsAuthenticated { get; set; }
    public DateTime LoginDateTime { get; set; }
    public int Age { get; set; }
    public string UserIconHTML { get; set; }
}

我们分配给这个模型的值是

AppUser appUser = new AppUser
{
    Name = "Raj",
    IsAuthenticated = true,
    LoginDateTime = DateTime.Now,
    Age = 26,
    UserIconHTML = "<i class='fa fa-users'></i>"
};

属性分配

让我们使用不同的语法进行赋值并观察结果。

1) 不用引号将属性赋值括起来。

var Name = @Model.Name;  
var Age = @Model.Age;
var LoginTime = @Model.LoginDateTime; 
var IsAuthenticated = @Model.IsAuthenticated;   
var IconHtml = @Model.UserIconHTML;  

如您所见,有几个错误,RajTrue 被认为是 javascript 变量,由于它们不存在,因此出现 variable undefined 错误。至于 dateTime 变量,错误是 unexpected number 数字不能有特殊字符,HTML 标签被转换为其实体名称,这样浏览器就不会混淆您的值和 HTML 标记。

2) 在引号中包装属性赋值。

var Name = '@Model.Name';
var Age = '@Model.Age';
var LoginTime = '@Model.LoginDateTime';
var IsAuthenticated = '@Model.IsAuthenticated';
var IconHtml = '@Model.UserIconHTML'; 

结果是有效的,所以用引号将属性赋值给我们提供了有效的语法。但请注意,Number Age 现在是一个字符串,所以如果您不希望我们可以删除引号,它将呈现为数字类型。

3) 使用@Html.Raw,但不使用引号

 var Name = @Html.Raw(Model.Name);
 var Age = @Html.Raw(Model.Age);
 var LoginTime = @Html.Raw(Model.LoginDateTime);
 var IsAuthenticated = @Html.Raw(Model.IsAuthenticated);
 var IconHtml = @Html.Raw(Model.UserIconHTML);

结果类似于我们的测试用例 1。但是在 HTML 字符串上使用 @Html.Raw() 确实向我们展示了一些变化。 HTML 被保留而不更改其实体名称。

来自文档Html.Raw()

将 HTML 标记包装在 HtmlString 实例中,以便将其解释为 HTML 标记。

但是我们在其他行中仍然有错误。

4) 使用@Html.Raw 并将其包含在引号中

var Name ='@Html.Raw(Model.Name)';
var Age = '@Html.Raw(Model.Age)';
var LoginTime = '@Html.Raw(Model.LoginDateTime)';
var IsAuthenticated = '@Html.Raw(Model.IsAuthenticated)';
var IconHtml = '@Html.Raw(Model.UserIconHTML)';

所有类型的结果都很好。但是我们的HTML 数据现在已损坏,这将破坏脚本。问题是因为我们使用单引号 ' 来包装数据,甚至数据也有单引号。

我们可以通过 2 种方法来克服这个问题。

1) 使用双引号 " " 包裹 HTML 部分。由于内部数据只有单引号。 (确保用双引号括起来后数据中也没有"

  var IconHtml = "@Html.Raw(Model.UserIconHTML)";

2) 转义服务器端代码中的字符含义。喜欢

  UserIconHTML = "<i class=\"fa fa-users\"></i>"

属性分配结束

  • 对非数字数据类型使用引号。
  • 数字数据类型不要使用引号。
  • 使用 Html.Raw 按原样解释您的 HTML 数据。
  • 注意您的 HTML 数据,以便在服务器端转义引号含义,或者在分配给 javascript 变量期间使用与数据中不同的引号。

对象赋值

让我们使用不同的语法进行赋值并观察结果。

1) 没有将对象赋值用引号括起来。

  var userObj = @Model; 

当您将 c# 对象分配给 javascript 变量时,将分配该对象的 .ToString() 的值。因此有上述结果。

2用引号包裹对象赋值

var userObj = '@Model'; 

3) 使用不带引号的Html.Raw

   var userObj = @Html.Raw(Model); 

4) 使用 Html.Raw 和引号

   var userObj = '@Html.Raw(Model)'; 

在将对象分配给变量时,Html.Raw 对我们没有多大用处。

5) 使用不带引号的Json.Encode()

var userObj = @Json.Encode(Model); 

//result is like
var userObj = {&quot;Name&quot;:&quot;Raj&quot;,
               &quot;IsAuthenticated&quot;:true,
               &quot;LoginDateTime&quot;:&quot;\/Date(1482572875150)\/&quot;,
               &quot;Age&quot;:26,
               &quot;UserIconHTML&quot;:&quot;\u003ci class=\&quot;fa fa-users\&quot;\u003e\u003c/i\u003e&quot;
              };

我们确实看到了一些变化,我们看到我们的模型被解释为一个对象。但是我们将这些特殊字符更改为entity names。将上述语法用引号括起来也没多大用处。我们只是在引号内得到相同的结果。

来自 Json.Encode()

的文档

将数据对象转换为 JavaScript Object Notation (JSON) 格式的字符串。

您已经在属性分配方面遇到过这个entity Name 问题,如果您还记得我们使用Html.Raw 克服了它。所以让我们尝试一下。让我们结合Html.RawJson.Encode

6) 使用不带引号的Html.RawJson.Encode

var userObj = @Html.Raw(Json.Encode(Model));

结果是一个有效的 Javascript 对象

 var userObj = {"Name":"Raj",
     "IsAuthenticated":true,
     "LoginDateTime":"\/Date(1482573224421)\/",
     "Age":26,
     "UserIconHTML":"\u003ci class=\"fa fa-users\"\u003e\u003c/i\u003e"
 };

7) 在引号内使用Html.RawJson.Encode

var userObj = '@Html.Raw(Json.Encode(Model))';

如您所见,用引号括起来为我们提供了 JSON 数据

关于对象分配的思考

  • 结合使用Html.RawJson.Encode 将您的对象作为JavaScript 对象 分配给javascript 变量。
  • 使用Html.RawJson.Encode 也将其包装在quotes 中以获得JSON

注意:如果你观察到DataTime的数据格式不对。这是因为如前所述 Converts a data object to a string that is in the JavaScript Object Notation (JSON) format 和 JSON 不包含 date 类型。解决此问题的其他选项是添加另一行代码以单独使用 javascipt Date() 对象处理此类型

var userObj.LoginDateTime = new Date('@Html.Raw(Model.LoginDateTime)'); 
//without Json.Encode


如何在.js文件中的Javascript/Jquery代码块中访问模型数据

Razor 语法在 .js 文件中没有意义,因此我们不能直接在 .js 文件中使用我们的模型。但是有一个解决方法。

1) 解决方案是使用 javascript 全局变量

我们必须将值分配给全局范围的 javascipt 变量,然后在您的 .cshtml.js 文件的所有代码块中使用此变量。所以语法是

<script type="text/javascript">
  var userObj = @Html.Raw(Json.Encode(Model)); //For javascript object
  var userJsonObj = '@Html.Raw(Json.Encode(Model))'; //For json data
</script>

有了这个,我们可以在需要时使用变量userObjuserJsonObj

注意:我个人不建议使用全局变量,因为它很难维护。但是,如果您没有其他选择,那么您可以通过适当的命名约定来使用它......类似于userAppDetails_global

2) 使用 function()closure 将所有依赖于模型数据的代码包装在一个函数中。然后从.cshtml文件中执行这个函数。

external.js

 function userDataDependent(userObj){
  //.... related code
 }

.cshtml文件

 <script type="text/javascript">
  userDataDependent(@Html.Raw(Json.Encode(Model))); //execute the function     
</script>

注意:您的外部文件必须在上述脚本之前被引用。否则 userDataDependent 函数未定义。

还要注意,该函数也必须在全局范围内。因此,无论哪种解决方案,我们都必须与全球范围内的玩家打交道。

【讨论】:

  • 可以在javascript中更新Model属性并发送到控制器动作方法吗?
  • @sortednoun 是的,你可以,你可以从表单提交修改后的数据,或者如果你不想重新加载页面,那么你可以使用 AJAX
  • 我没有使用 ajax,只是尝试在 javascript 中修改模型属性。但是在提交表单时,此更改并未反映在模型中。我正在做类似的事情: var model = @Html.Raw(Json.Encode(Model)); model.EventCommand = "更新值";它给了我正确的模型和更新的值,但是在提交时,动作方法中缺少更改。 (虽然我使用隐藏的 Html 控件做了同样的事情并将其绑定到 EventCommand 并在 javascript 中更新了它的值。但想知道是否可以直接对模型做同样的事情?)
  • @sortednoun 我明白了,var model = @Html.Raw(Json.Encode(Model)); 这将创建一个 javascript 对象 model,它与您传递给视图的 C# 模型无关。事实上,在视图渲染后不会有Model。所以 UI 中的 Form 将不知道 javascript 对象数据的变化。您现在需要通过 AJAX 将整个修改后的模型传递给控制器​​,或者您需要使用 javascript 在表单中更新输入控件的值。
  • Although I did the same thing using hidden Html control and bound it to EventCommand and updated it's value in javascript. But wondering if could do same directly to model? for this statement .. 在 MVC 中没有 EventCommand,它用于在 UI 和服务器操作之间存在连接的 Webforms,在 MVC 中它是完全分开的。您与控制器交互的唯一方法是通过 AJAX 或表单提交或新页面请求(也重新加载)
【解决方案3】:

试试这个:(你错过了单引号)

var floorplanSettings = '@Html.Raw(Json.Encode(Model.FloorPlanSettings))';

【讨论】:

  • @JuanPieterse 带引号给你一个JSON 带引号给你一个javascript Object。查看我在同一线程中的答案以获取更多详细信息。 stackoverflow.com/a/41312348/2592042
  • 这不是真的,@danmbuen 解决方案在我的情况下有效,我遇到了问题并将其包裹在单引号之间就像一种魅力,谢谢 ;)
  • 只有在你的 json 字符串中没有嵌套单引号时,用单引号括起来才有效
【解决方案4】:

用括号包裹模型属性对我有用。抱怨分号的 Visual Studio 仍然会遇到同样的问题,但它确实有效。

var closedStatusId = @(Model.ClosedStatusId);

【讨论】:

    【解决方案5】:

    我知道为时已晚,但此解决方案对 .net 框架和 .net 核心都适用:

    @System.Web.HttpUtility.JavaScriptStringEncode()

    【讨论】:

    • 不完美。这适用于字符串,但不适用于其他类型。但是 +1 是另一种选择。
    【解决方案6】:

    对于 MVC 4

    @model Inventory.Models.PurchaseVModel
    @{
        ViewData["Title"] = "Add";
        Layout = "~/Views/Shared/_Layout.cshtml";
        var jsonItems = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model.Items);
    }
    
    @section scripts{
        <script>
            $(document).ready(function () {
                var allItem =  @Html.Raw(jsonItems);
            console.log(allItem);
        });
        </script>
    }
    

    .Net Core 3.1

    @model Inventory.Models.PurchaseVModel
    @{
        ViewData["Title"] = "Add";
        Layout = "~/Views/Shared/_Layout.cshtml";
        var jsonItems = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Items);
    }
    
    @section scripts{
        <script>
            $(document).ready(function () {
                var allItem =  @Html.Raw(jsonItems);
            console.log(allItem);
        });
        </script>
    }
    

    【讨论】:

      【解决方案7】:

      如果出现“ReferenceError: Model is not defined”错误,那么您可以尝试使用以下方法:

      $(document).ready(function () {
      
          @{  var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
               var json = serializer.Serialize(Model);
          }
      
          var model = @Html.Raw(json);
          if(model != null && @Html.Raw(json) != "undefined")
          {
              var id= model.Id;
              var mainFloorPlanId = model.MainFloorPlanId ;
              var imageDirectory = model.ImageDirectory ;
              var iconsDirectory = model.IconsDirectory ;
          }
      });
      

      希望这会有所帮助...

      【讨论】:

        【解决方案8】:

        除了@Rajshekar 的彻底answer,我更喜欢返回IHtmlString 值的辅助方法,Razor 将其识别为已编码的HTML。然后,不需要Html.Raw() 包装器,从而提高可读性。

        public static class JSHelper
        {
            /// <summary>
            /// Encode a value as a JSON value or object for use in JavaScript code.
            /// </summary>
            /// <param name="value">Value to encode.</param>
            /// <returns>HTML string containing the JavaScript value or object.</returns>
            public static IHtmlString JsonEncode(object value)
            {
                return MvcHtmlString.Create(Json.Encode(value));
            }
        }
        

        然后我可以在我的 JavaScript 部分中使用 obj = @JSHelper.JsonEncode(myObject);

        在您的视图中包含 using 子句或更新 view/web.config 以解析视图中的命名空间。

        【讨论】:

          【解决方案9】:

          以下是我们在 .net core razor 页面中的操作方式。

          @section scripts
          {
              <script>
                  $(document).ready(function () {
                      leaveStatusDictionary = @Html.Raw(Json.Serialize(Model.LeaveStatusDictionary));
                  });
          
                  function GetStatusName(status) {
                      return window.leaveStatusDictionary[status];
                  }
              </script>
          }
          

          注意以下几点。

          1. 在 leaveStatusDictionary 之前我没有使用 var 关键字。所以这现在是窗口对象的一个​​属性。所以我能够在不同的 js 函数中访问它——你在那里看到的 GetStatusName。

          2. LeaveStatusDictionary 是 Dictionary 类型模型类的属性。

          【讨论】:

            【解决方案10】:

            我使用以下内容将从 Razor 视图中的控制器传递的模型对象转换为 JavaScript 中的 JSON 对象。这在 ASP.Net Core 中非常适合我。

            <script>
                let jsonData = @Html.Raw(Json.Serialize(Model))
                console.log(jsonData)
            </script>
            

            【讨论】:

              猜你喜欢
              • 2020-05-07
              • 2019-05-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-29
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多