I have a view model which is just
public class Visits
{
public List<Visit> visits { get; set; }
}
In my visit model I have a
public bool ValidVisit { get; set; }
I am able to pass everything to my view ok and render all of the visits on the view. The view looks like
#model TheWallSite.ObjectModels.Visits
#{
ViewBag.Title = "Potential invalid visits!";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
<fieldset>
<table>
<tr><th>Check In/Out Time</th><th>Visit Type</th><th>In/Out</th><th>IP</th><th>SSO ID</th><th>Valid Visit</th></tr>
#foreach (var item in Model.visits)
{
<tr>
<td>#Html.DisplayFor(model => item.InOutTime)</td>
<td>#Html.DisplayFor(model => item.VisitType)</td>
<td>#Html.DisplayFor(model => item.VisitName)</td>
<td>#Html.DisplayFor(model => item.IP)</td>
<td>#Html.DisplayFor(model => item.SSO)</td>
<td>#Html.EditorFor(model => item.ValidVisit)</td>
</tr>
}
</table>
<input type="submit" value="Submit" />
</fieldset>
}
The problem I am having is I want the end user to be able to check/uncheck the ValidVisit and then pass these back to the controller and make the correct changes in my database.. I am having a heck of a time figuring out how to do this. Any suggestions? My [HttpPost] controller signature is
public ActionResult ListQuestionableVisits(Visits model, FormCollection forms)
but nothing seems to be getting back to the controller.
It would be the model-binding not kicking in, probably due to the loop.
I know i know, it should work, but do it the right way, and it has a better chance of working.
Try using editor templates instead.
/EditorTemplates/Visit.cshtml
#model TheWallSite.ObjectModels.Visit
<tr><td>#Html.DisplayFor(model => model.InOutTime)</td></tr>
<tr><td>#Html.DisplayFor(model => model.VisitType)</td></tr>
<tr><td>#Html.DisplayFor(model => model.VisitName)</td></tr>
<tr><td>#Html.DisplayFor(model => model.IP)</td></tr>
<tr><td>#Html.DisplayFor(model => model.SSO)</td></tr>
<tr><td>#Html.EditorFor(model => model.ValidVisit)</td></tr>
Main View:
#model TheWallSite.ObjectModels.Visits
#{
ViewBag.Title = "Potential invalid visits!";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
<fieldset>
<table>
<tr>
<th>Check In/Out Time</th>
<th>Visit Type</th>
<th>In/Out</th>
<th>IP</th>
<th>SSO ID</th>
<th>Valid Visit</th>
</tr>
#Html.EditorFor(model => model.Visits)
</table>
<input type="submit" value="Submit" />
</fieldset>
}
Also, if that's your complete view, you don't need the FormCollection parameter in the action, unless there is a hidden field/some other magic field i'm not seeing.
Related
I have a dropdownlist with different soccer Clubs from my database. When I select one, an ajax call will be made to show all the Games that Club will play in.
The problem is whenever I'm logged on as an AspNetUser I automatically get logged off the second I submit the dropdownlist.
When I'm not logged in everything works as it should.
I'm really confused why exactly this happens.
Controller
[Authorize]
public class WedstrijdController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
ploegService = new PloegService();
ViewBag.PloegId = new SelectList(ploegService.All(),
"Id", "Naam");
return View();
}
[AllowAnonymous]
public ActionResult IndexAjax(int? ploegId)
{
if (ploegId == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
wedstrijdService = new WedstrijdService();
var wedstrijden = wedstrijdService.WedstrijdenByPloeg(Convert.ToInt16(ploegId));
return PartialView("_SearchWedstrijdenPartial", wedstrijden);
}
}
Index.cshtml
#{
ViewBag.Title = "Lijst";
}
<h2>Wedstrijden</h2>
<div class="panel panel-default">
<div class="panel-heading">Kies een wedstrijd</div>
<div class="panel-body">
#using (Ajax.BeginForm("IndexAjax", "Wedstrijd",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
LoadingElementId = "ajax-loader",
UpdateTargetId = "searchresults",
}))
{
<div class="form-horizontal">
<div class="form-group">
#Html.Label("Ploeg", htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-10">
#Html.DropDownList("PloegId", null, "---Kies ploeg---", htmlAttributes: new { #class = "form-control" })
<img id="ajax-loader"
src="#Url.Content("~/content/Images/ajax-loader.gif")"
style="display: none" />
</div>
</div>
</div>
}
<div id="searchresults"></div>
</div>
</div>
#section scripts
{#Scripts.Render("~/bundles/jqueryUnobtrusive")
<script>
$("#PloegId").on("change",
function() {
$("form").trigger("submit");
});
</script>
}
_SearchWedstrijdenPartial.cshtml
#model IEnumerable<VoetbalMVC.Models.Wedstrijd>
<table class="table">
<tr>
<th>
Thuisploeg
</th>
<th>
Bezoekersploeg
</th>
<th>
#Html.DisplayNameFor(model => model.Stadion)
</th>
<th>
#Html.DisplayNameFor(model => model.Datum)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Ploeg1.Naam)
</td>
<td>
#Html.DisplayFor(modelItem => item.Ploeg.Naam)
</td>
<td>
#Html.DisplayFor(modelItem => item.Stadion.Naam)
</td>
<td>
#Html.DisplayFor(modelItem => item.Datum)
</td>
<td>
#Html.ActionLink("Order tickets", "Detail", new { wedstrijdId = item.Id })
</td>
</tr>
}
</table>
Indeed, by using the $("form") jQuery selector you are targeting all form elements on the page. You can verify the forms being submitted from the client to the server with tools like Fiddler, Postman, or the developer tools of your browser (by hitting F12 or CTRL+Shift+I on Windows/Linux, or Command+Option+I on Mac).
As far as the logout form is concerned, if you haven't customized the folder/file structure of your MVC project, it should be located in Views/Shared/_LoginPartial.cshtml:
#using Microsoft.AspNet.Identity
#if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
// ...
}
}
..so it is generating a form with an ID of #logoutForm, but since you are submitting all forms at once, you are subsequently logging out the user each time.
This means you need to modify the call to only submit the form you want. Assuming the ID of your form being AjaxForm, you would do:
$("#AjaxForm").trigger("submit");
This piece of code was causing the error
$("form").trigger("submit");
As you can see this includes all forms. I suspect this means the logout button is included in some sort of form which triggers this action when logged in. Simply add an Id to your AjaxForm and only trigger the submit of that AjaxForm.
I've been struggling with this for a while now. I'm constructing this view:
But when I hit the 'Update' button after do some changes the web refreshes to show the original values.
About the view: I get this view using an IEnumerable and looping thru each item in the model inside a form. Then, inside the form, there is a table that contains only 1 row. I do this in order to wrap all the items of the record in one form. This is part of code:
#foreach (var item in Model)
{
<form asp-action="Test" asp-route-id="#item.Id">
<table class="table">
<tbody>
<tr>
<td>
<input type="hidden" asp-for="#item.Id" />
<div class="form-group">
<div class="col-md-10">
<input asp-for="#item.MchName" readonly class="form-control" />
<span asp-validation-for="#item.MchName" class="text-danger"></span>
</div>
</div>
</td>
//more fields
<td>
<input type="submit" value="Update" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>}
I declare an asp-action and a asp-route-id:
<form asp-action="Test" asp-route-id="#item.Id">
Question: Is this good enough? Is there something missing?
This is the Get Method:
public async Task<IActionResult> Test()
{
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I'm not passing any argument to the controller, yet the view will list the items following the given structure using an IEnumerable. Should I pass anything to the Get Method or is it fine as it is?
This is the Post Method:
#model IEnumerable<Application.Models.Machine>
[HttpPost, ActionName("Test")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TestPost(int? id)
{
if (id == null)
{
return NotFound();
}
var machinetoUpdate = await _context.Machines
.SingleOrDefaultAsync(s => s.Id == id);
if (await TryUpdateModelAsync(
machinetoUpdate,
"",
s => s.MchName, s => s.StoreID, s => s.PUnit, s => s.Status))
{
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction("Test");
}
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I don't know if because the entity I retrieve the id from (and that I use to update the model thru TryUpdateModelAsync()) is also being used to compare to the model that thru the view this might not been working properly.
Thanks in advance for any help.
i have a MvcApplication for Store WebSite and i want when user go to Products and when click on Buy for each of product,go to a view that will reviews Buy List and make sure's user are accepted,then after user clicked on IAccept return to Index View with a Message
now my problem is this,i can't use passed product object in my View,error message is this:"#Model.name is null"
here is my Product,Buy ActionResult and Buy,Product View
public ActionResult Product()
{
var pmodel = db.posts.ToList();
product pro = new product()
qrcode = 2455174,
name = "hub",
color_id = 3,
category_id = 3,
price = 10,
maker_code = 1,
offer_id = 0
};
db.products.Add(pro);
db.SaveChanges();
if (pmodel != null)
{
return View(pmodel);
}
return View();
}
Product View:
#model IEnumerable<MvcApplication1.Models.post>
#{
ViewBag.Title = "Product";
Layout = "~/Views/Shared/_LayoutHome.cshtml";
}
<h3>Products</h3>
<html>
<head><title></title>
<script type="text/javascript">
function enlarge(el) {
if (el.width = 300)
{
el.width = 50;
el.height = 50;
}
el.width = 300;
el.height = 240;
}
</script>
</head>
<body>
<table>
<tr>
<td style="font-weight:bold">
Image:
</td>
<td style="font-weight:bold">
Name:
</td>
<td style="font-weight:bold">
Description:
</td>
</tr>
#foreach(var item in Model) {
<tr>
<td>
<img src="~/Resources/image_2.jpg") id="x"
width="50" height="50" onclick="enlarge(this)"
alt="Click To See Image Larger">
</td>
<td>
#Html.DisplayFor(modelItem => item.title)
</td>
<td>
#Html.DisplayFor(modelItem => item.text)
</td>
<td>
#using (Html.BeginForm()){
<p>
#Html.ActionLink("Buy Now!", "Buy")
</p>
}
</td>
</tr>
}
</table>
</body>
</html>
Buy ActionResult:
[HttpPost]
public ActionResult Buy(user users,product products,post p)
{
var prod = db.products.Single(pro => pro.qrcode == products.qrcode);
DateTime date = DateTime.Now;
factor fact = new factor() {description=p.text,factor_id=products.qrcode,count=1
,product_name=products.name,product_qrcode=products.qrcode,status=
"Buy with Balance fFunds",date=date.ToString()};
return View(prod);
}
[HttpGet]
public ActionResult Buy(product products)
{
return View(products);
}
And Here is Buy View:
#model MvcApplication1.Models.product
#{
ViewBag.Title = "Buy";
Layout = "~/Views/Shared/_LayoutHome.cshtml";
}
<h2>Review</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Are you sure to buy this stuff?</legend>
</fieldset>
<div class="display">
#Html.DisplayFor(model => model.name)
</div>
<div class="display">
#Html.DisplayFor(model => model.price)
</div>
<div class="display">
#Html.DisplayFor(model => model.qrcode)
</div>
<p>
<input type="submit" value="Accept" />
</p>
}
my problem summary is,when user go to products and see the products post's and try to buy something (by clicking on "Buy Now!" link)then will be Redirect to Buy View,then user must reviews and Accept stuff details then Redirect to Index with a Message from complete operation or something like that!!But it doesn't show stuff details.
I have taken over support of an MVC application, but unfortunately have pretty much zero experience or knowledge of MVC, so I apologise in advance if this is a stupid question.
We are placing every single result into a listed item in the HTML, then hiding all but one record, so you can filter through the different entries using First/Prev/Next/Last buttons, all via jQuery:
$("a#next").on("click", function () {
var nextli = $("li.first");
if ($(nextli).is(":last-child")) {
return false;
}
nextli.removeClass("first").addClass("record").next().addClass("first").removeClass("record");
});
$("a#previous").on("click", function () {
var nextli = $("li.first");
if ($(nextli).is(":first-child")) {
return false;
}
nextli.removeClass("first").addClass("record").prev().addClass("first").removeClass("record");
});
This is fine, and displays the records without any problem, however when you try to edit any record but the first, you get a "System.ArgumentNullException: Value cannot be null." error.
Here's the code in the controller for the edit function:
[HttpPost]
public ActionResult Edit(RecordsView rv)
{
if (ModelState.IsValid)
{
repository.EditRecord(rv.Records.FirstOrDefault().DogIncident);
}
return RedirectToAction("Index");
}
This is defined at the start of the cshtml file:
#using (Html.BeginForm("Edit", "Home", FormMethod.Post,new {#class="record-view"}))
And finally, here is how the HTML is generated on the view:
<li class="first" id="record-1805">
<form action="/Home/Edit" class="record-view" method="post">
<ul>
[form elements]
<li><input type="submit" style="margin: 18px 0;" value="Save"></li>
</ul>
</form>
</li>
<li class="record" id="record-1804">
<form action="/Home/Edit" class="record-view" method="post">
<ul>
[form elements]
<li><input type="submit" style="margin: 18px 0;" value="Save"></li>
</ul>
</form>
</li>
<li class="record" id="record-1803">
<form action="/Home/Edit" class="record-view" method="post">
<ul>
[form elements]
<li><input type="submit" style="margin: 18px 0;" value="Save"></li>
</ul>
</form>
</li>
Does anyone please know why I can only edit the first record that is displayed and not the others? Even if I go through the records using the next/back buttons and back to the first record to submit it, it updates fine, but updating any other record generates an error.
Referencing Darin's post: Pass a parameter to a controller using jquery ajax takes you halfway. He's using an input val in jQuery and passing it to the Controller Action.
Typically you'd provide one input link or #Html.ActionLink per record to be clicked for editing and MVC will bind to the controls parameter to your action (ID or what ever you want) just use the same name on the action link as the parameter and it will be mapped during the post.
data: { input: $('#caption').val() },
Change the signature of your controller action , or add another that takes an 'int' as shown below.
[HttpPost]
public ActionResult Edit(int ID = 0)
{
if (ModelState.IsValid)
{
repository.EditRecord(rv.Records.Where(r => r.ID == ID).DogIncident);
}
return RedirectToAction("Index");
}
Can you post the complete view so we can complete a solution ?
Was expecting the cshtml view. Here's an example:
#model IEnumerable<yourModelName>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.NID)
</th>
<th>
#Html.DisplayNameFor(model => model.CreatedOn)
</th>
<th>
#Html.DisplayNameFor(model => model.ExtensionAttribute15)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.yourElement1)
</td>
<td>
#Html.DisplayFor(modelItem => item.yourElement2)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
</td>
</tr>
}
</table>
#section Scripts{
<script type="text/javascript">
$("a#next").on("click", function () {
var nextli = $("li.first");
if ($(nextli).is(":last-child")) {
return false;
}
nextli.removeClass("first").addClass("record").next().addClass("first").removeClass("record");
});
$("a#previous").on("click", function () {
var nextli = $("li.first");
if ($(nextli).is(":first-child")) {
return false;
}
nextli.removeClass("first").addClass("record").prev().addClass("first").removeClass("record");
});
</script>
}
I Have a View and Partial View. The layout for the view is something like this:
<html>
...
<div id="MainView">#RenderBody()</div>
<!--Partial View-->
<div id="partialView">#Html.Action("PartialViewForm", "Main")</div>
...
</html>
My Partial View (named as _Register) is something like this:
#model PartialViewModel
<div id="form">
#using (Html.BeginForm("PartialViewForm", "Main", FormMethod.Post))
{
#Html.ValidationSummary(true)
<table >
<tbody>
<tr>
<td align="left">#Html.LabelFor(model => model.Name)*</td>
<td>#Html.EditorFor(model => model.Name)</td>
<td align="left">#Html.ValidationMessageFor(model => model.Name, "")</td>
</tr>
<tr>
<td align="left"><input type="submit" value="Go" class="submit2"/></td>
</tr>
</tbody>
</table>
}
</div>
In my MainController I have methods like this:
public class MainController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult PartialViewForm()
{
var partialViewModel= new PartialViewModel();
return PartialView("_Register", partialViewModel);
}
[HttpPost]
public ActionResult PartialViewForm(PartialViewModel partialViewModel )
{
// if Validation is not successfull
return PartialView("_Register", partialViewModel);
// else
....
}
}
This is what I want to do... when validation fails on the partial view I want to g back to the main view... however in my case on the post action when validation fails all I can see is the partialview... there is no main page content.
There are posts on the forum that show the same kind of behavior but I am not able to solve my issue. Can anyone please tell me how to fix it (it will be really helpful if you can modify my example and show it)
Thanks
I'm not sure if I totally understand what you are trying to do but if what I'm thinking is right, you should just use
[HttpPost]
public ActionResult PartialViewForm(PartialViewModel partialViewModel )
{
// if Validation is not successfull
model = _db.getBlah(); //get the original model for the main view
return View("MainView", model);
// else
....
}
However I think your issue might be that you really should have your form submission in your main view and not in your partial - the partial is just there to render the editors for your Create/Edit views, etc; the data should be submitted to the main view's action so that it can create/update the proper model.