How to save the current model when ajax is requesting? - asp.net

I'm using Ajax in my application to update a view without refresh the webpage.
Can you notice here http://contoso2.azurewebsites.net/Test/DoTest because I'm highlighting the partial view in yellow color.
But the problem is, when I enter data to the items (math problem), when Ajax is requesting, I don't see the changes in the model.
public ActionResult DoTest()
{
List<Worksheet> worksheets = null;
if (Request.IsAjaxRequest())
{
worksheets = Session["Worksheets"] as List<Worksheet>;
return PartialView("_Problems", worksheets[1]);
}
worksheets = new List<Worksheet>()
{
new Worksheet("Addition and Subtraction of absolute values", new List<Problem1>() { ... }),
new Worksheet("Addition and Subtraction of absolute values", new List<Problem1>() { ... })
}
Session["Worksheets"] = worksheets;
return View(worksheets[0]);
}
I'm using a Session to recover my model, but if I debug in it I don't see any changes of the models. How can I do for when I press continue button, my model updates.
EDIT: This contain my AJAX in razor view
#using (Ajax.BeginForm(
new AjaxOptions
{
HttpMethod = "get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "problemList"
}))
{
<input type="submit" value="Continue" />
}

I usually have two Actions for a View . Though this is not a mandatory requirement.
The first action decorated with HttpGet renders the page on a Get when the user comes to the page for the first time. the second action is invoked when the user clicks next and posts a form.
public class TestController {
[HttpGet]
public void DoTest(){
var viewModel = new List<Worksheet>()
{
new Worksheet("Addition and Subtraction of absolute values", new List<Problem1>() { ... }),
new Worksheet("Addition and Subtraction of absolute values", new List<Problem1>() { ... })
};
return View(viewModel);
}
[HttpPost]
public void DoTest(List<Worksheet> worksheets){
//do whatever you want with the user response
var response = worksheets[1];
PartialView("_Problems",responseModel);
}
}
Note : you will have to invoke the ajax call with HttpMethod = "post". The ModelBinder in ASP.NET will bind the values posted in the request to your responseModel worksheets
You should try and go over the "getting-started-with-aspnet-mvc4" tutorials available on http://asp.net/

Related

asp.net mvc add partial view dynamically using ajax

I am new to ASP.NET and I have a problem to add a content to my main view. In HtmlBeginform I upload the file on a button click and after file loading I need to display partial view under my main view I donĀ“t know how to call ajax script properly.
My main view:
#using prvniAplikace.Models;
#using Chart.Mvc.ComplexChart;
#using Chart.Mvc.Extensions;
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("LoadFile", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<div class="form-group" align="left">
<label for="exampleInputFile">Load File</label>
<input type="file" accept=".tcx" class="form-control-file" name="exampleInputFile" id="exampleInputFile" aria-describedby="fileHelp">
</div>
<div class="form-group" align="left">
<button class="btn btn-primary" type="submit" id="add" name="add" value="Add">Display</button>
</div>
}
#section Scripts {
<script type="text/javascript">
$("#add").on('click', function () {
$.ajax({
async: false,
url: '/Home/getContent'
}).success(function (partialView) {
$('#getContent').append(partialView);
});
});
</script>
}
View I want to add to a main view:
#{
ViewBag.Title = "getContent";
Layout = null;
}
<h2>Obsah</h2>
<p>Odstavec</p>
<p>#DateTime.Now.ToString()</p>
Controller:
namespace prvniAplikace.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
public ActionResult getContent()
{
return PartialView("~/Views/Home/AjaxRequest.cshtml");
}
[HttpPost]
public ActionResult LoadFile(HttpPostedFileBase exampleInputFile)
{
if (exampleInputFile.ContentLength > 0)
{
var fileName = Path.GetFileName(exampleInputFile.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
exampleInputFile.SaveAs(path);
string xmlFile = Server.MapPath(fileName);
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList nodes = doc.GetElementsByTagName("HeartRateBpm");
XmlNodeList nodes2 = doc.GetElementsByTagName("Time");
}
return RedirectToAction("Index");
}
}
}
As per your comment, you would like to load the partial view content via ajax after the index view is (re)loaded after the normal form submit you do to upload the file. To achieve this, you should make the ajax call in the document ready event. Since it is the same page/view user will see before and after the form submit, you should conditionally make the ajax call based on whether the page is loaded for your first GET request or for the GET request issued by the Redirect call in your http post action.
Since Http is stateless, there is no way for the GET action method to know whether this was called from the Redirect method call after successfully processing the submitted form (in your http post action). You may use TempData to address this problem. Before redirecting to the Index view, set a flag to the temp data dictionary which will be available in the next GET request.
[HttpPost]
public ActionResult LoadFile(HttpPostedFileBase exampleInputFile)
{
// your existing code here
TempData["Success"] = true;
return RedirectToAction("Index");
}
Now in your GET action, read this and pass it to view via ViewBag (or a view model property if you have one)
public ActionResult Index()
{
ViewBag.IsSuccess = TempData["Success"];
return View();
}
Now in the view, check this ViewBag item and if it exist and has true value, render the div in which we want to show the partial view content. You can take advantage of the the Url.Action helper method to generate the correct relative path to the action method which returns partial view and keep that in html5 data attribute in the div tag so we can use that in javascript later to make the ajax call.
So add this to your index view.
#if (ViewBag.IsSuccess!=null && ViewBag.IsSuccess)
{
<div data-url="#Url.Action("getContent", "Home")" id="myPartial"> </div>
}
Now all you need is the javascript code which makes the ajax call. Execute that in the document ready event. You can use the jQuery load method.
$(function(){
// Get the url from the data attribute of the div
var url = $("#myPartial").data("url");
// Make the ajax call using load method
$("#myPartial").load(url);
});

