2013-11-27 16 views
2

我有一个web应用程序,我正在构建一个测试/问题/答案应用程序,我认识一位老师。其中一个要求是测试必须在一次会议中完成......即......不保存并继续。我选择通过使用jQuery UI的模式弹出窗口来实现这一点。在测试开始前,我有一个测试搜索页面和一个模态确认对话框。我遇到的问题是在用户选择继续测试之后,它需要重定向到一个新页面,其中第一个问题将显示模式弹出窗口(之后的每个问题将通过AJAX加载到相同的模式弹出窗口中)。我有搜索工作,以及确认弹出窗口,但我无法弄清楚如何重定向到问题页面。我的TestingController中的Question操作被调用并且参数是正确的,但是一旦返回View,ASP.NET将引发一个异常,告诉我第一个参数为null。以下是控制此行为的片段:从ASP.NET MVC中成功的AJAX调用重定向

从Search.cshtml(这个div是模态确认弹出):

<div id="dialog" title="Confirm Test"> 

     <p> 
      <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Are you sure you want to take the selected test? 
     </p> 

    </div> 

@section scripts 
{ 
    <script type="text/javascript"> 

     $(document).ready(function() { 

      $(".takeTest").click(function (e) { 

       e.preventDefault(); 

       var testId = $(this).data("test-id"); 
       $("#selectedTestId").val(testId); 

       $("#dialog").dialog("open"); 

      }); 

      $("#dialog").dialog({ 
       dialogClass: "no-close", 
       autoOpen: false, 
       modal: true, 
       resizable: false, 
       height: 180, 
       buttons: { 
        'Confirm': function() { 

         var appId = $("#applicantId").val(); 
         var id = $("#selectedTestId").val(); 

         $.ajax({ 
          url: "/Testing/TakeTest/", 
          data: { applicantId: appId, testId: id }, 
          type: "POST", 
          success: function (results) { 
           window.location.href = "/Testing/Question/"; 
          } 
         }); 
        }, 
        'Cancel': function() { 
         $(this).dialog('close'); 
        } 
       } 
      }); 
     }); 

    </script> 
} 

从TestingController:

 [HttpPost] 
     public ActionResult TakeTest(int applicantId, int testId) 
     { 
      try 
      { 
       ApplicantTest test = TestingRepository.GetInstance().TakeTest(applicantId, testId); 
       return RedirectToAction("Question", "Testing", new { applicantId = applicantId, testId = testId }); 
      } 
      catch 
      { 
       return RedirectToAction("Search", "Testing"); 
      } 
     } 


     [HttpGet] 
     public ActionResult Question(int applicantId, int testId) 
     { 
      Question nextQuestion = TestingRepository.GetInstance().GetNextQuestion(applicantId, testId); 
      NextQuestionViewModel model = AutoMapper.Mapper.Map<NextQuestionViewModel>(nextQuestion); 
      model.ApplicantId = applicantId; 
      model.QuestionNumber = (nextQuestion.ApplicantTestAnswers.Count + 1); 
      return View(model); 
     } 

来自Question.cshtml:

@Html.HiddenFor(x => x.ApplicantId, new { id = "applicantId" }) 
@Html.HiddenFor(x => x.TestId, new { id = "testId" }) 

<div id="dialog" title="Question: @Model.QuestionNumber"> 

    @Html.Partial("_NextQuestionPartial", Model) 

</div> 

@section scripts 
{ 
    <script type="text/javascript"> 

     $(document).ready(function() { 

      $("#dialog").dialog({ 
       dialogClass: "no-close", 
       autoOpen: true, 
       modal: true, 
       resizable: false, 
       height: 400, 
       buttons: { 
        'Next': function() { 


        } 
       } 
      }); 


     }); 

    </script> 
} 

从_NextQuestionPartial.cshtml:

@Ajax.BeginForm("Question", "Testing", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "nextQuestionContainer" }) 
{ 
    <fieldset> 
     <legend>Question # @Model.QuestionNumber</legend> 

     <div id="nextQuestionContainer"> 
      <p>Q: @Model.QuestionText</p> 
      <ul> 
       @foreach (var answer in Model.QuestionAnswers) 
       { 
        <li> 
         @answer.Answer 
        </li> 
       } 
      </ul> 
     </div> 
    </fieldset> 
} 

