ajax forms and results in popup window - ajax

I have a form in DoComment.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DT.KazBilet.Objects.PublicationComment>" %>
<div class="wrap">
<h4>Comment</h4>
<%using (Ajax.BeginForm("DoComment", "Publication", new {id = Model.Publication.OID, parentId = Model.OID},new AjaxOptions()))
{%>
<%=Html.TextAreaFor(x=>x.Text) %>
<%-- <textarea style="width: 100%; height: 152px;"></textarea>--%>
<input type="submit" value="Publish" class="btn ok_btn" />
<%}%>
</div>
This is my controller's action:
public JsonResult DoComment(PublicationComment model, int id, int parentId)
{
PublicationRepository.SaveComment(User.Identity.Name,id, parentId, model.Text);
return Json(new {
Message = "You comment on moderation"
});
}
I want that user clicks on Publish button then show popup window where will be written text from Message.
Can you help me(some code)?
Thanks.

You could subscribe to the OnSuccess javascript event in the AJAX options and then show the JSON result you have retrieved the way you like (new window, div, ...):
<% using (Ajax.BeginForm(
"DoComment",
"Publication",
new { id = Model.Publication.OID, parentId = Model.OID },
new AjaxOptions { OnSuccess = "onSuccess" })
) %>
and then you would define the onSuccess javascript function. Depending on whether you use jQuery or MicrosoftAjax the implementation of this function might slightly vary and more specifically the way to retrieve the JSON result.
For example if you are using MicrosoftAjax (obsolete now):
var onSuccess = function(e) {
var json = e.get_response().get_object();
alert(json.Message);
};
and if you are jQuery:
var onSuccess = function(json) {
alert(json.Message);
};

Related

how to pass a model to view in ajax-based request in mvc4

I'm creating an ajax-based Quiz in MVC. Below is the Question view. When the form is submitted I save the user selection in the controller then need to send the next question to the view without reloading the page. Is it possible to send/update the model from the controller in the ajax request
#model DataAccess.Question
#{
ViewBag.Title = "Survey";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Ajax.BeginForm("Survey", "Tools", new AjaxOptions { UpdateTargetId = "QuestionContent", HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, new { QuestionId = Model.QuestionId }))
{
<div id="QuestionContent">
<h2>Welcome To Quiz</h2>
<fieldset>
<p>
Question
#Model.QuestionId of #ViewBag.QuestionCount:
</p>
<p>
#Model.Description.
</p>
<ul style="list-style:none;">
#foreach (var item in Model.Answers)
{
<li> #Html.RadioButton("ChoiceList", item.score) #item.AnswerDesc</li>
}
</ul>
<input type="submit" value="Next" id="submitButton" />
</fieldset>
</div>
}
It's much easier to implement an AJAX POST using jQuery and return a JSON object that contains all the next Q&A info. Use js/jQuery to set <div>'s or any other html element. Posting back and reloading is such a pain and becoming an outdated approach.
For example you could have this ViewModel class:
public class Answer
{
public int QuestionId {get; set;}
public string Answer {get; set;}
}
Build a view that has a div & input control for the Q & A.
Implement the Answer Button to POST via AJAX:
$.ajax({
type: "POST",
url: "/Exam/HandleAnswer" ,
data: { QuestionId: _questionId, Answer: $("#txt_answer").val() },
success: function (resp) {
if (resp.Success) {
$("#div_Question").text( resp.NextQuestionMessage);
_questionId = resp.NextQuestionId,
$("#txt_answer").val(''"); //clear
}
else {
alert(resp.Message);
}
}
});
In your ExamController:
[HttpPost]
public ActionResult HandleAnswer(Answer qa)
{
//use qa.QuestionId to load the question from DB...
//compare the qa.Answer to what the DB says...
//if good answer get next Question and send as JSON or send failure message..
if (goodAnswer)
{
return Json(new { Success = true, NextQuestionMessage = "What is the capital of of Texas", NextQuestionId = 123});
}
else{
return Json(new { Success = false, Message = "Invalid response.."});
}
}

Asp.net MVC, 4.0 - Ajax, field value is overriden after update

I am playing around with some ajax, and have experienced a very odd and to me illogical bug.
I am displaying a list of events, wrapped in a form, in a table. Each event has a unique ID (EventID). This is submitted to the action when a button is pressed.
A div surrounding the table is now updated with the partialview that the action has returned.
The problem
When the view is reloaded, all the HiddenFields that contains the field EventID, now cointains the same EventID as. the one that was submitted to the action
I have tried placing a breakpoint in the view, to see what value is put in the HiddenField. Here is see that the correct id is actually set to the field. but when the page updates, all the hiddenfields contains the same eventid as the one originally submitted to the action.
The partialview: _Events
#model SeedSimple.Models.ViewModelTest
<table class="table table-striped table-bordered table-condensed">
#foreach (var item in Model.events)
{
#using (Ajax.BeginForm("AddAttendantToEvent", "MadklubEvents", new AjaxOptions()
{
HttpMethod = "post",
UpdateTargetId = "tableevents"
}))
{
#Html.Hidden("EventID", item.MadklubEventID);
<input type="submit" value="Join!" id="join" class="btn" />
}
#using (Ajax.BeginForm("RemoveAttendantFromEvent", "MadklubEvents", new AjaxOptions()
{
HttpMethod = "post",
UpdateTargetId = "tableevents"
}))
{
#Html.Hidden("EventID", item.MadklubEventID);
<input type="submit" value="Leave" class="btn" />
}
}
</table>
AddAttendantToEvent Action:
[HttpPost]
[Authorize]
public ActionResult AddAttendantToEvent(int EventID)
{
if (ModelState.IsValid)
{
var uow = new RsvpUnitofWork();
var currentUser = WebSecurity.CurrentUserName;
var Event = uow.EventRepo.Find(EventID);
var user = uow.UserRepo.All.SingleOrDefault(u => u.Profile.UserName.Equals(currentUser));
user.Events.Add(Event);
Event.Attendants.Add(user);
uow.Save();
ViewModelTest viewmodel = new ViewModelTest();
viewmodel.events = madklubeventRepository.AllIncluding(madklubevent => madklubevent.Attendants).Take(10);
viewmodel.users = kitchenuserRepository.All;
return PartialView("_Events", viewmodel);
}
else
{
return View();
}
}
How all the input fields look after having submitted EventID 4 to the action
<input id="EventID" name="EventID" type="hidden" value="4">
I am suspecting, this is due to some side-effects from the ajax call, that i am unknown to.
Any enlightentment on the subject would be much appreciated :)

