0

私はC#のASP.NETMVC3で作業しています。

データベースに質問を含むテーブルがあります。管理者は、新しい質問を追加したり、質問を編集したりできます。

質問と回答(つまり回答)を格納する別のテーブルがあります。

例:

質問表:

QuestionId..........質問

....... 1 ..............お元気ですか?

....... 2 .........なぜ空が青いのですか?

私の見解では、「すべての質問について、質問を印刷し、質問に回答するためのテキスト領域を提供する」と言います。

次に、「送信したら、すべての質問と回答のペアを質問と回答のテーブルに保存します」と言いたいです。

回答表:

AnswerId........質問........回答

...... 1 .........お元気ですか?......元気です

...... 2 ....空が青いのはなぜですか?...

問題は、質問の数が任意/可変であるため、テキスト領域の数が任意であるということです。その情報を投稿アクションに渡すにはどうすればよいですか?

編集

これがXanderの推薦後の私の見解です

@using (Html.BeginForm("QuestionsAndAnswers", "Product"))
{
    int i = 0;
    foreach (var m in Model.Questions)
    {
    i++;
    <div>@m.Body</div>
    @Html.TextArea(string.Format("textareas[{0}]", i))
    <br />
    }
    <input type="submit" value="Save"/>
    @Html.ActionLink("Cancel", "Index", "Home");
}
4

4 に答える 4

2

ビューを使用して...

@using (Html.BeginForm("QuestionsAndAnswers", "Product"))
{

    foreach (var m in Model.Questions)
    {
    <div class="formfields">
    <input type="hidden" name="QuestionId" id="QuestionId" value="@m.QuestionId" />
    <div>@m.Body</div>
    <textarea name="Answer" id="Answer"></textarea>
    </div>
    }
    <input type="submit" value="Save"/>
    @Html.ActionLink("Cancel", "Index", "Home");
}

これがそのためのJqueryです...

<script type="text/javascript">
    $.fn.serializeObject = function () {
        var o = {};
        var a = this.serializeArray();
        $.each(a, function () {
            if (o[this.name]) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        });
        return o;
    };
    $(document).ready(function () {
        $("#Submit").click(function () {
            var QuestionAnswerArray = [];
            var QuestionAnswerLength = $(".formfield").length;
            $(".formfield").each(function (i) {
                var test = $(this).find("textarea, input").serializeObject()
                QuestionAnswerArray.push(test);
                if ((i + 1) == QuestionAnswerLength) {
                    $.ajax({
                        type: 'POST',
                        url: '/../Product/QuestionsAndAnswers',
                        data: JSON.stringify(QuestionAnswerArray),
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        success: function (return_flag) {                            
                            if (return_flag == true) {
                                alert("Question and Answers Saved Succesfully!");                                
                            } else {
                                alert("Error Occured");
                            }
                        }
                    });
                }
            });
        });
    });
</script>

コントローラーでアクションを実行します。

[HttpPost]
public ActionResult QuestionsAndAnswers(Answers[] answers)
{
                foreach (var item in answers)
                {
                    // do whatever you want here
                }
                return View();
}
于 2012-04-28T10:10:36.217 に答える
1

モデル:

public class Question
{
    public int Id { get; set; }
    public string QuestionText { get; set; }
}

public class Answer
{
    public int Id { get; set; }
    public string QuestionText { get; set; }
    public string AnswerText { get; set; }
}

ViewModel:

public class AnswersViewModel
{
    public IList<Answer> Answers { get; set; }
}

コントローラ:

public class AnswersController : Controller
{
    QuestionRepository _questionRepository = new QuestionRepository();

    public ActionResult Index()
    {
        AnswersViewModel model = new AnswersViewModel();
        model.Answers = new List<Answer>();
        IEnumerable<Question> questions = _questionRepository.GetRandomQuestions();
        foreach (Question question in questions)
        {
            model.Answers.Add(new Answer() { QuestionText = question.QuestionText });
        }
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(AnswersViewModel model)
    {
        //the model will be properly bound here
        return View(model);
    }
}

Views / Answers / Index.cshtml

@model MvcApplication1.Models.AnswersViewModel
@{
    ViewBag.Title = "Index";
}
@using (Html.BeginForm("Index", "Answers", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.EditorFor(x => x.Answers)
    <input name="submit" type="submit" value="Submit" />
}

Views / Answers / EditorTemplates / Answer.cshtml

@model MvcApplication1.Models.Answer
@Html.HiddenFor(x => x.Id)
@Html.HiddenFor(x => x.QuestionText)
@Html.DisplayFor(x => x.QuestionText)
<br />
@Html.TextAreaFor(x => x.AnswerText)
<br />

編集:

答えをより明確にするために更新しました。

于 2012-04-27T23:28:40.090 に答える
1

モデルまたはビューモデルから配列を受け取るようにコントローラーを作成することはできますが、配列はORM対応ではありません(ドメインモデルを使用してビューを直接表示する場合)。そのことを念頭に置いて、コントローラーのビューはIList;で動作します。IList柔軟性があり、配列とは異なり、要素の数による制約を受けません。IListは、アレイと比較してORM対応です。

The only adjustment we should make is in view; HTML or rather javascript, doesn't have notion of list, it can only use an array or associative array. Acknowledging this limitation, we will emit those items from List<ClassType> to javascript-friendly arrays.

Finally, when we submit, our friendly neighborhood ASP.NET MVC will take care of these matters for us, i.e. it can automatically populate our List<ClassType> variables based on the submitted arrays from HTML/javascript, i.e. there is no need for us to iterate the Request.Form, no need for manual population, everything our code operates on is Model/ViewModel-centric as they are ought to be. ASP.NET MVC coders' life is wonderful isn't it? ;-)

Complete code below:


Model:

namespace SoQna.Models
{
    public class Question
    {
        public int QuestionId { get; set; }
        public string QuestionText { get; set; }
    }

