繁体   English   中英

通过JavaScript将Razor视图中的局部变量传递给Java脚本函数,然后传递给C#方法

[英]Passing local variable in Razor view by JavaScript to java script function and then to C# method

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

我的按钮:单击javascript:SubmitClick参数传递给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

该类Survey看起来像:

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; }
    }
}

您不能仅将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) {       }

更新:

由于类之间存在循环引用,因此您的Survey实体无法正确序列化。 因此,您这里没有什么选择:

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

你做错了。

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

@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);
    });
}

发回@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为null,对于保存并不重要,因此请保留。

结果

暂无
暂无

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

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