MVC 4 Razor using Ajax forms to update a foreach loop

Where to start...I can find similar things on the Internet as to how, but they never seem to work with my specific way of wanting to do something. I have tried with and without partial views with very little success.
Quick rundown: I have a strongly-typed View with an Ajax form. underneath the form, I have a foreach loop that repeats a code block. I need to be able to update the code block from the forms choices (filters).
Here's my View, 'FindATeacher.cshtml', as it currently stands (after trying many different ideas):
#model Teachers.Models.OmniModel
#{
ViewBag.Title = "FindATeacher";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Find a Teacher</h2>
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions { HttpMethod = "Post", OnSuccess = "onSuccess" }))
{
<div id="ContentFilter">
<div class="filterLabels">
<p>Search by Name</p>
<p>Filter By Instrument</p>
<p>Filter By City</p>
</div>
<div class="filterObjects">
<p>
<input type="text" id="nameTXT" />
<button type="submit" id="findButton">find</button>
</p>
<p>#Html.DropDownList("InstrumentID", (SelectList)Model.Instruments, "-- Select an Instrument --", new { id = "instrumentDD" })</p>
<p>#Html.DropDownList("CityID", (SelectList)Model.Cities, "-- Select a City --", new { id = "cityDD" })</p>
</div>
</div>
}
<hr />
#foreach (var r in Model.Teachers)
{
<div id="ContentResults">
<div id="avatar">
<img src="i" />
</div>
<div id="demographics">
<h6>#r.Teacher</h6>
<strong>#r.StudioName</strong>
<p>#r.URL</p>
<p>#r.StreetAddress</p>
<p>#r.City, #r.AddressStateID #r.Zip</p>
<p>#r.Phone</p>
<p>#r.EmailAddress</p>
</div>
<div id="studioDetails">
<p><strong>Instrument(s) Taught</strong></p>
<p>
#{
var instrumentString = r.Instruments.Aggregate("", (a, b) => a + b.Instrument + ", ");
if (instrumentString.Length != 0)
{
instrumentString = instrumentString.Remove(instrumentString.LastIndexOf(","));
}
}
#instrumentString
</p>
<br />
#if (r.Information != "" && r.Information != null)
{
<p><strong>Information</strong></p>
<p>#r.Information</p>
}
</div>
</div>
}
Now here's my Controller. I get the results back correctly in the Controller, just not updating the code block:
public ActionResult FindATeacher()
{
Model.Instruments = new SelectList(TeacherService.GetInstrumentList(0),"InstrumentID","Instrument");
Model.Cities = new SelectList(TeacherService.GetCityList(),"CityID","City");
Model.Teachers = TeacherService.GetTeacherList("", 0);
return View(Model);
}
[HttpPost]
public JsonResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList("John", 0, 0);
return Json(Model.Teachers);
}
Thanks.
#VishalVaishya presents the right idea, but there's a simpler way, which doesn't involve custom javascript code: AjaxOptions has an UpdateTargetId property that the AJAX toolkit will interpret to mean you want the given target to be updated with the results sent back from the controller.
FindATeacher.cshtml:
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions {
HttpMethod = "Post", UpdateTargetId = "TeacherList" }))
{
...
}
<hr />
<div id="TeacherList">
#Partial("TeacherList", Model.Teachers)
</div>
TeacherList.cshtml
#model IEnumerable<Teacher>
#foreach(var teacher in Model)
{
...
}
Controller action:
[HttpPost]
public ActionResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList(teacherName, instrumentID, cityID);
return PartialView("TeacherList", Model.Teachers);
}
You can try following method:
Separate your foreach loop into another partial view.
And load your partial view on filter / click event and pass filtered parameters to your controller-action.
JS change event code will be something like this:
var teacherName = ''; //get your selected teachername
var instrumentID = ''; //get your selected instrumentid
var cityID = ''; //get your selected city id
var url = '#Url.Action("FilterTeachers", "ControllerName", new { teacherName = "teacher-Name", instrumentID="instrument-ID", cityID="city-ID" })';
url = url.replace("teacher-Name", teacherName).replace("instrument-ID", instrumentID).replace("city-ID", cityID);
$('#result').load(url);