    public class Answer
    {
        public int AnswerId { get; set; }
        public Question Question { get; set; }
        public string AnswerText { get; set; }
    }
}

ViewModel:

using System.Collections.Generic;

namespace SoQna.ViewModels
{
    public class QnaViewModel
    {
        public IList<AnswerToQuestion> Answers { get; set; }
    }

    public class AnswerToQuestion
    {
        public int ToQuestionId { get; set; }
        public string QuestionText { get; set; }
        public string AnswerText { get; set; }
    }
}

Controller:

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

namespace SoQna.Controllers
{
  public class HomeController : Controller
  {
    IList<SoQna.Models.Question> _qnaRepo = new List<SoQna.Models.Question>
    {
      new SoQna.Models.Question { QuestionId = 1, 
        QuestionText = 
          "Why is there a proliferation of different kind of ORMs?" 
      },
      new SoQna.Models.Question { 
          QuestionId = 2, QuestionText = "How are you?" 
      },
      new SoQna.Models.Question { 
          QuestionId = 3, QuestionText = "Why the sky is blue?" 
      },          
      new SoQna.Models.Question { 
          QuestionId = 4, QuestionText = "Why is MVC the bees knees?" 
      },          
    };


    public ActionResult Index()
    {
      var qna = new SoQna.ViewModels.QnaViewModel { 
          Answers = new List<SoQna.ViewModels.AnswerToQuestion>() 
      };

      foreach (var question in _qnaRepo)
      {
        if (question.QuestionId == 1) continue; // subjective :-)

        qna.Answers.Add(
          new SoQna.ViewModels.AnswerToQuestion { 
              ToQuestionId = question.QuestionId, 
              QuestionText = question.QuestionText, 
              AnswerText = "Put your answer here" 
          }
        );         
      }

      return View(qna);
    }

    [HttpPost]
    public ViewResult SubmitAnswers(SoQna.ViewModels.QnaViewModel a)
    {
      foreach (var answer in a.Answers)
      {
        answer.QuestionText = _qnaRepo.Single(x => 
           x.QuestionId == answer.ToQuestionId).QuestionText;
      }
      return View(a);
    }

  }//HomeController
}//namespace

View for Home/Index

@model SoQna.ViewModels.QnaViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Hahah</h2>

@using (Html.BeginForm("SubmitAnswers", "Home"))
{


    int i = 0;
    foreach (var answer in Model.Answers)
    {
        @: Question #@(answer.ToQuestionId) <br />

        @Html.Hidden("Answers[" + i + "].ToQuestionId", answer.ToQuestionId)

        @Html.Label("Answers[" + i + "].QuestionText", answer.QuestionText)

        @* 
           to save bandwidth we didn't include QuestionText on submit, 
           this is done by assigning it on Label, and no need to persist 
           QuestionText on Hidden 
        *@

        <br />

        @Html.TextArea("Answers[" + i + "].AnswerText", answer.AnswerText)

        <hr />

        ++i;

    }

    <input type="submit" value="Done" />
}

View for Home/SubmitAnswers

@model SoQna.ViewModels.QnaViewModel

@{
    ViewBag.Title = "SubmitAnswers";
}

<h2>SubmitAnswers</h2>


@foreach (var item in Model.Answers)
{
    @: Answer to question: @item.QuestionText
    <br />    
    @item.AnswerText

    <hr />
}
于 2012-04-28T12:10:38.723 に答える
0

I suggest to build hidden field, something like this:

<input type="hidden" name="questionsAndAnswers" 
value="[{'id':questionId, 'question':questionName, 'answer':answerName}, 
        {'id':questionId, 'question':questionName, 'answer':answerName}...] />

Then you serialize posted hidden value

于 2012-04-28T15:05:35.680 に答える