在Search.cshtml模态确认弹出罚款和确认按钮调用TestingController问题的行动(与断点VS验证)。 applicantId和testId都填充了正确的值。 NextQuestionViewModel被正确创建并且返回View(模型)被调用,但是这正是我所迷失的事情发生的地方。我得到了这个异常:参数字典包含一个空方法'System.Web.Mvc.ActionResult Question(Int32,Int32)'的非空类型'System.Int32'的参数'applicantId'的空项。

但是,如果我直接从URL中将这些参数添加到querystring中,页面将加载并且问题的模式弹出窗口会正确显示。看起来这是一个路由问题,但我是MVC的新手,我无法理解为什么TestingController :: TakeTest中的RedirectToAction正在抛出有关applicantId的此异常,因为我可以在操作方法Question中看到它的值。

+0

等待。当你从头到尾地执行这个过程时,是否会发生异常*只是在用户在第**行确认测试后返回RedirectToAction(“Question”,“Testing”,...'**或者第一个问题成功显示并*然后*抛出异常? – William

+0

它发生在第一个问题显示之前。使用Fiddler,我已经确定有2个调用操作方法。第一个来自我的TakeTest操作方法,然后是第二个(从ajax成功函数中的window.location.href行猜测)。第一个参数是querystring,第二个参数不是......因此错误。我不确定最好的方法来做这个重定向,所以也许它 – user1011627

+0

如果我删除了window.location.href,那么对话框并没有关闭,但是只有第一个请求被执行(带有查询字符串参数),但是对话框保持不变打开重定向不会发生。如果我将$(this).dialog('close')添加到成功函数中,我得到一个javascript错误:“JavaScript运行时错误:无法在初始化之前调用对话框上的方法;试图调用方法'关闭'” 确定如何关闭模式对话框,然后将其重定向到问题页面。 – user1011627

回答

3

最快的解决将是改变你的线路:

window.location.href = "/Testing/Question/"; 

以下几点:

window.location.href = "/Testing/Question?applicantId=" + appId + "&testId=" + id; 

编辑:用户用户确认

之后,他/她想要要参加测试,您可以:

  1. 重定向页面并全部替换其内容。
  2. 用测试的第一个问题替换页面的一部分。

根据你的问题,我假设你要#1。通过这种方式,用户确认后,浏览器会被重定向到类似http://YourSite.com/Testing/Question?applicantId=123&testId=456一个网址“而不是停留在” http://YourSite.com/TestPage”。

我能想到做到这一点,最好的办法是用一个简单的HTML表单,绕过$.ajax完全调用它看起来像你有两个元素,你用jQuery引用了它,它是由ids'applicantId'和'selectedTestId'知道的。我不知道你是如何为这些元素赋值的,但是你可以把它们包装起来在像这样的一种形式:

<form id="testForm" action="/Testing/TakeTest" method="post"> 
    <!-- Put your two elements here --> 
    <!-- For example: --> 
    <input id="applicantId" name="applicantId" type="hidden" /> 
    <input id="selectedTestId" name="testId" type="hidden" /> 
</form> 

注:通知如何的上述共同输入的name属性与您的Question操作方法中的参数名称相对应。 然后,你可以用以下替换整个$.ajax电话:

$('#testForm').submit(); 

默认情况下,这将您的数据提交给你的TestPage POST操作,这反过来将浏览器重定向到/测试/问题......“并呈现新的页面。

摘要:由于您不想简单地替换页面的一部分,请避免使用ajax调用并仅使用表单提交数据。

+0

感谢威廉。这确实起作用,如果我从TakeTest中删除RedirectToAction,则只会调用一次,这也很好。无论如何,我都会接受你的回答,但我确实对你的回复有疑问。当我看到“最快......”时,这让我相信有可能有更好的方法来实现这一点。在我的情况下,最好是从服务器重定向,并以某种方式处理成功函数中的问题,或者按照您的答案构建重定向?只是想确保我正在学习最好的方式来做到这一点,因为我没有时间紧迫...感谢你的时间。 – user1011627

+0

你打赌!它确实取决于您点击“确认”后用户同意参加测试时想要发生的事情。我会编辑我的答案来涵盖这一点。 – William

+0

谢谢......我认为完成要求的最佳方式是使用模态对话框。我有另一个要求,测试可以采取多次,但只有在一个3个月内一次。因此,确认用于确保他们想要开始测试。我试图做的是当选择一个测试(即......测试?链接)时从Search.csthml中弹出对话框。我认为最好重定向到另一个页面(Question.cshtml),然后显示一个包含问题的新模态对话框。当问题得到解答时,对话框会通过另一个AJAX调用来获得一个新问题 – user1011627