Jquery Accordion Validation Not working when rendering Partial View through $.ajax call

Hi friends,I am working on MVC 4 Razor and I am stuck in a situation
where Employee Personal Details form is to be filled in
steps(wizard)..for which i used jquery accordion control..for every
step i put an accordion..The html in each accordion section is
rendered from partial view through ajax call on every click of
respective accordion (i.e. <h3></h3> tag)..
On page load first/top accordion is active by default. My problem is
to restrict the user to click on next accordion until he/she fills the
presently active accordion correctly..
Here is my full code:
View:
#model XXX.ViewModels.PersonalDetailsViewModel
#{
ViewBag.Title = "PersonalDetails";
Layout = "~/Views/Shared/Template.cshtml";
}
#using (Html.BeginForm("Lifestyle", "Apply", FormMethod.Post, new { id = "personalDetailForm" }))
{
<div class="centerdiv margin_top20">
<div class="row">
#Html.ValidationSummary(true, "Please Correct the following errors:")
</div>
<div style="width: 1000px;">
<div id="Personalaccordion" class="acordion_div" style="padding: 10px; float: left;">
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetBasicDetailsView','personalDetailForm','BasicDetailsDiv');">
<p>
Basic Details<span id="BasicDetailsDivExp"></span>
</p>
</h3>
<div id="BasicDetailsDiv">
</div>
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetPersonalAddressView','personalDetailForm','PersonalAddressDiv');">
<p>
Address<span id="PersonalAddressDivExp"></span></p>
</h3>
<div id="PersonalAddressDiv">
</div>
</div>
<ul id="conlitue_ul" style="margin-top: 20px;">
<li style="margin-left: 140px;">
<input type="submit" class="compareBtn float_lt" value="Continue Buying >" id="continue" /></li>
</ul>
</div>
</div>
}
#Scripts.Render("~/bundles/PersonalDetails")
<script type="text/javascript">
PersonalModule.GetRenderingView('Apply/GetBasicDetailsView', '', 'BasicDetailsDiv');
</script>
My Controller:
public ActionResult PersonalDetails(int leadId)
{
var personalDetailsViewModel = LeadHelper.GetPersonalDetails(leadId);
return View(personalDetailsViewModel);
}
public ActionResult GetBasicDetailsView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.BasicDetails == null)
{
ModelInitializerHelper.InitilaizeBasicDetailsVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializeBasicLookup(personalDetailsViewModel);
return PartialView("Personal/BasicDetails", personalDetailsViewModel);
}
public ActionResult GetPersonalAddressView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.PersonalAddressDetails == null)
{
ModelInitializerHelper.IntializePersonalAddressVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializePersonalAddressLookup(personalDetailsViewModel);
return PartialView("Personal/PersonalAddress", personalDetailsViewModel);
}
My JS :
var PersonalModule = {
GetRenderingView: function (url, formId, containerID) {
var applicationurl = ApplicationRoot + '/' + url;
var objects = $('#BasicDetailsDivExp , #PersonalAddressDivExp' );
viewDivID = containerID;
GetAccordionView(applicationurl, formId, objects, containerID, 'accordion_plus', 'accordion_minus');
}
}
GetAccordionView: function (url, formId, objects, containerID, accordion_plus, accordion_minus) {
var formObjectData = null;
if (formId != undefined) {
formObjectData = $("#" + formId).serialize();
}
var renderView = function (data) {
$('#' + containerID).innerHtml = data;
}
ExpandAccordion(objects, containerID, accordion_plus, accordion_minus);
DoServerRequest(url, formObjectData, renderView);
}
ExpandAccordion: function (objects, spanIconID, accordion_plus, accordion_minus) {
var Objects = objects;
Objects.removeClass(accordion_minus);
Objects.addClass(accordion_plus);
$('#' + spanIconID + 'Exp').removeClass(accordion_plus).addClass(accordion_minus);
if (Browser.ie7) {
Objects.css("margin-top", "-22px");
}
}
DoServerRequest: function (url, data, funSuccess) {
$.ajax({
type: "POST",
url: url,
data: data,
async: false,
dataType: "json",
success: funSuccess,
error: function (errorResponse) {
if (errorResponse.readyState == 4 && errorResponse.status == 200) {
renderCurrentView(errorResponse.responseText)
}
else {
alert(errorResponse.responseText);
}
}
});
}
Please somebody help..I have heard lots of good thing about this forum
and this is my first Question...Thanks in advance..
I have removed my jquery validation attempt as it made the code
garbage thing Now I dont know what to write and where to write
If you are trying to validate data that has been added to form via Ajax after page load then you will need to use the rules method and add rules for these new elements. Jquery Validate has no way of knowing about them otherwise.
Example
Once you have loaded your new content via Ajax you need to find each element and add the necessary rules to them.
$('#yourDiv').find(".newElements").rules("add", {
required: true,
messages: {
required: "Bacon is required"
}
});
If you are using unobtrusive validate you may need to add your new elements to that also. See this SO question for more details.
Validating the Form
To check if the fields are valid, you will need to validate the form on click. This can be done using .validate(). You can then check if the form validated using .valid()
Example
$('#yourForm').validate();
if(!$('#yourForm').valid()) {
alert('Bacon is required');
}