MVC - Update model in view after ajax form submit

I have a question concerning MVC4. I have a form that I submit through ajax to my controller. In the controller, I create a new entry in a database, using the data of the form.
In case of success, the form fields need to go empty and a message should appear that the record has been added. So that the user is ready to add the next item through the form. I can clear the fields in the "ResetView" method through javascript (that's called through "OnSuccess"), that's not a problem
In case of error, the form fields need to remain filled in and a message should appear that it failed. In my case, it calls also the "OnFailure" method "ShowError" (which just shows the div "CustomerMessage").
The issue I am having when an item fails, is that the "CustomMessage" from my model is empty, while I did explicitly set it in my controller. So in my view, the #Model.CustomMessage is always empty!
I read that I should call the "ModelState.Clear()" function in my controller but that doesn't seem to do anything.
Can someone check what could be wrong in my code?
Any help is greatly appreciated.
View:
<div id="createform">
#using (Ajax.BeginForm("Create", "Payment", new { username = User.Identity.Name }, new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "createform",
//OnBegin = "SubmitForm",
OnSuccess = "ResetView",
OnFailure = "ShowError"
}))
{
<div id="CustomMessage">#Model.CustomMessage</div>
... bunch of #Html.TextBoxFor stuff (like below) ...
#Html.TextBoxFor(model => model.SenderName, new { id = "SenderName"})
}
</div>
Controller:
[HttpPost]
public ActionResult Create(PaymentViewModel payment, string username)
{
if (ModelState.IsValid)
{
try
{
paymentRepository.AddPayment(payment.PaymentLine, username);
paymentRepository.SaveChanges();
payment.CustomMessage = "success";
}
catch (Exception ex)
{
payment.CustomMessage = "error";
}
}
else
{
payment.CustomMessage = "error";
}
ModelState.Clear();
return PartialView(payment);
}
I found the problem. It seemed that I was missing a reference to the jquery unobtrusive ajax script. After adding that, everything worked correctly
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

Asp.net MVC4 Dropwdownlist Retain Selected Value after Get

