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..
Related
I have a C# MVC web form with a fairly complex hierarchy of data. I need to select a portion of that data, a sub-collection of objects, and send it to an Action where I can manipulate the collection and return a partial view. All of this is old-hat, except I can't figure out how to select the sub-collection with JQuery.
Example:
Orders.Customers
// For simplicity, Customer has the following properties
public class Customer
{
public int Id { get; set;}
public string Name { get; set;}
}
On the Razor view, you end up with elements that look like this:
<input name="Order_Customers[0].Id" id="Order.Customers[0].Id" type="hidden" value="154' />
<input name="Order_Customers[0].Name" id="Order.Customers[0].Name" type="hidden" value="John Smith' />
<input name="Order_Customers[1].Id" id="Order.Customers[1].Id" type="hidden" value="176' />
<input name="Order_Customers[1].Name" id="Order.Customers[1].Name" type="hidden" value="Kendra Wallace' />
I only need to pass the sub-collection of Customers to an action that looks something like this:
public ActionResult AddCustomer(IList<Customer> customers)
{
// Do some work on the collection, add/remove members, etc.
return PartialView("_Customers", customers);
}
The part I can't figure out is the JQuery selection. I've tried variations of this but I can't get any of them to work:
var customers = $("input[name^='Order_Customers']".toArray(); // ?
var customers = $("input[name^='Order_Customers[]']".toArray(); // ?
If the selected inputs are not already in a form, create one:
var $form = $('<form>');
Append the elements you found with jQuery to that new form and then make a new FormData object with the populated form:
var formData = new FormData($form);
You can then pass that formData directly to the AJAX url and MVC will deserialize/bind the submitted data to the list of Customers.
url: '#Url.Action("UploadImage")',
type: 'POST',
data: formData,
You'll also need to change the paramter of your action so that MVC can map the properties to Order.Customers or change the name property in the HTML of those fields to be like Customer[0].Name.
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".
I am trying to do a search with GET Method but I couldnt do the way I need. My html-css code is like below
<div class="top_search_form">
<a class="top_search_btn" href="javascript:void(0);" ><i class="fa fa-search"></i></a>
<form method="GET" action="/Banyo/Urunler">
<input type="text" name="search" value="Search" onFocus="if (this.value == 'Search') this.value = '';" onBlur="if (this.value == '') this.value = 'Search';" />
</form>
</div>
It looks like below
The user enters some text and hit the enter to do a search. But when I do a search, the URL is like below, which is not the way I need.
/Banyo/Urunler?search=asd
when the user hits the enter. I want to see the link below
/Banyo/Urunler/asd
how can I have this URL "/Banyo/Urunler/asd" ? what should I do to have this?
My MapRoute is like below
routes.MapRoute(
"Urunler", // name it!
"Banyo/Urunler/{Filtre}", // Route name
new { controller = "Banyo", action = "Urunler", Filtre = UrlParameter.Optional } // Parameter defaults
);
and I updated my html
<form method="GET" action="/Banyo/Urunler">
if the parameter name in your action (search in this case) is not defined in your route config, it'll be appended as a query string parameter when doing GET requests.
the default route defines an id parameter so you could use this instead.
Your search field would be renamed to id and your action would have an id parameter as well.
public ActionResult Urunler(string id)
{
}
Another option would be to use attribue routing (if you are using MVC4 and above).
Route("Banyo/Urunler/{search}")]
public ActionResult Urunler(string search)
{
}
Attribute routing in MVC4 would require you to install the nuget packages yourself ... i think they are added by default in MVC5
In the form, add JavaScript to the onsubmit attribute. For example...
<form onsubmit="location.assign(this.action+'/'+this.search.value);return false" action="/Banyo/Urunler">
This browses the <input> tag's value appended to the URL provided by the form. this.search provides access to the <input> element with the name of "search".
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).
I have an MVC project that has a page with several forms on it. Most of the content on the page is rendered based on an initial form that a user submits. When a user updates information on that page I don't want the entire page to refresh I just need it to submit the form and stay on the page. I've tried to setup the form to submit with AJAX, but I don't know what to make the controller method return to accomplish this.
Form:
<div id="HeatNameDiv" title="Change Heat Name">
#using (Ajax.BeginForm("ChangeHeatName", "Home", new AjaxOptions(){UpdateTargetId = "HeatNameDiv"}))
{
<section>
Heat Name:<input type="text" name="heatName" value="#Html.ValueFor(x => x.heatname)" style ="width:100px"/>
Change to:<input type="text" name="updatedHeat" value="" style="width: 100px" />
<input type="submit" name="ChangeHeatName" value="Change" />
</section>
}
Current Controller:
public ActionResult ChangeHeatName(string heatName, string updatedHeat)
{
string user = User.Identity.Name;
HomeModel H = new HomeModel();
H.ChangeHeatName(heatName, updatedHeat, user);
return Content("Index");
}
It depends on what you want refreshed. Ajax.BeginForm expects an HTML fragment. So you need a partial that represents the heatNameDiv that you want to replace after submit:
public ActionResult ChangeHeatName(string heatName, string updatedHeat)
{
string user = User.Identity.Name;
HomeModel H = new HomeModel();
H.ChangeHeatName(heatName, updatedHeat, user);
return PartialView("NameOfPartialView", H);
}
I agree with Jeremy because Ajax.BeginForm is less flexible. I have tried hard to use it in the past, but the fact that it replaces the target element, instead of the innerHtml of the target, makes it difficult for many scenarios.
With $.ajax you can set url: '#(Url.Action("MyActionReturningAPartialView"))' and in the .success callback function(response) { $('#heatNameDiv').innerHtml(response); }
The action you call still returns a PartialView.