【问题标题】:Passing local variable in Razor view by JavaScript to java script function and then to C# method通过JavaScript将Razor视图中的局部变量传递给java脚本函数,然后传递给C#方法
【发布时间】:2014-08-31 16:56:41
【问题描述】:

我想将class Survey 的对象@survey 传递给JavaScript 函数SubmitClick,然后传递给PersonController.cs 中的SubmitSurvey

我的按钮:点击时会将参数传递给javascript:SubmitClick

<button class='mybutton' type='button' onclick="javascript:SubmitClick(@Model.Item1.Id, @survey);">Save Survey</button>

和JavaScript函数:

function SubmitClick(pid, sid) {     
    var url = '@Url.Action("SubmitSurvey", "Person")';
    $.post(url, { personId: pid, survey: sid }, function (data) {
        alert('updated' + pid);
    });
}

以及我要传递的方法@survey:

  public void SubmitSurvey(int personId, Survey survey) {

        }

结果是:

我想指出传递@survey.Id(int) 有效,所以唯一的问题是传递@survey

将参数传递给 java 脚本函数时弹出错误。


编辑

按钮在 foreach 循环中,模型有点复杂。我可以在循环中序列化它吗?

我从这里将调查列表传递给视图:

 public ActionResult _Survey1(int id) {
            System.Diagnostics.Debug.WriteLine("PASSED ID: " + id);
            Person person = db.Persons.Find(id);
            //Passing a Tuple to Partial View, I want to pass copies further I use copying constructor
            List<Survey> localSurveysCopy = new List<Survey>();
            foreach (Survey survey in db.Surveys) {
                localSurveysCopy.Add(new Survey(survey));
            }
            var tuple = new Tuple<Person, List<Survey>>(person, localSurveysCopy) { };
            return PartialView(tuple);
 }

观点:

 @using WebApplication2.Models
@model   System.Tuple<Person, List<Survey>>

<hr />
<h1>Surveys</h1>

<input type="button" id="Coll" value="Collapse" onclick="javascript:CollapseDiv()" />

@{int i = 1;}
@foreach (var survey in Model.Item2) {
    using (Html.BeginForm()) {
        <h2>Survey @(i)</h2>
        <p />
        @Html.EditorFor(x => survey.Questions)
        <button class='mybutton' type='button' onclick="javascript:SubmitClick(@Model.Item1.Id,  @Newtonsoft.Json.JsonConvert.SerializeObject(survey));">Save Survey</button>
    }
    i++;
    <hr style="background-color:rgb(126, 126, 126);height: 5px" />
}
<hr />

脚本。我想我必须直接传递变量,因为我有很多调查和很多按钮:

function SubmitClick(pid, sid) {     
    var url = '@Url.Action("SubmitSurvey", "Person")';
    var objSurvey = $.parseJSON(sid);
    $.post(url, { personId: pid, survey: objSurvey }, function (data) {
        alert('updated person' + pid + ' survey ' + sid);
    });
}

我明白了:

A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in System.Web.Mvc.dll
A first chance exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in System.Web.Mvc.dll

类调查看起来像:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplication2.Models {


    public class Survey {
        public int Id { set; get; }
        public virtual ICollection<Question> Questions { set; get; }

        public Survey() { }
        public Survey(Survey survey) {
            Id = survey.Id;
            Questions = new List<Question>();
            System.Diagnostics.Debug.WriteLine("SURVEY " + survey.Questions == null);
           foreach (Question question in survey.Questions) {
                Questions.Add(new Question(question));
            }
        }
    }
    public class Question {
        public int Id { set; get; }
        public string QuestionText { set; get; }
        public virtual ICollection<Answer> Answers { set; get; }
        public virtual Survey Survey { get; set; }
        public string SelectedAnswer { set; get; } //this field is SET after clicking SAVE button

        public Question() { }

        public Question(Question question) {
            Id = question.Id;
            QuestionText = question.QuestionText;
            Answers = question.Answers;
            Survey = question.Survey;
            SelectedAnswer = "";
        }
    }
    public class Answer {
        public int Id { set; get; }
        public string AnswerText { set; get; }
        public virtual Question Question { get; set; }
        public virtual ICollection<Person> Persons { get; set; }
    }
}

【问题讨论】:

  • 为什么要发回@survey 对象?如果@survey有属性Answer并且它的值为空,那么用户将UI中的Answer输入&lt;input name="Answer" type="text" /&gt;更改为Some Value,提交按钮不会发送Some Value,而是空值,您需要做的是序列化表单,而不是发送@survey

标签: javascript .net asp.net-mvc razor


【解决方案1】:

您不能只将 C# 对象传递给 JS 并将其发回。

你应该:

  • 将您的对象转换为 JSON 并将其传递给 JS。我建议使用Newtonsoft.JSON

控制者:

string json = JsonConvert.SerializeObject(survey);

标记:

<button class='mybutton' type='button' onclick="javascript:SubmitClick(@Model.Item1.Id, @json);">Save Survey</button>
  • 然后,您应该从 JS 将 JSON 发布到您的 MVC 控制器,然后 MVC 会将其反序列化为您的 C# 对象。

标记:

function SubmitClick(pid, sid) {     
    var objSurvey = $.parseJSON(sid);
    var url = '@Url.Action("SubmitSurvey", "Person")';
    $.post(url, { personId: pid, survey: objSurvey }, function (data) {
        alert('updated' + pid);
    });
}

控制者:

  public void SubmitSurvey(int personId, Survey survey) {       }

更新:

由于类之间的循环引用,您的调查实体无法正确序列化。所以你在这里有几个选择:

  • 使用 [JsonIgnore] 属性忽略反向引用。 (所以你应该用这个属性标记 Question 类中的 Survey 属性,Answer 类中的 Question 属性等等)请记住,这些字段不会序列化为 JS 并反序列化回 C# 对象
  • 为序列化创建没有循环引用的单独模型,并在转换为 JSON 时使用它。