I have a drop down list that is included in the _layout view of my application.
What i am trying to do is populate the list with Data from a sql server and then based on the value selected redirect the user to another view.
All is working fine except that when the user click Enter/Search the value of dropdownlist gets defaulted to the first value. As i am currently transitioning from Web Forms it's quite difficult and frustrating.
Here is the code for my Model
public class DomainNameViewModel
{
private static readonly string ConStr = WebConfigurationManager.ConnectionStrings["App"].ConnectionString.ToString();
public string SelectedDomainId { get; set; }
public IEnumerable<SelectListItem> domains
{
get
{
List<SelectListItem> l = new List<SelectListItem>();
using (SqlConnection con = new SqlConnection(ConStr))
{
SqlCommand com = new SqlCommand("spDomainList", con);
con.Open();
SqlDataReader sdr = com.ExecuteReader();
while (sdr.Read())
{
l.Add(new SelectListItem() { Text = sdr[0].ToString(), Value = sdr[1].ToString() });
}
return l;
}
}
The Code for controller.
[ChildActionOnly]
public ActionResult Index()
{
return PartialView(new DomainNameViewModel());
}
The DomainName View
#model app.Models.DomainNameViewModel
#{
Layout = null;
}
#Html.DropDownListFor(x => x.SelectedDomainId, Model.domains, new { #id = "e1",#class = "bannerlist" })
And the code for _Layout view
#using (Html.BeginForm("Search","DomainSearch",FormMethod.Get))
{
#Html.TextBox("txtDomain", null, new { #class = "bannertextbox" , placeholder="Search for a Perfect Domain!" })
#Html.Action("index","DomainName")
<input type="submit" class="bannerbutton" value="Search" />
}
Any help would be appreciated.
EDIT: Added the DomainSearchController code.
public class DomainSearchController : Controller
{
//
// GET: /DomainSearch/
public ActionResult Search(string txtDomain,string SelectedDomainId)
{
DomainNameViewModel Domain = new DomainNameViewModel();
Domain.SelectedDomainId = SelectedDomainId;
string check = Domain.ParseDomain(HttpUtility.HtmlEncode(txtDomain), HttpUtility.HtmlEncode(SelectedDomainId));
string s = Domain.CheckDomains(check);
ViewBag.Domain = Domain.DomainCheckResult(s);
return View();
}
}
You haven't quite shown/explained how exactly are you performing the redirect. But you will need to either pass the selected value in the query string to the target page or store in in a cookie or somewhere on the server like in the ASP.NET Session (beurk).
The reason you need to do this is because in ASP.NET MVC, contrary to classic WebForms there's no ViewState and you cannot retrieve the selected value on subsequent PostBack (there's neither such notion as PostBack in ASP.NET MVC).
Then in your child controller action you will need to retrieve the selected value from the query string or from the cookie or from the ASP.NET session (beurk) and set the SelectedDomainId property on your view model to this value.
For example:
[ChildActionOnly]
public ActionResult Index()
{
var model = new DomainNameViewModel();
// here you need to set the SelectedDomainId property on your view model
// to which the dropdown is bound to the selected value
model.SelectedDomainId = Request["domain_id"];
return PartialView(model);
}
Assuming you decide to pass this value as query string parameter when redirecting you will need to keep this parameter on subsequent redirects in order to keep the state.

Updating View with Model changes via Ajax Post - MVC3

I am trying to use an Ajax (I think) call to update my model value and then have that new value reflected in the view. I am just using this for testing purposes for the moment.
Here's the overview:
MODEL
public class MyModel
{
public int Integer { get; set; }
public string Str { get; set; }
}
CONTROLLER
public ActionResult Index()
{
var m = new MyModel();
return View("Test1", m);
}
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
return View("Test1", m);
}
VIEW
#model Test_Telerik_MVC.Models.MyModel
#using Test_Telerik_MVC.Models
#{
ViewBag.Title = "Test1";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Test1</h2>
#if (false)
{
<script src="~/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery-ui.min.js" type="text/javascript"></script>
}
<h2>
ViewPage1
</h2>
<div>
<input type="button" onclick="changeButtonClicked()" id="changeButton" value="Click Me!" />
<input type="text" value="#Model.Str" class="txt" id="str" name="Str"/>
<div></div>
</div>
<script type="text/javascript">
function changeButtonClicked() {
var url = '#Url.Action("ChangeTheValue", "Test1")';
var data = '#Model';
$.post(url, data, function (view) {
$("#Str").value = '#Model.Str';
});
}
</script>
Basically the view renders a button with a textbox. My sole aim is to simply display the value of my model (Str property) in the textbox.
I have tried various combinations of the changeButtonClicked() function to no avail. Test1 is the name of my controller. What I don't understand is when I debug it, the controller action fires and sets my values correctly. If I place a breakpoint on the "#Model.Str" section of the input tag, it shows me that my #Model.Str is equal to Changed! which is correct. However, as soon as my success function fires in the javascript, the value reverts back to it's original value.
I can make it work by changing the input type to submit and wrapping it in a #Html.BeginForm() section but I am wondering if/how to do it like this? Or is a Submit the only way to accomplish it?
Thanks
First thing in the jQuery the proper way to set a value of an input is to use:
$("#Str").val(#Model.Str);
Next we'll look at the controller. In the POST action result you are returning the entire View in your AJAX call. That means all the HTML, script references, and JavaScript are being returned in your jQuery post request. Since all you are trying to update is the value of the input named Str, I would just return that value as JSON and nothing else.
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
return Json(m.Str);
}
Next I would place your HTML inputs in a <form> so you can have jQuery serialize your model for you and then you can change your jQuery post code to be:
function changeButtonClicked() {
var url = '#Url.Action("ChangeTheValue", "Test1")';
$.post(url, $('form').serialize(), function (view) {
$("#Str").val(view);
});
}
All the serialization is doing is encoding the inputs in your form into a string and if everything is named properly ASP.NET will bind that back to your model.
If you need to have your route handle both AJAX calls and full requests you could use ASP.NET's IsAjaxRequest function to test the request and return different results depending on if the request is AJAX or not. You would do something like this in your controller:
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
if (Request.IsAjaxRequest) {
return Json(m.Str);
}
else {
return View("Test1", m);
}
}
In the ActionResult above you are doing everything you did before, but now are testing the request type and if it's AJAX you return a JSON result of your string value. If the request was not from an AJAX call then the full View (HTML, scripts, etc) are returned to be displayed in the browser.
I hope this is helps you out and is what you were looking for.
You can update the view, just not the model. The model in a razor page is compiled on the server in order to render the view; you would need to recompile the razor page after every ajax request.
Only real option is to return json from server and manually update DOM/View.