MVC 2.0 Ajax: auto-submit on dropdown list causes normal postback

I am trying to add Ajax functionality to my MVC application. I want a form to post back asynchronously. Here's the form code:
using (Ajax.BeginForm("SetInterviewee", "Date", routeValues, new AjaxOptions { UpdateTargetId = "divInterviewee" }))
and I want it to automatically post back when a dropdown list selected value changes:
<%= Html.DropDownList("interviewees", Model.interviewees.intervieweeLists.intervieweesList, "-- select employee --", new { #class = "ddltext", style = "width: 200px", onchange = "this.form.submit();" })%>
However, when I try this out, the program posts back normally, not a partial postback as I was expecting. Here's what I think the problem is: onchange = "this.form.submit();" in the dropdown list.
I think that this somehow causes a normal postback instead of the asynchronous postback.
Here's what MVC generates for HTML for the form tag:
<form action="/SetInterviewee/2011-1-26/2011-1/visit" method="post" onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));" onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: 'divInterviewee' });">
I think that with "this.form.submit()" the "onsubmit" event handler is not being called. The thing is, I don't understand why. Wouldn't "onsubmit" catch any event that submits the form?
UPDATE: I went to jquery, thusly:
$(function () {
$('#interviewees').change(function () {
var form = $('#intervieweeForm');
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function (result) {
$('#selectedInterviewee').val(result);
}
});
});
});
This is causing many problems, among them:
-- It still does not seem to do an asyncrhonous postback. In my controller action method, I have the following code: "if (Request.IsAjaxRequest())" which returns false.
-- I can't seem to do model binding any more. My route looks like :
http://localhost:1986/Interviews/2011-2-25/2011-2/visit
but the route that apparently ends up being sent is
http://localhost:1986/SetInterviewee/2011-2-25/2011-2?
Count=5&Keys=System.Collections.Generic.Dictionary`2+KeyCollection
[System.String,System.Object]
&Values=System.Collections.Generic.Dictionary`2+ValueCollection
[System.String,System.Object]
causing the model binding not to work -- "visit" is supposed to be a "mode" parameter, but it's not there so "mode" defaults to "phone", which upsets the whole applecart.
It is the serialize command that is causing this? I don't understand why it would append it to the querystring when the method is POST.
There are other things -- among them, the fact that my action must return a ViewResult, so how can I possibly just return a string, which is all I need using ajax ... but I will defer that concern until I get the routing/binding thing straightened out!
UPDATE: "SetInterviewee" is indeed the correct route to post to, but the routeValues parameter should copy the route values from the current view -- I would think. Here's the code for the form:
RouteValueDictionary routeValues = ViewContext.RouteData.Values;
using (Html.BeginForm("SetInterviewee", "Date", routeValues, FormMethod.Post, new { id = "intervieweeForm" }))
So I know this is quite an old question, but I've been messing around with a similar issue and seem to come to a workaround that might prove useful in the future.
Inside your form, add a submit button. Something like:
<input type="submit" name="submit" value="save" style="display: none;" />
Make sure that you have specified the name attribute as it seems to matter in this case. Here is the code I have an it is currently working with full model binding:
<% using (Ajax.BeginForm("SaveStatus", "Finding", new { FindingId = Model.FindingId },
new AjaxOptions {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "StatusWindow",
OnBegin = "function(){ jQuery('#SaveStatusForm').block({ Message: 'Saving' }); }",
OnComplete = "function(){ jQuery('#SaveStatusForm').unblock(); }",
OnFailure = "HandleMSAjaxFail",
}, new { id = "SaveStatusForm" })) { %>
<div>
<%: Html.DropDownListFor(Status => Status.SelectedTagId, Model.AvailableStatuses, null, new Dictionary<string, object> { { "onchange", "jQuery('#SaveStatusForm').submit();" } })%>
<input type="submit" name="submit" value="save" style="display: none;" />
</div>
<% } %>
Granted this is my code and not tied to your example, but you can get the idea from what is going on. Originally I had the dropdownlist just doing a submit and when it fired I was getting all sorts of quirky responses - including a full synchronous postback. When I added the submit button, the MS ajax code seems to work beautifully. Give it a shot!
I would recommend you to use jquery and get rid of all Ajax.* helpers and MSAjax scripts.
So:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<% using (Html.BeginForm("SetInterviewee", "Date", routeValues, FormMethod.Post, new { id = "myform" })) { %>
...
<% } %>
<%= Html.DropDownList(
"interviewees",
Model.interviewees.intervieweeLists.intervieweesList,
"-- select employee --",
new { id = "interviewees", #class = "ddltext", style = "width: 200px" }
)%>
and then in a separate javascript file:
$(function() {
$('#interviewees').change(function() {
var form = $('#myform');
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function(result) {
$('#divInterviewee').html(result);
}
});
});
});
Now we have successfully separated HTML markup from javascript. It is unobtrusive javascript.

Resources