I have a newsletter text box that renders in a PartialView. This is the get action:
[ChildActionOnly]
public PartialViewResult NewsLetterSidebar()
{
return PartialView("_NewsLetterSidebar");
}
And this is the Razor view:
model Blog.Web.UI.ViewModels.NewsLetterViewModel
#{
ViewBag.Title = "_NewsLetterSidebar";
}
#using (Html.BeginForm("NewsLetter", "Home", FormMethod.Post))
{
<h3>News Letter</h3>
<div>
#Html.TextBoxFor(news => news.EmailAddress)
#Html.ValidationMessageFor(news => news.EmailAddress)
</div>
<div>
<input type="submit" value="Verify">
</div>
}
I want the success message to appear under the verify button in case of valid input. This is my post action:
[HttpPost]
public JsonResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
}
return Json("Done!");
}
How can I show the JSON message under the View?
Not tested but will help you to complete what you want.
[HTTPGET]
public JsonResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
}
return Json("Done!", JsonRequestBehavior.AllowGet);
}
replace this
#using (Html.BeginForm("NewsLetter", "Home", FormMethod.Post))
{}
with
#using (Ajax.BeginForm("NewsLetter", "Home", new AjaxOptions{ onsuccess:"ShowMessage"}))
{}
JS
function ShowMessage(data){
alert(data);
}
If you would like to use the first approach from my comment above, you need slightly modify your code. First of all, add Message property to your NewsLetterViewModel, then change the partial view:
#using (Ajax.BeginForm("NewsLetter", new AjaxOptions{UpdateTargetId = "newsletter-container"}))
{
<h3>News Letter</h3>
<span>#Model.Message</span>
<div>
#Html.TextBoxFor(news => news.EmailAddress)
#Html.ValidationMessageFor(news => news.EmailAddress)
</div>
<div>
<input type="submit" value="Verify">
</div>
}
Please noеe that your partial view should be wrapped into a html element with id="newsletter-container" on your page e.g:
<div id="newsletter-container">
#{Html.RenderPartial("_NewsLetterSidebar", new NewsLetterModel());}
</div>
Now, a small change in the controller:
[HttpPost]
public ActionResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
model.Message = "Done!";
}
return PartialView("_NewsLetterSidebar", model);
}
You also need to add jquery.unobtrusive-ajax.js to make it work.
Related
I have a simple model called JobStatus, and I am enabling edit functionality within the Index view with an Ajax Actionlink.
My problem is that if there is a model error when editing an item, I don't know how to bring the item back to the model.
My Index action in my controller:
public ActionResult Index()
{
return View(db.JobStatuses.OrderBy(x => x.JobStatusID).ToList());
}
Here is my Index view:
#model IEnumerable<Project.Models.JobStatus>
#foreach (var item in Model)
{
<div id='#string.Format("div_{0}", item.JobStatusID)'>
#item.JobStatusID
#item.Name
#item.Description
#Ajax.ActionLink("Edit", "Edit", new { id = item.JobStatusID }, new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = string.Format("div_{0}", item.JobStatusID) })
</div>
}
And here is my edit GET request:
public ActionResult Edit(string id = null)
{
JobStatus jobstatus = db.JobStatuses.Find(id);
if (jobstatus == null)
{
return HttpNotFound();
}
return PartialView(jobstatus);
}
My edit.cshtml:
#model Project.Models.JobStatus
#using Microsoft.Ajax;
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.JobStatusID)
#Html.TextBoxFor(model => model.Name, null, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Description, null, new { #class = "form-control" })
<input type="submit" value="Save" />
}
And finally my edit POST method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(JobStatus jobstatus, string action)
{
if (ModelState.IsValid)
{
db.Entry(jobstatus).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
// Not sure what to do here, how to I repopulate my index form?
return RedirectToAction("Index");
}
At the moment, on a modelstate failure the user is just redirected to the index page - what I'd like is to simply redisplay the index form, with the appropriate edit form enabled and populated, and any validation errors shown.
I've tried redirecting to my Edit action, but this just shows my form on a new page, without my index form (because currently my edit action is an ajax action)
Of course, please let me know if there is a better way to achieve this!
You can't do the RedirectToAction with Ajax Post.
Check out asp.net mvc ajax post - redirecttoaction not working
But you can load in the following way
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Edit(JobStatus jobstatus, string action)
{
if (ModelState.IsValid)
{
db.Entry(jobstatus).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return Json(new{id=jobStatus, success=true})
}
Once you get the JSON result from server you can load the same using the id returned
Like
$.post('/jobs/edit',{data:$(form).serialize()},function(data){
if(data.success){
$.get('/jobs/index/'+data.id,{},function(data){
$('#container').html(data);
});
}
});
I'm trying to implement a little ajax using unobtrusive ajax of mvc 3. Here is the code snippet:
Controller:
[HttpGet]
public ActionResult ViewEmployee()
{
return View();
}
[HttpPost]
public ActionResult ViewEmployee(EMPLOYEE model)
{
var obj = new EmployeeService();
var result=obj.FindEmployee(model);
return View("ViewEmployee", result);
}
View:
#{AjaxOptions AjaxOpts = new AjaxOptions { UpdateTargetId = "ajax", HttpMethod = "Post" };}
#using (Ajax.BeginForm("ViewEmployee", "Home", AjaxOpts))
{
#Html.LabelFor(x => x.EmployeeID)
#Html.TextBoxFor(x => x.EmployeeID)
<input type="submit" name="Find Name" value="Find Name" />
}
<div id="ajax">
#{
if (Model != null)
{
foreach (var x in Model.EmployeeName)
{
#x
}
}
else
{
#Html.Label("No Employee is selected!")
}
}
</div>
I debugged the code, its sending the employee id to the ViewEmployee method, finding the name but not being able to display the name back into the view.
I've activated the unobtrusive ajax property in web.config & imported the scripts into the view.
Whats going wrong with this? Please help.
This is simple but effective article, ask me if you have any more question! I resolved the problem! By the way, whats wrong with stackoverflow, i'm not getting no response literally!
http://www.c-sharpcorner.com/UploadFile/specialhost/using-unobtrusive-ajax-forms-in-Asp-Net-mvc3/
I have a form on my page:
#using(Html.BeginForm("DoReservation","Reservation"))
{
...some inputs
<button id="recalculate">Recalculate price</button>
<button id="submit">Submit</button>
}
When I click the "Recalculate price" button I want the following action to be invoked:
public ActionResult Recalculate(FormCollection form)
{
var price = RecalculatePrice(form);
... do some price recalculation based on the inputs
return PartialView("PriceRecalculation",price);
}
When I click the "Submit" button I want the "DoReservation" action to be invoked (I want the form to be submitted).
How can I achieve something like that?
What I can suggest is , adding a new property to your view model and call it ActionType.
public string ActionType { get; set; }
and then change your cshtml file like below
#using (Html.BeginForm())
{
<div id="mytargetid">
...some inputs*#
</div>
<button type="submit" name="actionType" value="Recalculate" >Recalculate price</button>
<button type="submit" name="actionType" value="DoReservation" >Submit</button>
}
in post action method based on ActionType value you can decide what to do !
I noticed that in your comments you mentioned you need to return partial and replace if with returning partial , no problem , you can use
#using (Ajax.BeginForm("DoProcess", new AjaxOptions { UpdateTargetId = "mytargetid", InsertionMode = InsertionMode.Replace }))
and in controller change your action to return partial view or java script code to redirect page
public ActionResult DoProcess(FormModel model)
{
if (model.ActionType == "Recalculate")
{
return PartialView("Test");
}
else if (model.ActionType == "DoReservation")
{
return JavaScript(string.Format("document.location.href='{0}';",Url.Action("OtherAction")));
}
return null;
}
Currently I have a Razor View like this:
TotalPaymentsByMonthYear.cshtml
#model MyApp.Web.ViewModels.MyViewModel
#using (#Ajax.BeginForm("TotalPaymentsByMonthYear",
new { reportName = "CreateTotalPaymentsByMonthYearChart" },
new AjaxOptions { UpdateTargetId = "chartimage"}))
{
<div class="report">
// MyViewModel fields and validation messages...
<input type="submit" value="Generate" />
</div>
}
<div id="chartimage">
#Html.Partial("ValidationSummary")
</div>
I then display a PartialView that has a #Html.ValidationSummary() in case of validation errors.
ReportController.cs
public PartialViewResult TotalPaymentsByMonthYear(MyViewModel model,
string reportName)
{
if (!ModelState.IsValid)
{
return PartialView("ValidationSummary", model);
}
model.ReportName = reportName;
return PartialView("Chart", model);
}
What I'd like to do is: instead of displaying validation errors within this PartialView, I'm looking for a way of sending this validation error message to a DIV element that I have defined within the _Layout.cshtml file.
_Layout.cshtml
<div id="message">
</div>
#RenderBody()
I'd like to fill the content of this DIV asynchronously. Is this possible? How can I do that?
Personally I would throw Ajax.* helpers away and do it like this:
#model MyApp.Web.ViewModels.MyViewModel
<div id="message"></div>
#using (Html.BeginForm("TotalPaymentsByMonthYear", new { reportName = "CreateTotalPaymentsByMonthYearChart" }))
{
...
}
<div id="chartimage">
#Html.Partial("ValidationSummary")
</div>
Then I would use a custom HTTP response header to indicate that an error occurred:
public ActionResult TotalPaymentsByMonthYear(
MyViewModel model,
string reportName
)
{
if (!ModelState.IsValid)
{
Response.AppendHeader("error", "true");
return PartialView("ValidationSummary", model);
}
model.ReportName = reportName;
return PartialView("Chart", model);
}
and finally in a separate javascript file I would unobtrusively AJAXify this form and in the success callback based on the presence of this custom HTTP header I would inject the result in one part or another:
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result, textStatus, jqXHR) {
var error = jqXHR.getResponseHeader('error');
if (error != null) {
$('#message').html(result);
} else {
$('#chartimage').html(result);
}
}
});
return false;
});
i have a button on the cshtml view..its clicked every-time an item is scanned.
The user has to do it one by one and once all the items have been scanned..i want to opem/pop up a new window plus redirect him to another page.. The condition whether it was the last item..is being checked in the controller method.
How can i call a javascript to open the new window from the controller..right before my 'redirecttoaction' ?
is there a better way to do it?
Here's a sample pattern:
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// TODO Process the scanned code model.Code
if (IsLastItem())
{
model.IsLast = true;
}
return View(model);
}
and inside the view:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Code)
<input type="submit" value="OK" />
}
<script type="text/javascript">
#if (Model.IsLast)
{
<text>
window.open('#Url.Action("foo")', 'foo');
window.location.href = '#Url.Action("bar")';
</text>
}
</script>
Its not clean to call JavaScript from controller. Instead, move the logic of checking if its a last item to the client side and call appropriate controller action as appropriate.