I'm trying to get my table in the index view filtered by certain values, for this I use a [HttpGet] Index method which creates 2 selectLists (one for each filter type). The filter button is supposed to take the the selected value of each list, and send them to the [HttpPost] Index method, which filters the table.
The problem is that that it doesn't "reset" the url when I filtered, so it keeps adding to the url everytime I change the filter.
Index Get (This one works fine)
[HttpGet]
public IActionResult Index()
{
IEnumerable<Lesson> Lessons = _LessonRepository.GetAll();
ViewData["Types"] = GetTypesAsSelectList();
ViewData["Difficulties"] = GetDifficultiesAsSelectList();
return View(Lessons);
}
Index Post (This one keeps adding /Lesson/Index everytime I click the filter button in my view)
[HttpPost]
public IActionResult Index(string filter, string filter2)
{
IEnumerable<Les> Lessons = null;
if (filter == null && filter2 == null)
Lessons = _LessonRepository.GetAll();
else if (filter != null && filter2 == null)
{
Lessons = _LessonRepository.GetByDifficulty(filter);
}
else if (filter == null && filter2 != null)
{
Lessons = _LessonRepository.GetByType(filter2);
}
else if (filter != null && filter2 != null)
{
Lessons = _LessonRepository.GetByType(filter2).Where(l => l.Difficulty == filter);
}
ViewData["Types"] = GetTypesAsSelectList();
ViewData["Difficulties"] = GetDifficultiesAsSelectList();
return View(Lessons);
}
View
<form action="Lesson/Index/" method="post">
<div class="form-inline">
<select id="difficulties" name="filter" asp-items="#ViewData["Difficulties"] as List<SelectListItem>" class="form-control">
<option value="">-- Select difficulty --</option>
</select>
<select id="types" name="filter2" asp-items="#(ViewData["Types"] as List<SelectListItem>)" class="form-control">
<option value="">-- Select type --</option>
</select>
<button type="submit">Filter</button>
</div>
</form>
This happens because action attribute in form tag contains relative url. The resulting url of request is current url + relative url and that's why Lesson/Index/ is appended to current url on request. Consider using absolute url by adding / at the beggining
<form action="/Lesson/Index/" method="post">
Since you are using ASP.NET Core you can also make use of asp-action and asp-controller
<form asp-action="Index" asp-controller="Lesson" method="post">
Or you can stick with relative url but you need to consider how the resulting url is built. So if you form is on /Lesson/Index view then can use the following action
<!-- empty action, or you can just remove the attribute completely -->
<form action="" method="post">
This will give you current url + relative url = "/Lesson/Index" + "" = "/Lesson/Index"
Related
I am looking for a way to pass currently selected model from view to controller.
My select code:
<select asp-for="Product">
#foreach (var p in Model.Products)
{
<option value="#p">#p.ProductName</option>
}
</select>
I'm trying to bind option value #p to bind with my property below:
[BindProperty]
public Product Product { get; set;}
But whenever after submitting my form the Product property has "null" values.
Any suggestions?
I think you can use a hidden type for this. No need to query to find ProductName after submit in list.
<input type="hidden" asp-for="ProductName" />
<select asp-for="ProductId">
#foreach (var p in Model.Products)
{
<option value="#p.Id">#p.ProductName</option>
}
</select>
<script>
$(function () {
$('form').submit(function () {
var productName = $('#ProductId option:selected').text();
$('#ProductName').val(productName);
});
});
</script>
Usually you would pass the Id of the selected item when the form is posted. That is typically enough data to work with. However, if you really want the ModelBinder to create a Product instance from the posted values, your form fields should be named Product.ProductId and Product.ProductName. The other answer shows how to obtain the ProductName value and then assign it to a hidden field.
<select asp-for-"Product.ProductId" asp-items="Model.Products">
...
</select>
<input type="hidden" asp-for="Product.ProductName" />
How can I pass data from partial view on submit form in ASP.NET MVC.
#using (Html.BeginForm("Edit", "BlogPost", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
................
#Html.Partial("PostImagesForPost",Model.PostImages)
}
PostImagesForPost - partial view:
#model IEnumerable<Blog.Models.PostImage>
<script type="text/javascript" src="~/Scripts/jquery.zoom.min.js"></script>
<div>
#{
List<Blog.Models.PostImage> images = Model.ToList();
<ul class="images">
#foreach (var img in images)
{
string parameterValue_small = "~/BlogPhotos/120/" + img.Photo.ToString();
string parameterValue_big = "~/BlogPhotos/600/" + img.Photo.ToString();
<li>
<div id="jquery-image-zoom-example">
<span data-postid="#img.ID" data-delete="true" class="deletespan"></span>
<a href="#Url.Content(parameterValue_big)">
<img src="#Url.Content(parameterValue_small)" data-postid="#img.ID" class="zm" onclick="$('.jquery-image-zoom img').click()" />
</a>
<input type="checkbox" checked="checked" name="selectedImagesForDelete" style="display:none;" data-postid="#img.ID" value="#img.ID" />
</div>
</li>
}
</ul>
}
On submit function the parameter selectedImagesForDelete is null.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Post post,string[] selectedImagesForDelete)
{...........}
This has nothing to do with the fact you're using a partial, and everything to do with how the modelbinder in MVC works. For iterable posted items, the model binder expects field names in the form of ListProperty[index].ModelProperty. The problem is that the Html.* family of helpers will not create this name properly unless they are passed an indexed value, which you can't achieve with foreach. The solution is to simply use for, instead:
#for (var i = 0; i < images.Count(); i++)
{
Html.EditorFor(m => image[i].SomeProperty)
}
By passing in a value that's indexed (images[i]), the helper recognizes that it needs to add the proper indexed html prefix to the name, so that the modelbinder will understand where to stuff the value when it's posted back.
Though, in your case, you seem to actually just be manually specifying the HTML for the fields, which is fine, but you're responsible at that point for getting the name values right.
I believe your name property needs to have indexes in the name:
Create a index variable called index and increment it after each iteration
<input type="checkbox" name="selectedImagesForDelete[index]" value="2">
Actually it was a problem with the javascript file. The checkboxes were never checked.
<input type="checkbox" name="selectedImagesForDelete" value="#img.ID" />
But I resolved that problem and now everything works like expected.
But thanks for trying to help me. I appreciate it.
I have a form in ASP.Net and razor.
I need to have two ways of submitting said form: one that goes through the Edit action, and another that goes through the Validate action.
How should I go about doing this?
I don't mind using JavaScript for this.
EDIT:
Using the custom attribute I get this error.
The current request for action 'Resultados' on controller type 'InspecoesController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Validar(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
System.Web.Mvc.ActionResult Resultados(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
That's what we have in our applications:
Attribute
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
Actions decorated with it:
[HttpParamAction]
public ActionResult Save(MyModel model)
{
// ...
}
[HttpParamAction]
public ActionResult Publish(MyModel model)
{
// ...
}
HTML/Razor
#using (#Html.BeginForm())
{
<!-- form content here -->
<input type="submit" name="Save" value="Save" />
<input type="submit" name="Publish" value="Publish" />
}
name attribute of submit button should match action/method name
This way you do not have to hard-code urls in javascript
You can do it with jquery, just put two methods to submit for to diffrent urls, for example with this form:
<form id="myForm">
<%-- form data inputs here ---%>
<button id="edit">Edit</button>
<button id="validate">Validate</button>
</form>
you can use this script (make sure it is located in the View, in order to use the Url.Action attribute):
<script type="text/javascript">
$("#edit").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Edit","MyController")");
form.submit();
});
$("#validate").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Validate","MyController")");
form.submit();
});
</script>
If you are working in asp.net with razor, and you want to control multiple submit button event.then this answer will guide you. Lets for example we have two button, one button will redirect us to "PageA.cshtml" and other will redirect us to "PageB.cshtml".
#{
if (IsPost)
{
if(Request["btn"].Equals("button_A"))
{
Response.Redirect("PageA.cshtml");
}
if(Request["btn"].Equals("button_B"))
{
Response.Redirect("PageB.cshtml");
}
}
}
<form method="post">
<input type="submit" value="button_A" name="btn"/>;
<input type="submit" value="button_B" name="btn"/>;
</form>
Here is a good eplanation:
ASP.NET MVC – Multiple buttons in the same form
In 2 words:
you may analize value of submitted button in yout action
or
make separate actions with your version of ActionMethodSelectorAttribute (which I personaly prefer and suggest).
With HTML5 you can use button[formaction]:
<form action="Edit">
<button type="submit">Submit</button> <!-- Will post to default action "Edit" -->
<button type="submit" formaction="Validate">Validate</button> <!-- Will override default action and post to "Validate -->
</form>
<input type="submit" value="Create" name="button"/>
<input type="submit" value="Reset" name="button" />
write the following code in Controler.
[HttpPost]
public ActionResult Login(string button)
{
switch (button)
{
case "Create":
return RedirectToAction("Deshboard", "Home");
break;
case "Reset":
return RedirectToAction("Login", "Home");
break;
}
return View();
}
We can have this in 2 ways,
Either have 2 form submissions within the same View and having 2 Action methods at the controller but you will need to have the required fields to be submitted with the form to be placed within
ex is given here with code Multiple forms in view asp.net mvc with multiple submit buttons
Or
Have 2 or multiple submit buttons say btnSubmit1 and btnSubmit2 and check on the Action method which button was clicked using the code
if (Request.Form["btnSubmit1"] != null)
{
//
}
if (Request.Form["btnSubmit2"] != null)
{
//
}
I have a page that I want to create a drop down list, and post back to the same page that I am on now.
How can I do this?
One catch is, I want all the querystring values to be the same also, except for 1 which is what the drop down list will be overriding.
You can use both querystring and form variables in the same page if you want. If you use <form method="post"> and leave the action empty, it will post the form back to the current page, so that's one problem solved. There is one caveat: I'm not sure if leaving the action empty will keep the querystring parameters intact or not.
If not, you can try something like this: <form method="post" action="index.asp?<%= request.querystring %>"> (not sure about the exact syntax, the gist is that you will need to specify the current page and add the current querystring variables in the method).
In the ASP code on your page after posting you can check both request.form and request.querystring. request.form will contain your form post variables. request.querystring will contain the variables behind the ? in your URL.
HTH,
Erik
A Javascript method:
<html>
<head>
<script>
function jumpto(whatform, querykey) {
//get the url querystring
var url = window.location.search;
//the replace query
var queryrx = new RegExp("([?&])" + querykey + "=[^\&]+(?=&|$)", "gi");
//which item selected in dropdown
var index=whatform.pageselect.selectedIndex;
//if the first option, ignore it since it is blank
if (whatform.pageselect.options[index].value != "0") {
//is a query string available
if (url.length>0) {
//our query key is present
if (queryrx.test(url)) {
//now we replace the querystring from old to new
url = url.replace(queryrx, '$1' + querykey + '='+whatform.pageselect.options[index].value);
//clear out the question mark from the querystring
url = url.replace("?", '');
//our query key is not present, but there is querystring data
}else{
url = url.replace("?", '');
url = querykey + "=" + whatform.pageselect.options[index].value + "&" + url;
}
//no querystring data exists
}else{
url = querykey + "=" + whatform.pageselect.options[index].value;
}
//alert(url);
//this is the url we are getting bounced to
location = "mypage.asp?"+url;
}
}
</script>
</head>
<body>
<FORM NAME="form1">
<SELECT NAME="pageselect" ONCHANGE="jumpto(this.form, 'thequerykey')" SIZE="1">
<OPTION VALUE="">Choose a Page</OPTION>
<OPTION VALUE="pageA">First Page</OPTION>
<OPTION VALUE="pageB">Second Page</OPTION>
</SELECT>
</FORM>
</body>
</html>
If you want to go with an ASP Classic solution, you will need to use a function to clear your old value from your querystring
https://stackoverflow.com/a/1221672/2004151
And then print your querystrings as Hidden Input fields in your form (MyFunctionResultsExceptPageSelect below).
Something like:
<FORM ACTION="mypage.asp" METHOD="GET" NAME="form3">
<%=MyFunctionResultsExceptPageSelect("pageselect")%>
<SELECT NAME="pageselect" ONCHANGE="document.form3.submit()" SIZE="1">
<OPTION VALUE="">Choose a Page</OPTION>
<OPTION VALUE="pageA">First Page</OPTION>
<OPTION VALUE="pageB">Second Page</OPTION>
</SELECT>
</FORM>
<%
Function MyFunctionResultsExceptPageSelect(key)
Dim qs, x
For Each x In Request.QueryString
If x <> key Then
qs = qs & "<input type=""hidden"" name="""&x&""" value="""&Request.QueryString(x)&""" />"
End If
Next
MyFunctionResultsExceptPageSelect = qs
End Function
%>
If you want to get the current page instead of manually specifying it, then use the following.
In javascript snippet, use the answer here:
https://stackoverflow.com/a/5817566/2004151
And in ASP, something like this:
http://classicasp.aspfaq.com/files/directories-fso/how-do-i-get-the-name-of-the-current-url/page.html
I've a MVC application, whose SharedLayout view(Master Page) gives user capability to search. They could search their order by Order No or By Bill no. So there are two option buttons the Shared View along with the textbox. Code is somewhat like this
#using (Html.BeginForm("Track", "Tracking", FormMethod.Post))
{
<div style="text-align: center">
<textarea cols="20" id="txtNo" name="txtOrderNo" rows="2" ></textarea>
</div>
<div style="text-align: center">
<input type="radio" name="optOrderNo" checked="checked" value="tracking" />Order No <input type="radio" name="optRefNo" value="tracking" />Ref No
</div>
<div style="text-align: center">
<input type="submit" value="Track" />
</div>
}
So it'll go to TrackingController and Track Method in it and return the view. It works fine for a single search as a View is associated with a controller's methods. It works fine but how could i conditionally return the other view based on the radio button selection.
What i come up with is this
[HttpPost]
public ActionResult Track(FormCollection form)
{
string refNo = null;
if (form["optRefNo"] == null)
{
string OrderNo = form["txtOrderNo"];
var manager = new TrackingManager();
var a = manager.ConsignmentTracking(OrderNo);
var model = new TrackingModel();
if (OrderNo != null)
model.SetModelForConsNo(a, consNo);
return View(model);
}
refNo = form["txtConsNo"];
return TrackByRef(refNo);
}
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View();
}
Kindly guide.
Thanks
View has an overload where the first parameter is a string. This is the name (or path) to the view you want to use, rather than the default (which is a view that matches the action's name).
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View("Track");
// or, if you want to supply a model to Track:
// return View("Track", myModel);
}