I'm stuck with a very basic detail in a view.
I want to be able to let the user filter the results in the Index view.
To do this I've created a dropdown list, which gets populated thourgh my viewmodel:
#using (Html.BeginForm("Index", "Captains", FormMethod.Get)) {
<div class="row">
<div class="dropdown">
#Html.DropDownList("Name", new SelectList(Model.SomeProperty), new { id = "FilterList" })
</div>
</div>
#* ... *#
}
Additionally I have a small jQuery snippet to submit the form on the change event:
$('#FilterList').on('change', function () {
var form = $(this).parents('form');
form.submit();
});
The route I have created for this looks like this:
routes.MapRoute(
name: "IndexFilter",
url: "{controller}/{action}/{Name}",
defaults: new { Name = UrlParameter.Optional}
);
After the submit event I get redirected to the url /Index?Name=ChosenValue
This is filtering totally correct. However I'd like to get rid of the querystring and transform the route to /Index/ChosenValue.
Note: "Name", "ChosenValue" & "SomeProperty" are just dummy replacements for the actual property names.
Instead of submitting the form, you can concatenate /Captains/Index/ with the selected value of the dropdown and redirect to the url using window.location.href as below
$('#FilterList').on('change', function () {
window.location.href = '/Captains/Index/' + $(this).val();
});
I think you're looking for the wrong routing behavior out of a form submit. The type of route resolution that you're hoping to see really only happens on the server side, where the MVC routing knows all about the available route definitions. But the form submission process that happens in the browser only knows about form inputs and their values. It doesn't know that "Name" is a special route parameter... it just tacks on all the form values as querystring parameters.
So if you want to send the browser to /Index/ChosenValue, but you don't want to construct the URL from scratch on the client, you need to construct the URL on the server when the view is rendering. You could take this approach:
<div class="row">
<div class="dropdown">
#Html.DropDownList("Name", new SelectList(Model.SomeProperty),
new {
id = "FilterList",
data_redirect_url = #Url.Action("Index", "Captains", new { Name = "DUMMY_PLACEHOLDER" })
})
</div>
</div>
Above you're setting the URL with a dummy "Name" value that you can replace later, then you'll do the replacement with the selection and redirect in javascript:
$('#FilterList').on('change', function () {
var redirectUrl = $(this).data('redirect-url');
window.location.href = redirectUrl.replace("DUMMY_PLACEHOLDER", $(this).val());
});
If you are wanting to drop the query string off the url because it looks weird, then change your FormMethod.Post.
However, to really answer your question, I've tried the following successfully (Note: this might be considered a hack by some)
In short: update the action url on the form element when the list changes, client side.
$('#FilterList').on('change', function () {
var form = $(this).parents('form');
var originalActionUrl = form.attr("action");
var newActionUrl = originalActionUrl + "/" + $(this).val();
form.attr("action", newActionUrl);
console.log(form.attr("action"));
form.submit();
});
You will need to change your controller's signature to match whatever optional param value you specify in your route config. In your example, "Name".
Related
I'm unsure if this is possible but I want to use jQuery to assign value from my bound model to different textboxes inside a PartialView.
Originally when the page loads, it populates correctly with all of the model information. However I would like to implement a DDL to view historical updates (retrieved from my pre-populated DB).
I am able to call an Action method inside my respective controller which accepts a revisionID. I have verified that the method is returning the correct data.
Please see below for my code snippets:
Partial View:
$('#revisionDDL').change(function () {
var selectedRevisionID = $(this).val();
if (selectedRevisionID == '') {
selectedRevisionID = #Model.RevisionID - 1;
}
var url = '#Url.Action("GetAgreementByRevision")';
$.get(url, { revisionID: selectedRevisionID }, function () {
$('#ChangeReason').val('#Model.ChangeReason');
})
});
Input element:
<div class="input-group">
<span class="input-group-addon" id="change-reason">Change Reason</span>
#Html.TextAreaFor(m => m.ChangeReason, new { #class = "form-control", #rows = "1" })
</div>
Controller method:
public ActionResult GetAgreementByRevision(int revisionID)
{
Agreement revisedAgreement = new Agreement();
revisedAgreement = _agreementService.GetAgreementDetailsByRevision(revisionID);
return PartialView("AgreementDetailsFormPartial", revisedAgreement);
}
If I am not able to accomplish this, what would be my other options?
Your method in the controller returns PartialView which returns HTML content and you're trying to pass that HTML content as a value in the text area - this is not how it should work. You should return Json(revisedAgreement, JsonRequestBehavior.AllowGet); and then access this object in JavaScript.
$.get(url, { revisionID: selectedRevisionID }, function (data) {
// 'data' is your Agreement object
$('#ChangeReason').val(data.SomePropertyHere);
});
I'm trying to dynamically set the StudentIds by letting the user select check boxes for the reports they want. When they click the ActionLink, I use jQuery to set the values of the ids in a hidden field. I need the Action Link to read the ids from hidden field.
The values are getting set in the hidden field, but they are not being passed to the controller from the actionLink.
I need to pass the ReportIds to the controller.
#Html.ActionLink("PrintMed", "GetMedEdVerificationReport", "Student", new { studentIdList = Model.ReportIds }, new { #class = "button print_selected print_selectedMedEd disabled" })
#Html.HiddenFor(model => model.ReportIds)
javascript
$('.print_selectedMedEd').bind('click', function () {
var ids = getPrintIds();
if (ids.length == 0) {
return false;
}
$('#ReportIds').val(ids.toString());
return true;
});
When the asp.net mvc render your ActionLink it will generate a link with a parameter that you have on the model. Event you change the value of the model, it will not change the value on the output generated by ActionLink.
Given this, you have to se again the value, try to generate an ACtionLink without the argument:
#Html.ActionLink("PrintMed", "GetMedEdVerificationReport", "Student", null, new { #class = "button print_selected print_selectedMedEd disabled" })
On the javascript side, you could try using the on method to bind a event handler and call the preventDefault method from the event argument, for sample:
$('.print_selectedMedEd').on('click', function (e) {
e.preventDefault();
var ids = getPrintIds();
if (ids.length > 0) {
$('##Html.IdFor(model => model.ReportIds)').val(ids.toString());
// make an url to redirect
var url = $(this).prop("href") + "?studentIdList=" + ids.toString();
// redirect using the generated url
window.location.href = url;
}
});
Remember to use the Html.IdForm() to make sure you have the right id for a specific property.
That is because #Html.ActionLinkdoesn't use the hidden fields to make the request. Once the action link renders it becomes
PrintMed
so you would need to modify the html on the anchor tag.
You should be using Html.Beginform instead in order to pass along the model.
#using (Html.BeginForm("GetMedEdVerificationReport", "Student", FormMethod.Post, null))
{
#Html.HiddenFor(model => model.ReportIds)
<input type="submit" value="PrintMed" />
}
#Html.HiddenFor(modelItem => item.OrderId)
<td>
<input type="button" value="Pickup" onclick="location.href='#Url.Action("Edit", "Assignment", new { ID = item.OrderId })'" />
In View, the user will check 1 or more names from what's displayed ...
<form name=chkAttend method=post onsubmit='return validate(this)'>
<div>
#if (Model.evModel.Participants != null)
{
foreach (var fi in Model.evModel.Participants)
{
<div>
#if (#fi.AttendedFlag != true)
{
<input type="checkbox" id="c_#fi.EnrollmentId" name="MyCheckboxes" value="#fi.EnrollmentId" />
<label for="c_#fi.EnrollmentId" aria-multiselectable="True"></label>
<span></span> #fi.EnrollmentId #fi.ParticipantName
}
</div>
}
}
<input type=submit value="Confirm Attendance">
</div>
</form>
After selecting names, call the function to identify which names checked. The checked names only need to be passed to the controller. The problem - I'm getting the error message: Error 49 The name 'id' does not exist in the current context
function validate(form) {
var id = ""
for (var i = 0; i < document.chkAttend.MyCheckboxes.length; i++)
{
if (document.chkAttend.MyCheckboxes[i].checked)
id += document.chkAttend.MyCheckboxes[i].value + ","
}
if (id == "")
{
alert("Place a check mark next to event's Participant")
}
else
{
#Html.Action("ConfirmAttendance", "Admin", new { eventid = #Model.evModel.Id, enrollid =id })
}
return false;
}
How do I pass ONLY the checked items as parameter for the function in my controller?
You cannot inject a server-side partial view into your code like that. As it stands (if you got around the id variable reference problem) you would literally inject a partial view inline into your Javascript which will create invalid Javascript!
Instead treat the JS as client-side only and feed information into the page that the Javascript will need in a way that is easy to access. You can inject global variables via injected JS code, but I strongly advise against that practice.
Instead your MVC page could inject the controller action URL and the event id as data- attributes like this:
<form name="chkAttend" method="post"
data-action="#Url.Content("~/Admin/ConfirmAttendance")"
data-eventid="#Model.evModel.Id">
Using Url.Content will ensure the URL is always site relative, even when hosted as a virtual application.
Your client-side code can then pick up the values from the form, add the selected id and call the server action using Ajax:
e.g.
function validate(form) {
var action = $(form).data('action');
var eventId = $(form).data('eventid');
The fun begins now because you need to call the server from the client-side, e.g. via Ajax, with your selected option and do something with the result to change the display.
$.ajax({
// Use constructed URL (action + event id + id)
url: action + "?eventid=" + eventId + "&enrollid=" + id,
type: "PUT"
success: function (data){
// Do something with the server result
}
});
You do not show your controller's ConfirmAttendance action so I cannot even guess what you are returning. Make sure it is suitable (could be as simple as a Boolean result or as complex as a partial view to insert into the page).
Controller
[HttpGet]
[Route("~/search/{clause}/{skip?}")]
public async Task<ActionResult> Search(string clause, int skip = 0)
{
...
}
View
#using (Html.BeginForm("Index", "search", FormMethod.Get))
{
#Html.TextBox("clause", null, new { #class = "form-control col-md-4" })
...
}
Rendered Html
<form action="/search" method="get">
<input id="clause" name="clause" type="text" value="test">
</form>
I am using [HttpGet] partly because i want the search to be accessing via http://myapp.com/search/<search values>
When i navigate to http://myapp.com/search/test, everything seems fine, but when i try to enter my new search term in the textbox and hit enter or submit, it navigates to http://myapp.com/search?clause=newsearch
What should I do so that my textbox will navigate to http://myapp.com/search/newsearch instead?
Your form generates http://myapp.com/search?clause=newsearch because a browser has no knowledge of your routes (c# code running on your server).
In order to generate your preferred url (http://myapp.com/search/newsearch), you need javascript to intercept and cancel the default submit, and build a url to navigate to. Using jQuery:
$('form').submit(function() {
var baseUrl = $(this).attr('action'); // or var baseUrl = '#Url.Action("Index", "search")';
var url = baseUrl + '/' + $('clause').val(); // add value for skip if required
location.href = url; // redirect
return false; // cancel the default submit
});
I am trying to set up a simple login html page, whose action is sent to mvc controller on another of my sites. I have no problem setting up the page to do the post, and in the mvc controller I have my method that reads the form post. The problem is that I am not seeing my fields from the html form in the form collection.
Is there something special that I need to do to read a form post within a mvc controller method, if so what is that?
The is the form action markup from my page
<form action="http://reconciliation-local.sidw.com/login/launch" method="post">
User Name <input type="text" id="username"/><br/>
Password <input type="text" id="password"/>
<input type="submit" value="launch"/>
</form>
The controller method
[HttpPost]
public ActionResult launch(FormCollection fc)
{
foreach (string fd in fc)
{
ViewData[fd] = fc[fd];
}
return View();
}
When I step through the controller method code, I am not seeing anything in the formcollection parameter.
Post Html To MVC Controller
Create HTML page with form (don't forget to reference a Jquery.js)
<form id="myform" action="rec/recieveData" method="post">
User Name <input type="text" id="username" name="UserName" /><br />
Password <input type="text" id="password" name="Password"/>
<input type="submit" id="btn1" value="send" />
</form>
<script>
$(document).ready(function () {
//get button by ID
$('#btn1').submit(function () {
//call a function with parameters
$.ajax({
url: 'rec/recieveData', //(rec)= Controller's-name
//(recieveData) = Action's method name
type: 'POST',
timeout: '12000', (optional 12 seconds)
datatype: 'text',
data: {
//Get the input from Document Object Model
//by their ID
username: myform.username.value,
password: myform.password.value,
}
});
});
});
</script>
Then in The MVC Controller
controller/action
| |
1. Create Controller named rec (rec/recieveData)
Create View named rec.cshtml
Here is the controller:
public class recController : Controller
{
// GET: rec
string firstname = "";
string lastname = "";
List<string> myList = new List<string>();
public ActionResult recieveData(FormCollection fc)
{
//Recieve a posted form's values from parameter fc
firstname = fc[0].ToString(); //user
lastname = fc[1].ToString(); //pass
//optional: add these values to List
myList.Add(firstname);
myList.Add(lastname);
//Importan:
//These 2 values will be return with the below view
//using ViewData[""]object...
ViewData["Username"] = myList[0];
ViewData["Password"] = myList[1];
//let's Invoke view named rec.cshtml
// Optionaly we will pass myList to the view
// as object-model parameter, it will still work without it thought
return View("rec",myList);
}
}
Here is the View:
#{
ViewBag.Title = "rec";
}
<h2>Hello from server</h2>
<div>
#ViewData["Username"]<br /> <!--will display a username-->
#ViewData["Password"] <!-- will display a password-->
</div>
If you posted some code it would be much easier to help you, so please edit your question...
Make sure that your form's action has the correct address, that your method is specifying POST (method="POST") and that the input fields under your form have name attributes specified.
On the server side, try making your only parameter a FormCollection and test that the fields in your form posted through the debugger. Perhaps your model binding isn't correct and the FormCollection will at least show you what got posted, if anything.
These are just common issues I've seen. Your problem could be different, but we need to see what you're working with to be able to tell.
Try something like this:
cQuery _aRec = new cQuery();
_aRec.Sqlstring = "SELECT * FROM Admins";
DataSet aDS = _aRec.SelectStatement();
DataTable aDT = aDS.Tables[0];
foreach (DataRow aDR in aDT.Rows){
if (txtAdminUsername.Text == aDR[0].ToString()){
if (txtAdminPassword.Text == aDR[1].ToString()){
Session["adminId"] = aDR[0];
Response.Redirect("Admin.aspx");
return;
}
}
}
Make sure that your FormCollection object properties for username and password are defined properly.
I had to use the name attribute on the text tag, and that solved my problem, is now working like a charm.
You have to use Ajax to do that.. Whenever you want to "submit" from client side, you should use Ajax to update the server
Step 1 - you redirect your Ajax call to your action, but with your list of parameters in the query-string appended
$.ajax(url: url + "?" + your_query_string_parameter_list_you_want_to_pass)
Step 2 - add optional parameters to your Controller-action with the same names and types you expect to get returned by the client
public ActionResult MyControllerAjaxResponseMethod(type1 para1 = null,
type2 para2 = null,
type3 para3 = null, ..)
Know that the optional parameters have to be initialized, otherwise the Action itself will always ask for those
Here's where the "magic" happens though --> MVC will automatically convert the query-string parameters into your optional controller-parameters if they match by name
I was also looking for a good answer for this, --> i.e. - one that doesn't use q-s for that usage, but couldn't find one..
Kinda makes sense you can't do it in any other way except by the url though..