I am new to asp .net mvc3. I am trying to create a failrly simple blog comments section.
I have a CommentsViewModel
public class CommentsViewModel
{
public CommentModel NewComment { get; set; }
public IList<CommentModel> CommentsList { get; set; }
}
The corresponding view is like
<div id="CommentsArea">
#Html.Partial("CommentsList", Model.CommentsList)
</div>
#using (Ajax.BeginForm("Create",
"Comment",
new { id = Model.NewComment.detailsId, comment = Model.NewComment },
new AjaxOptions { UpdateTargetId = "CommentsArea" ,
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace}))
{
<div class="display-label">Add Comment</div>
<div class="display-field">
#Html.EditorFor(model => Model.NewComment.Body)
</div>
<input type="submit" value="Post" />
}
Now when user enters Post button I want the "CommentsArea" to be updated with the new comments list and also the form values to be cleared with empty text.
Here is the Post method:
[HttpPost]
public ActionResult Create(int id, CommentModel newcomment)
{
var newsItem = m_db.NewsList.Single(news => news.Id == id);
if (!string.IsNullOrWhiteSpace(newcomment.Body))
{
newcomment.detailsId = id;
newsItem.Comments.Add(newcomment);
m_db.SaveChanges();
}
return PartialView("CommentsList", newsItem.Comments);
}
Now when user clicks Post button the list gets updated properly,
but the form values are not cleared. i.e. if I posted a comment "New Comments", the comments list gets updated with "New Comments", but that text remains inside the edit box of the form.
How do I clear that text?
just call a js function on success of form submit.
#using (Ajax.BeginForm("Create",
"Comment",
new { id = Model.NewComment.detailsId, comment = Model.NewComment },
new AjaxOptions { OnSuccess="ClearInput", HttpMethod = "Post",}))
on js function render create view again
function ClearInput(){
//call action for render create view
$.ajax({})
}
Related
My first ever Ajax request is failing, and I'm not quite sure as to why.
I've used the MVC scaffolding in order to create a table (which uses a default #Html.Actionlink). However, I'm looking to include an 'edit' section on the same page via ajax requests.
So my table now has:
<td>
#Ajax.ActionLink("Edit", "Edit", new { id=item.OID}, new AjaxOptions {
UpdateTargetId = "editblock",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET" }
) |
As suggested here.
Within the same view i have a div defined as:
<div id="editblock">
Edit Section Here
</div>
And My controller is defined as:
public PartialViewResult Edit(int? id)
{
if (id == null)
{
return PartialView(new HttpStatusCodeResult(HttpStatusCode.BadRequest));
}
TableModel tablevar = db.TableModel.Find(id);
if (tablevar == null)
{
return PartialView(HttpNotFound());
}
return PartialView("Edit", tablevar );
}
[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult Edit( TableModel tablevar )
{
if (ModelState.IsValid)
{
db.Entry(tablevar ).State = EntityState.Modified;
db.SaveChanges();
}
return PartialView("Edit",tablevar );
}
My "Edit.cshtml" looks like:
#model Project.Models.TableModel
<body>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
Could anyone suggest as to why this is failing, and what I should be doing instead to render this partial view onto the page (as currently it keeps redirecting to new page and not showing on 'index' screen)?
Place those scripts at the bottom of your view. By the time they execute your form isn't present (and therefore the auto-wireup fails). In general, you want <script> tags as close to the </body> tag as possible to your content is there before the script executes.
Other than that, you look fine.
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.."});
}
}
I am building a page where a user can view the details of an item which s/he selected.
As part of this project, I need to show all the comments that are listed under this particular item using Ajax and partial views.
In the Controller class, I am somehow unable to pass the productID of the selected item to the partial view method. When I hard code the productID into the method, the comments show up, however when I pass it through the parameter, the method won't even trigger.
All the product details, however, show without restrictions.
I would appreciate any help. Below please find the code in my Controller
public ActionResult Index()
{
List<Product> productList = new ProductClient().GetAllProducts().ToList();
return View("Index", productList);
}
//This method works correctly. The id of the product is passed.
public ActionResult Details(int id)
{
return View(new ProductClient().GetProductByID(id));
}
// This method is not even getting triggered.
public PartialViewResult ProductComments(int id)
{
List<Comment> commentList = new ProductCommentClient().GetCommentsByProductID(id).ToList();
return PartialView("_comments", commentList);
}
This is my Details.cshtml
#Ajax.ActionLink("Product Comments", "ProductComments(" + #Model.ID + ")", new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId= "divComments",
InsertionMode = InsertionMode.InsertAfter
})
<fieldset>
<div id="divComments">
<legend>Comments</legend>
</div>
</fieldset>
Many thanks in advance.
I solved this.
#Ajax.ActionLink("Product Comments", "ProductComments", new {id=Model.ID}, new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId= "divComments",
InsertionMode = InsertionMode.InsertAfter
})
<fieldset>
<div id="divComments">
<legend>Comments</legend>
</div>
</fieldset>
I was passing the ID in the wrong manner. I hope that this would at least help somebody else.
I have a ViewModel which contains a List of my Model, like so:
public class OrderConfirm
{
public ICollection<DayBookQuoteLines> SalesLines { get; set; }
public ICollection<DayBookQuoteLines> LostLines { get; set; }
public string Currency { get; set; }
}
I then use this ViewModel in my View like so:
#model btn_intranet.Areas.DayBook.Models.ViewModels.OrderConfirm
#{
ViewBag.Title = "Daybook - Order Confirmation";
}
<h6>Sales Lines</h6>
<div id="SalesOrders">
#using (Ajax.BeginForm("ConfirmSalesOrder", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "SalesOrders",
OnBegin = "SalesOrderConfirm"
}))
{
#foreach(var item in Model.SalesLines)
{
<p>#item.ItemName</p>
<p>#item.Qty</p>
#* Other Properties *#
}
<input type="submit" value="Submit Sales Order" />
}
</div>
<h6>Lost Lines</h6>
<div id="LostOrders">
#using (Ajax.BeginForm("ConfirmLostOrder", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "LostOrders",
OnBegin = "LostOrderConfirm"
}))
{
#foreach(var item in Model.SalesLines)
{
<p>#item.ItemName</p>
<p>#item.Qty</p>
#* Other Properties *#
}
<input type="submit" value="Submit Lost Order" />
}
</div>
The problem is, in my [HttpPost] actions, both ConfirmSalesOrder and ConfirmLostOrder. The value of my Model passed as a parameter is null:
[HttpPost]
public ActionResult ConfirmSalesOrder(List<DayBookQuoteLines> quoteLines)
{
// Process order...
return PartialView("Sales/_ConfirmSalesOrder");
}
so quoteLines is null. How can I bind the form to my model?
You don't have any input field in your form that will send the values to the server. You are only displaying them. That's why they are null when you submit the form => nothing is sent to the server.
But if inside this form the user is not supposed to modify any of the values all you need to do is to pass an id to the controller action that will allow you to fetch the model from the exact same location from which you fetched it in your GET action that rendered this form.
In this case your action will look like this:
[HttpPost]
public ActionResult ConfirmSalesOrder(int id)
{
List<DayBookQuoteLines> quoteLines = ... fetch them the same way as in your GET action
// Process order...
return PartialView("Sales/_ConfirmSalesOrder");
}
If on the other hand the user is supposed to modify the values in the form you need to provide him with the necessary input fields: things like textboxes, checkboxes, radio buttons, dropdownlists, textereas, ... And in order to generate proper names for those input fields I would recommend you using editor templates instead of writing foreach loops in your views.
UPDATE:
Seems like the user is not supposed to edit the data so there are no corresponding input fields. In this case in order to preserve the model you could during the AJAX request you could replace the Ajax.BeginForm with a normal Html.BeginForm an then manually wire up the AJAX request with jQuery. The advantage of this approach is that now you have far more control and you could for example send the entire model as a JSON request. To do this you could store the model as a javascript encoded variable inside the view:
<script type="text/javascript">
var model = #Html.Raw(Json.Encode(Model));
</script>
and then AJAXify the form:
$('#formId').submit(function() {
$.ajax({
url: this.action,
type: this.method,
contentType: 'application/json',
data: JSON.stringify({ quoteLines: model }),
success: function(result) {
$('#someTargetIdToUpdate').html(result);
}
});
return false;
});
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;
}