【讨论】:

  • 我对 OP 进行了编辑。我之前没有发布它,因为我想保持问题简单。交易是我在按钮中有很多调查,我得到序列化错误可能是由于虚拟属性。请查看编辑。
  • 只是想知道你为什么在剃刀标记中写@Newtonsoft.Json.JsonConvert.SerializeObject(Model) 而不是@Newtonsoft.Json.JsonConvert.SerializeObject(survey)?您应该通过序列化调查,而不是整个模型。
  • 你说得对,我刚刚处理这个问题将近一个星期。我犯了一个错误。我更正了它编辑了 OP 我得到了同样的错误。我评论了function SubmitClick(pid, sid) { 的内容以确保此处抛出异常` ` 也许延迟加载是一个原因?我将尝试在视图中捕获。
  • 我不知道如何在 Razor 视图中围绕 html 进行 try-catch。没用。
【解决方案2】:

你做错了。

基本上,当您执行@survey 时,您正在查看服务器端代码。在客户端,这个@survey,它是一个强类型clr类的一个实例,被转换为字符串,并且你知道当你将对象转换为字符串时会发生什么,你会得到它的字符串类型,即

@survey.ToString() == "WebApplications2.Models.Survey"

显然这是错误的原因,你的按钮标签的标记,最后,实际上变成了:

<button class='mybutton' type='button' 
         onclick="javascript:SubmitClick(@Model.Item1.Id, 
                                     WebApplications2.Models.Survey);">
        Save Survey
</button>

您应该首先在服务器端序列化您的@survey 对象并将其存储在隐藏变量中,即

@Html.Hidden("hdnSurvey", Newtonsoft.Json.JsonConvert.SerializeObject(Model))

并在你的 javascript 中使用这个隐藏变量

function SubmitClick(pid) {     
    var objSurvey = $.parseJSON( $('#hdnSurvey').val());

    var url = '@Url.Action("SubmitSurvey", "Person")';

    $.post(url, { personId: pid, survey: objSurvey }, function (data) {
        alert('updated' + pid);
    });
}

【讨论】:

  • 我想知道你为什么对 JSON 使用隐藏字段?我想你可以直接将它传递给 JS 函数,它会被解析为 JS 对象,对吧?
  • 你是绝对正确的。只是为了简单起见,并指出,它与您传递它的方式或 javascript 函数无关
  • 我发布了对 OP 的编辑。我之前没有发布它,因为我想保持问题简单。交易是我在按钮中有很多调查,并且我得到序列化错误可能是由于虚拟属性。请查看编辑。
【解决方案3】:

发回@survey变量是没有意义的,来自UI的变化不会反映在变量上,而是来自HTML输入,你真正需要的是序列化表单。

这是您真正需要的完整解决方案。

型号

public class Person
{
    public int Id { set; get; }
}
public class Survey
{
    public int Id { set; get; }
    public virtual ICollection<Question> Questions { set; get; }
}
public class Question
{
    public int Id { set; get; }
    public string QuestionText { set; get; }
    public virtual ICollection<Answer> Answers { set; get; }
    public int SelectedAnswerId { set; get; } // Notice that I change it into int not string
}
public class Answer
{
    public int Id { set; get; }
    public string AnswerText { set; get; }
}

控制器

public ActionResult Index()
{
    var person = new Person { Id = 1 };
    var survey = new Survey
    {
        Id = 12,
        Questions = new List<Question> 
        {
            new Question 
            {
                Id = 34,
                QuestionText = "What is your favorite language?",
                Answers = new List<Answer>
                {
                    new Answer { Id = 56, AnswerText = "A#" },
                    new Answer { Id = 57, AnswerText = "B#" },
                    new Answer { Id = 58, AnswerText = "C#" }
                }
            }
        }
    };

    var model = new Tuple<Person, List<Survey>>(person, new List<Survey> { survey });
    return View(model);
} 

[HttpPost]
public ActionResult SubmitSurvey(int personId, Survey survey)
{
    return Json(new { success = true });
}

Index.cshtml

@model  Tuple<Person, List<Survey>>
@{
    ViewBag.Title = "Index";
}

<h2>Surveys</h2>

@{int i = 1;}
@foreach (var survey in Model.Item2)
{
    using (Html.BeginForm())
    {
        <h3>Survey @(i++)</h3>
        @Html.HiddenFor(x => survey.Id)
        @Html.EditorFor(x => survey.Questions)
        <button class="mybutton" type="button">Save Survey</button>
    }
}

@section Scripts
{
    <script>
        $(".mybutton").click(function () {
            var personId = "@Model.Item1.Id";
            var survey = $(this).closest("form").serialize();
            var data = survey + "&personId=" + personId;
            $.ajax({
                type: "POST",
                url:  "@Url.Action("SubmitSurvey", "Survey")", 
                data: data,
                traditional: true,
                success: function (data) {
                    alert("submitted :" + data.success);
                }
            });
        });
    </script>    
}

EditorTemplates/Question.cshtml

@model Question
<h3>@Model.QuestionText </h3>

@Html.HiddenFor(x => x.Id)
@foreach (var a in Model.Answers)
{
    <label>@Html.RadioButtonFor(b => b.SelectedAnswerId, a.Id) @a.AnswerText</label>
}

结果

如果用户在第一个问题的第一个调查中选择B#,则提交的调查将返回SelectedAnswerId 为57。AnswersQuestionText 等其他属性为空,它们对于保存就这样吧。

【讨论】:

    猜你喜欢
    • 2018-12-14
    • 2018-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-27
    • 1970-01-01
    相关资源
    最近更新 更多