This question already has answers here:
MVC 3 - Html.EditorFor seems to cache old values after $.ajax call
(5 answers)
Closed 6 years ago.
I have a ASP MVC web app.
I have a partial form and it initally displays 'Hello Andy!'.
I press the submit button and I change this to 'Hello Andy Again!.
I pass the model back to the UI.
The label still shows the old value.
Why?
My markup:
#using (Ajax.BeginForm("SaveAlertPreferences", "Users", new AjaxOptions
{
UpdateTargetId = "partialform",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
{
<div>
#Html.AntiForgeryToken()
<div class="section group">
<div class="col span_3_of_12">
#Html.LabelFor(model => model.myStub)
</div>
<div class="col span_9_of_12">
#Html.TextBoxFor(model => model.myStub)
</div>
</div>
<div class="section group">
<div class="col span_3_of_12">
</div>
<div class="col span_4_of_12">
<input type="submit" value="Press me" />
</div>
<div class="col span_5_of_12">
</div>
</div>
</div>
}
My Model:
public class ChangeAlertPreferencesModel
{
public string myStub { get; set; }
}
My Controller:
[AcceptVerbs("HEAD", "GET")]
public PartialViewResult _ChangeAlertPreferences()
{
Response.CacheControl = "no-cache";
ChangeAlertPreferencesModel m = new ChangeAlertPreferencesModel();
m.myStub = "Hello Andy!";
return PartialView("_ChangeAlertPreferences", m);
}
[HttpPost]
public PartialViewResult SaveAlertPreferences(ChangeAlertPreferencesModel m)
{
Response.CacheControl = "no-cache";
if (ModelState.IsValid)
{
m.myStub = "Hello Andy Again!";
return PartialView("_ChangeAlertPreferences", m);
}
else
{
m.myStub = "I have errored!";
return PartialView("_ChangeAlertPreferences", m);
}
return null;
}
To complete my comment, your form statement looks odd,so you might wanna try this:
#using (Ajax.BeginForm("SaveAlertPreferences", "Users", new AjaxOptions
{
UpdateTargetId = "partialform",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
}))
{
#Html.AntiForgeryToken()
<div class="section group">
<div class="col span_3_of_12">
#Html.LabelFor(model => model.myStub)
</div>
<div class="col span_9_of_12">
#Html.TextBoxFor(model => model.myStub)
</div>
</div>
<div class="section group">
<div class="col span_3_of_12">
</div>
<div class="col span_4_of_12">
<input type="submit" value="Press me" />
</div>
<div class="col span_5_of_12">
</div>
</div>
}
To explain, in the first line, the using part declares the form and how it should behave, then you end(close) that declaration and open the block that should contain the body of the form.
Related
first i create list of models in [HttpGet] action and return to view.
public ActionResult Setting()
{
var model = db.Settings.ToList();
return View(model);
}
them in view get list in view and show good.
but after edit the value of setting i want to pass list of object from view to controller don't work this.
#model List<TajerWebsite.Models.Setting>
<!-- Main content -->
<section class="content">
<div class="container-fluid">
<div class="row">
<!-- left column -->
<div class="col-md-6">
<!-- general form elements -->
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">تنظیمات</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
#using (Html.BeginForm("Setting","Admin", new { FormMethod.Post }))
{
#Html.AntiForgeryToken()
foreach (var item in Model)
{
<div class="card-body">
<div class="form-group">
#Html.HiddenFor(model => item.Id)
<label for="exampleInputPassword1">#item.Name</label>
#Html.EditorFor(model => item.Value, new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(model => item.Value, "", new { #class = "text-danger" })
</div>
</div>
}
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-primary">ذخیره</button>
</div>
}
</div>
</div>
</div>
</div>
</section>
and action is :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Setting(IEnumerable<Models.Setting> settings)
{
db.Entry(settings);
db.SaveChanges();
return View(settings);
}
but settings is null!
You can't use #foreach loop in the view in order to pass list of object back to the controller, because that would generate input elements with same IDs and Names.
Instead, use standard for loop:
for(int i = 0; i < Model.Count; i++)
{
<div class="card-body">
<div class="form-group">
#Html.HiddenFor(m => m[i].Id)
<label for="exampleInputPassword1">#Model[i].Name</label>
#Html.EditorFor(m => m[i].Value,
new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(m => m[i].Value,
new { #class = "text-danger" })
</div>
</div>
}
Layout -> View -> Partial View
In the View:
<div class="col-md-8">
#{Html.RenderPartial("_komentari", commentlist);}
<div class="gap gap-small"></div>
<div class="box bg-gray">
<h3>#Res.commentwrite_title</h3>
#using (Ajax.BeginForm("postcomment", new { propertyid = Model.PublicID }, new AjaxOptions { UpdateTargetId = "commentsarea", HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, null))
{
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>#Res.commentwrite_content</label>
<textarea id="comment" name="comment" class="form-control" rows="6"></textarea>
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value='#Res.commentwrite_btn' />
</div>
</div>
</div>
}
</div>
</div>
In the Partial View:
<div id="commentsarea">
<ul class="booking-item-reviews list">
#if (Model != null)
{
foreach (Comment item in Model)
{
<li>
<div class="row">
<div class="col-md-2">
<div class="booking-item-review-person">
<a class="booking-item-review-person-avatar round" href="#">
<img src="/assets/img/70x70.png" alt="Image Alternative text" title="Bubbles" />
</a>
<p class="booking-item-review-person-name">
#if (item.UserId != null)
{
<a href='#Url.Action("details", "user", new { userid = item.User.PublicId })'>#item.User.Username</a>
}
else
{
Anonymous
}
</p>
</div>
</div>
<div class="col-md-10">
<div class="booking-item-review-content">
<p>
#item.Content
</p>
<p class="text-small mt20">#item.DateOnMarket</p>
<p class="booking-item-review-rate">
#using (Ajax.BeginForm("reportcomment", new { comment = item.PublicId }, new AjaxOptions { UpdateTargetId = "reportscount", HttpMethod = "Post", InsertionMode = InsertionMode.Replace }, null))
{
<a id="submit_link" href="#">Spam?</a>
<a class="fa fa-thumbs-o-down box-icon-inline round" href="#"></a>
}
<b id="reportscount" class="text-color">#item.CommentReports.Count</b>
</p>
</div>
</div>
</div>
</li>
}
}
</ul>
</div>
<script>
$(function () {
$('a#submit_link').click(function () {
$(this).closest("form").submit();
});
});
</script>
View
Both scripts for Ajax are always included in the Layout (I'm already using Ajax on other pages too). On the View page, when I add a new comment, it is added in the database and shows the updated list of comments via ajax. Everything works fine.
Partial View
But if I want to report the comment as spam, I have to click on the link inside the Partial View (#submit_link), and after reporting, inside the #reportscount part, I want to show the updated number of reports of that comment. The actionresults returns that number like Content(numberofreports.toString()). It works but I get the number in a blank page?
Thank you very much.
It's better if you don't. The main issue is that, for security reasons, <script> tags are ignored, when HTML is inserted into the DOM. Since the Ajax.* family of helpers work by inserting <script> tags in place, when you return the partial via AJAX, those will not be present. It's better if you only include the HTML contents of the form in the partial, and not the form itself.
I have this code
[HttpGet]
public ActionResult DeleteKamion(int id)
{
using (TruckCompanyEntities1 databaseKamion2 = new TruckCompanyEntities1())
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Kamioni KamionDelete = databaseKamion2.Kamionis.Find(id);
if (KamionDelete == null)
{
return HttpNotFound();
}
return View();
}
}
[HttpPost, ActionName("DeleteKamion")]
public ActionResult DeleteKamionConfirmed(int id)
{
using (TruckCompanyEntities1 databaseKamion10 = new TruckCompanyEntities1())
{
Kamioni SoferDeleteConfirmed = databaseKamion10.Kamionis.Find(id);
databaseKamion10.Kamionis.Remove(SoferDeleteConfirmed);
databaseKamion10.SaveChanges();
return RedirectToAction("DisplayUserDetailsKamion");
}
}
and this HTML
#model DarkoPage3.Models.Kamioni
#{
ViewBag.Title = "DeleteKamion";
Layout = "/Views/TruckCompanyLayout.cshtml";
}
<div class="page-content-wrapper">
<div class="page-content">
<div class="row">
<div class="col-md-6">
<div class="portlet-body form container" style="background-color:white;">
<h2>Избриши Камион</h2>
<div class="form-body ">
<div class="form-group">
<div class="col-md-9" style="color:black;">
Марка :
#Html.DisplayFor(model => model.MarkaID)
</div>
</div>
<div class="form-group">
<div class="col-md-9">
Модел :
#Html.DisplayFor(model => model.Model)
</div>
</div>
<div class="form-group">
<div class="col-md-9">
Година :
#Html.DisplayFor(model => model.Godina)
</div>
</div>
<div class="form-group">
<div class="col-md-9">
Поминати КМ :
#Html.DisplayFor(model => model.PominatiKM)
</div>
</div>
<div class="form-group">
<div class="col-md-9">
Шофер :
#Html.DisplayFor(model => model.SoferID)
</div>
</div>
<div class="form-group">
<div class="col-md-9">
Дата :
#Html.DisplayFor(model => model.Date)
</div>
</div>
</div>
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" onclick="DeleteConfirmed" class="btn btn-success" /> |
#Html.ActionLink("Назад", "DisplayUserDetailsKamion")
</div>
}
</div>
</div>
</div>
</div>
The problem is that when i press the DELETE view is not displaying the values of the model but when i press the delete button is deleting, but i want to displaying the information as well, please help thanks.
This is becaues you are returning the view emtpy.. the view is expecting a model. The data is fetched but not returned.
[HttpGet]
public ActionResult DeleteKamion(int id)
{
using (TruckCompanyEntities1 databaseKamion2 = new TruckCompanyEntities1())
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Kamioni KamionDelete = databaseKamion2.Kamionis.Find(id);
if (KamionDelete == null)
{
return HttpNotFound();
}
return View(KamionDelete);
}
}
I am using ajax.beginform to make an ajax login popup.
Everything works fine the first time, but when I submit a second time (after an error message from model validation) it no longer updates my div with the content but refreshes the page and shows the partial view in a blank page. It's not doing the ajax anymore.
I have included all javascripts needed.
My partial view:
#using (Ajax.BeginForm("Login", "Account", null, new AjaxOptions
{
UpdateTargetId = "login-partial-update",
HttpMethod = "POST",
OnSuccess = "loginSuccess"
}, new { id = "js-form-login" }))
{
<div class="fluid-row-margin">
<div class="cell12">
#Html.TextBoxFor(x => x.Email, new { placeholder = "Email address" })
<div class="errormessage">
#Html.ValidationMessageFor(x => x.Email)
</div>
</div>
</div>
<div class="fluid-row-margin">
<div class="cell12">
#Html.PasswordFor(x => x.Password, new { placeholder = "Password" })
<div class="cell12 errormessage">
#Html.ValidationMessageFor(x => x.Password)
</div>
</div>
</div>
<div class="fluid-row-margin">
<div class="cell1">
#Html.CheckBoxFor(x=>x.RememberMe)
</div>
<div class="cell11">Remember me</div>
</div>
<div class=" errormessage">
#if (Model.HasErrors)
{
<br />#Model.ErrorMessages
}
</div>
}
<script type="text/javascript">
$.validator.unobtrusive.parse("#js-form-login");
</script>
My parent view includes this partial
<div id="login-partial-update">
#Html.Partial("Widgets/Login/_LoginInput", new LoginInputModel())
</div>
All this is happening inside a javascript modal dialog
Whenever i run this code i have a problem passing the result from the controller to view from httppost method. The server side code is fine its just that when i assign a new result in the calculator.Result property i never see that newly assign value in the textbox in the view.The rest of the properties are populated with appropriate values.
Could anyone please help me how can i fix this? or what i am missing?
Thank you
Here is my code from .cshtml
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.FirstNumber)
</div>
<div class="span2">
#Html.TextBoxFor(x => x.FirstNumber)
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.FirstNumber)
</div>
</div>
<br />
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.SecondNumber)
</div>
<div class="span2">
#Html.TextBoxFor(x => x.SecondNumber)
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.SecondNumber)
</div>
</div>
<br />
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.SelectedFunction)
</div>
<div class="span2">
#Html.DropDownListFor(x => x.SelectedFunction, Model.Functions, "Please Make a Selection")
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.SelectedFunction)
</div>
</div>
<br/>
<div class="row">
<div class="span2">
#Html.Label("Result: ")
</div>
<div class="span2">
#Html.TextBoxFor(x => x.Result)
</div>
</div>
<br />
<div class="row">
<input type="submit" value="Load" />
</div>
}
Here is my code behind from the controller
[HttpPost]
public ActionResult Index(CalculatorViewModels calculator)
{
//If the entries are valid
if (ModelState.IsValid)
{
try
{
double firstNum = calculator.FirstNumber;
double secondNum = calculator.SecondNumber;
string selectedFunction = calculator.SelectedFunction;
double result = -1;
if (selectedFunction.Equals("1"))
{
result = service.CombinedWith(firstNum, secondNum);
}
else if (selectedFunction.Equals("2"))
{
result = service.Either(firstNum, secondNum);
}
calculator.Result = Convert.ToString(result);
return View(calculator);
}
catch(Exception ex)
{
calculator.Result = "Error in calculating probability "+ex.Message;
return View(calculator);
}
}
//entries are not valid
else
{
return View(calculator);
}
}
here is my view model
public class CalculatorViewModels
{
[Required(ErrorMessage = "Please enter a Number between zero and one")]
[Display(Name = "FirstNumber")]
[Range(0, 1)]
public double FirstNumber { get; set; }
[Required(ErrorMessage = "Please enter a Number between zero and one")]
[Display(Name = "Second Number")]
[Range(0, 1)]
public double SecondNumber { get; set; }
[Required(ErrorMessage = "Please Select at least one function")]
[Display(Name="Please Select a Function")]
public string SelectedFunction { get; set; }
//will be used to report exception as well if needed
public string Result { get; set; }
public List<SelectListItem> Functions
{
get
{
return new List<SelectListItem>()
{
new SelectListItem{ Text="CombinedWith",Value="0"},
new SelectListItem{Text="Either",Value="1"}
};
}
}
}
At the top of your view, dump out the contents of your model just for a sanity check. Use HTML.Raw(..) or something and then view the page source to check the result is actually being set.
Something like
#{
var model = #Html.Raw(Json.Encode(Model));
}
Use JavaScript to write out the model to the console or something.
Let me know how you get on and if the result is getting set.
Try this approach...
1) Update your view to add a click handler for the submit button and handle it in javascript
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.FirstNumber)
</div>
<div class="span2">
#Html.TextBoxFor(x => x.FirstNumber)
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.FirstNumber)
</div>
</div>
<br />
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.SecondNumber)
</div>
<div class="span2">
#Html.TextBoxFor(x => x.SecondNumber)
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.SecondNumber)
</div>
</div>
<br />
<div class="row">
<div class="span2">
#Html.LabelFor(x => x.SelectedFunction)
</div>
<div class="span2">
#Html.DropDownListFor(x => x.SelectedFunction, Model.Functions, "Please Make a Selection")
</div>
<div class="field-validation-error">
#Html.ValidationMessageFor(x => x.SelectedFunction)
</div>
</div>
<br/>
<div class="row">
<div class="span2">
#Html.Label("Result: ")
</div>
<div class="span2">
#Html.TextBoxFor(x => x.Result)
</div>
</div>
<br />
<div class="row">
<input type="button" value="Load" id="btnSubmit" onclick="submitForm();"/>
</div>
}
<script src="~/Scripts/jquery-2.1.3.js"></script>
<script type="text/javascript">
var url = '#Url.Action("Index")';
function submitForm() {
var data = {};
data.FirstNumber = $('#FirstNumber').val();
data.SecondNumber = $('#SecondNumber').val();
data.SelectedFunction = $('#SelectedFunction').val();
$.post(url, data).done(function (result) {
$('#Result').val(result);
});
}
</script>
Modify the controller to return Json data
using Newtonsoft.Json;
..
..
[HttpPost]
public ActionResult Index(CalculatorViewModels calculator)
{
//If the entries are valid
if (ModelState.IsValid)
{
try
{
double firstNum = calculator.FirstNumber;
double secondNum = calculator.SecondNumber;
string selectedFunction = calculator.SelectedFunction;
double result = -1;
if (selectedFunction.Equals("1"))
{
result = service.CombinedWith(firstNum, secondNum);
}
else if (selectedFunction.Equals("2"))
{
result = service.Either(firstNum, secondNum);
}
calculator.Result = Convert.ToString(result);
return Json(result);
}
catch (Exception ex)
{
calculator.Result = "Error in calculating probability " + ex.Message;
return Json(0);
}
}
//entries are not valid
else
{
return Json(0);
}
}
Do not forget to add jQuery library to scripts folder and add a reference to Newtonsoft.Json. Hope this helps.