Message Control in Masterpage with ASP.NET MVC

Hey everyone. Got a custom on how to do this as im new to MVC and trying to get a couple of small things implemented. This is the way I did it in WebForms but want to transition it to MVC.
I have a user control that contains CSS which will render a message. This control is located in the MasterPage and called from a ASPX page like this:
Pseudo code:
try{
Msg.MessageMode = WebPageMessageMode.OK;
Msg.ShowOK("Report deleted.");
}
catch
{
Msg.MessageMode = WebPageMessageMode.ErrorMessage;
Msg.ShowError("There was a problem deleting the report.");
}
Masterpage.aspx
<cc1:WebPageMessage runat="server" ID="msg" />
I currently have the control in the MasterPage and now im a bit confused about proceeding from here.
Should I put the 'Msg' object above from the pseudo code to a View from the MasterPage?
What is the proper way to do something like?
I dont think there is a one-solution-fits-all here.
Anyway this is my solution that uses jQuery:
1) Create a MyResultModel class to handle a message to the user
public enum MyResultType { Info, Error }
public class MyResultModel
{
public MyResultModel( MyResultType type, string message ) {
switch ( type ) {
case MyResultType.Info: Title = "OK"; break;
case MyResultType.Error: Title = "Error!!!"; break;
}
Message = message;
}
public String Title { get; set; }
public String Message { get; set; }
}
2) Create a Partial View named MyResult in the Shared Folder to handle the model
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyResultModel>" %>
<div id="resultTitle"><%: Model.Title %></div>
<div id="resultMessage"><%: Model.Message %></div>
3) Create and use a BaseController for your controllers and add the following method to it. The method simply add a custom Http Header to the response
protected PartialViewResult PartialView( string viewName, object model, string resultHeader ) {
Response.AppendHeader( "MyHttpCustomHeader", resultHeader );
return base.PartialView( viewName, model );
}
4) In your action return a MyResultView when you've done
[HttpPost]
public virtual ActionResult DoSomething() {
try {
//Do Something
return PartialView( "MyResult",
new MyResultModel( MyResultType.Info, "Operation Completed" ),
"HttpResultInfo" );
}
catch ( Exception ex ) {
return PartialView( "MyResult",
new MyResultModel( MyResultType.Error, ex.Message ),
"HttpResultError" );
}
}
5) Finally, Submit the form using jquery and handle the results.
$.ajax({
type: "post",
dataType: "html",
url: "your/url/here",
data: $("#myform").serialize(),
success: function (response, status, xml) {
var resultType = xml.getResponseHeader("MyHttpCustomHeader");
if (resultType == null) {
//No message do whatever you need
}
else {
//response contain your HTML partial view here. Choose your
//desidered way to display it
}
}
});
With a scenario like this you dont need to place a control on the master page. You can:
Show the view as it comes from the action without any modification
Use some fancy message display technique as StackOverflow does with the orange sliding message (in this case simply extract the title and the message from the returned html)
Use some fancy jquery plugin as jGrowl to show your message
If you want to check wether it is an Info/Error message simply check the custom header with jQuery in the else branch
var title = $(response).filter("#resultTitle").text();
var message = $(response).filter("#resultMessage").text();
if (resultType == "HttpResultInfo") {
showInfoMessage(title, message);
}
else if (resultType == "HttpResultError") {
showErrorMessage(title, message);
}
Hope it helps!
In a controller, as part of the action, you can set a message like this:
public ActionResult MyAction()
{
// Do some stuff
TempData["message"] = "This is a message.";
return View("MyView");
}
In your master page or in your view:
<%
string text = TempData["Message"] as string;
Response.Write(text);
%>

Resources