Passing textbox value from View to action without using Html.begin form and Submit button - asp.net-mvc-4

I have created a texbox. When user give some input in the textbox and click the actionlink below, the value of the textbox will get pass to the actionResult(FWMenu) in the controller. I can not use html.begin form and submit button in the view. And i can not even use [httppost] in my controller.
Is it possible in that way? If yes then please help me how.
I have not used any class in model.
Below is my Controller.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult FWMenu(string username)
{
return View();
}
}
This is my View.
<div>
#Html.TextBox("txtUserName")
#Html.ActionLink("Login", "FWMenu", new { username = #Html.TextBox("txtUserName") })
</div>

You need to use javascript/jquery to build the url and redirect. From your comments you mentioned you wanted to use a image rather than a button or link, and that you will have multiple items, so assuming you html is
<div>
<input type="text" name="username">
<img class="submit scr=....>
<div>
<script>
var urlBase='#Url.Action("FWMenu");
$('.submit').click(function() {
var userName = $(this).prev('input').val();
location.href = urlBase + '/' + userName;
}
</script>
Side note: No real point using #Html.TextBox("txtUserName") and if you have multiple instance of this it would generate invalid html (duplicate id attributes) and in any case the name of the parameter is username so it would have needed to be #Html.TextBox("username")`

Related

Select dropdown value after post

I was hoping for some guidance on an issue I am having with preserving the value in a dropdownlist after post (razor)
I have a simple page:
#model testContingency.Models.ListByWardDD
#{
ViewBag.Title = "TestDropDowns";
}
<h2>TestDropDowns</h2>
<div>
#Html.DropDownList("HospModel", Model.Hospital, new { #onchange = "ChangeHospital(this.value)" })
#Html.DropDownList("WardModel", Model.Wards)
<script type="text/javascript">
function ChangeHospital(val) {
window.location.href = "/PatientListByWardDD/TestDropDowns?hospID=" + val;
}
</script>
</div>
here's the controller
public ActionResult TestDropDowns(int? hospID)
{
PASInpatientRepository pasRepo = new PASInpatientRepository();
var returnModel = new ListByWardDD();
var HospitalData = pasRepo.GetPatientHospitalsEnum();
returnModel.Hospital = pasRepo.GetHopspitalListItems(HospitalData);
var WardData = pasRepo .GetPatientWardsEnum(hospID);
returnModel.Wards = pasRepo.GetWardListItems(WardData);
ViewBag.HospSearch = hospID;
return View(returnModel);
}
In the controller PASInpatientRepository() communicates with a cache database. It passes back public IEnumerable < SelectListItem > GetHopspitalListItems. It calls stored procedures written within a cache database (same as sql stored procedures in essence). This is all working fine in its own crude way.
The issue I am having is that when I select the dropdownlist #Html.DropDownList("HospModel", Model.Hospital, new { #onchange = "ChangeHospital(this.value)" }) and the controller is called to refresh the Wards dropdown, I want to preserve the value I have selected in the hospital dropdown. I have tried a few different ways, but I admit, I'm a bit stuck. Most examples I found are for strongly typed.
As I mentioned, I'm new to MVC, but any advice on how to solve this issue, or suggestions on improving my code are greatly appreciated.
So I'm not sure what the Hospital property looks like but I'll make the assumption that each one has a unique ID.
Furthermore to bind the posted data to the view model you'll need to use forms in your view. To create the drop down list use the DropDownListFor-Helper. This way the data will be bound back to your Model after submitting the form.
So your view could look something like this
#model testContingency.Models.ListByWardDD
#{
ViewBag.Title = "TestDropDowns";
}
<h2>TestDropDowns</h2>
<div>
#using (Html.BeginForm("TestDropDowns", "YourController", FormMethod.Post))
{
#Html.DropDownListFor(x => x.HospitalID, Model.Hospital)
#Html.DropDownListFor(x => x.WardID, Model.Wards)
<input type="submit" value="send" />
}
</div>
Your ViewModel testContigency.Models.ListByWardDD must have at least the following properties
public class ListByWardDD {
public int HostpitalID { get;set; }
// the value of the SelectListItem-objects should be the hospital ID
public IEnumerable<SelectListItem> Hospital { get;set; }
public int WardID { get;set; }
// the value of the SelectListItem-objects should be the ward ID
public IEnumerable<SelectListItem> Wards { get;set; }
}
Once you post the form (for simplicity I added a button to send the form and left the javascript part out) the method TestDropDowns of your controller (which you need to fill in the BeginForm-Helper) will be called. That method expects expects an object of type ListByWardDD as a parameter and the framework will automatically populate the values for you.
[HttpPost]
public ActionResult TestDropDowns(ListByWardDD viewModel) {
// your code here, viewModel.HospitalID should contain the selected value
}
Note: After submitting the form the properties Hospital and Wards will be empty. If you need to display the form again, you need to repopulate those properties. Otherwise your dropdown lists are empty.
I tried my best to post valid code but I did not compile or test it.

Post back Errors in MVC 4

In regular Asp.Net, when you want to post an error, for ex, a duplicate ID, I use Panels for controls, error message labels, etc. I was wondering, how to achieve the same using MVC 4.
Currently, on my Index page, I have an Id, Name & Address column and a Submit button. My HTTPPOST ActionResult here:
[HttpPost]
public ActionResult Index(Person p)
{
if (ModelState.IsValid)
{
PersonInfo pi = new PersonInfo();
var duplicate = from d in db.PersonInfoes
where d.Id == p.Id
select d;
if (duplicate.Any())
{
return View("Duplicate");
}
else
{....}
When I enter a duplicate Id, upon submitting the page, I need to post to the same view ("Index") page to let user know that there is an Id already, but currently, I am redirecting to a different view to let user know as a duplicate, and I dont think this is the right way to do this. I am learning MVC, btw and hence this doubt. My duplicate cshtml here:
#{
ViewBag.Title = "Duplicate";
}
<h2>Duplicate</h2>
<h3>Duplicate ID found !!</h3>
<p>Please correct the ID and re-enter !</p>
<br/><br/>
#Html.ActionLink("Back to Data Entry","Index")
Any pointers would help.
You can return to the same view. You should consider adding an error to the model state dictionary so that you can show that in the UI.
[HttpPost]
public ActionResult Index(Person p)
{
if (ModelState.IsValid)
{
var duplicate= db.PersonInfoes.Where(s=>s.Id== p.Id);
if (duplicate.Any())
{
ModelState.AddModelError(string.Empty,"Duplicate found");
return View(p);
}
// to do : Your existing code
}
return View(p);
}
Just make sure you are calling the ValidationSummary method in your Index view to show this error message.
#model Person
#using (Html.BeginForm())
{
#Html.ValidationSummary(false)
<!-- Your form fields goes here-->
<input type="submit" />
}

Pass data from view to controller method

I need to use the name of the current view in a method in my controller
I am able to get the name with the code below in my view.
I will like to pass this #ViewData["pageName"] to my MakeChange action result
in my controller. Each time I step through the MakeChange method all I get
is "object reference not set to an instance of an object"
How can I pass data from my view to controller method ?
#ViewData["pageName"] = #Path.GetFileName(Server.MapPath(VirtualPath))
public ActionResult MakeChange(string lang)
{
string getPageName = ViewData["pageName"].ToString();
return RedirectToAction(getPageName, "Home");
}
You can't pass data from view to controller using ViewData. You can use ViewData to pass data from Controller to your view.
To achieve what you want, you can do as follows:
<input type='hidden' name='lang' value='#Path.GetFileName(Server.MapPath(VirtualPath))' />
<input type='submit' value='send'>
Ps: you should put the input's inside a form tag.
Path.GetFileName(Server.MapPath(VirtualPath)) will give you the razor view name with extension (Ex : index.cshtml). You can not use that with RedirectToAction method as RedirectToAction method is looking for an action method name. You need to trim down the file extension part before using it.
To send this to the controller action, you can keep the value inside a hidden field inside your form. When user posts the form, it will be available in your HttpPost action method. You need to make sure that there is a parameter which has same name as the hidden field's name value.
#using (Html.BeginForm())
{
<input type="text" name="lang" value="English" />
<input type="hidden" name="pageName"
value="#Path.GetFileName(Server.MapPath(VirtualPath))" />
<input id="BtnAdd" type="submit" value="Save" />
}
So your action method will be
public ActionResult MakeChange(string lang,string pageName)
{
var viewName=pageName;
//Get rid of the extension.
viewName = viewName.Replace(".cshtml","");
return RedirectToAction(viewName , "Home");
}
Even if you are doing an ajax post, it will still work, just serialize your form and send it
$("#BtnAdd").click(function(e){
e.preventDefault();
var _this = $(this);
$.post("#Url.Action("MakeChange","Home")",_this.closest("form").serialize(),
function(response){
//do something with response
});
});
There are more clean ways of getting the view name without the file extension trimming approach we did. Take a look at this answer.

can't pass multiple parameters using mvc4 html.beginform(...)

In my mvc4 application i want to use html.beginform() to pass multiple parameters to an actionResult on the same controller.
I do it like this:
view:
<div>
#using (Html.BeginForm("AddNote", "Lead",FormMethod.Post, null))
{
#Html.Hidden("leadID",#Model.ID)
<input type="text" name="noteBody" />
<input type="submit" class="mainButton" value="Add New!"/>
}
</div>
Controller (LeadController):
[HttpPost]
ActionResult AddNote(int leadID, string noteBody)
{
Note note = new Note();
note.DateModified = DateTime.Now;
note.Title = "No Title";
note.Body = noteBody;
Lead lead = unitOfWork.LeadRepository.GetById(leadID);
lead.Notes.Add(note);
unitOfWork.Save();
return RedirectToAction("Details", new { id = leadID });
}
when i press the submit button i get an exception:
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Lead/AddNote
this is the place to say that i have tried it withput parameters and it worked just fine.
I've also tried to pass the "leadID" parameter inside the form declaration (new {leadID = #Model.ID}).
Any idea what am i doing wrong ?
Just add the 'public' modifier to your action and it will do the magic.
The AddNote method should be public. Use the public keyword and it will work.
Add the HTTPPOST attribute , like this
[HttpPost]
ActionResult AddNote(int leadID, string noteBody)
{
Note note = new Note();
note.DateModified = DateTime.Now;
note.Title = "No Title";
note.Body = noteBody;
Lead lead = unitOfWork.LeadRepository.GetById(leadID);
lead.Notes.Add(note);
unitOfWork.Save();
return RedirectToAction("Details", new { id = leadID });
}
Perhaps it helps you

Working with Multiple forms in MVC4

I am creating a small application in MVC 4. I have 2 forms form1 and form2 in single view. When one form is posted I proceed to the next form where I redirect from view to a action method Employee in which I perform some task and then again from action method I return back to view, in the view I want to go for form2 without touching form1 how do I do that.
Below I will show sample of how my code looks like
Controller
public ActionResult Index()
{
//some task
resturn view();
}
public ActionResult Employee()
{
//some task
}
View
#html.BeginForm("Index","Show",FormMethod.Post,new {#name=form1})
{
//Shown something
}
#Html.Action("Employee","Show")
#html.BeginForm("Employee","Show",FormMethod.Post,new {#name=form2})
{
//Shown something
}
Create a Javascript that checks if any of the required values in form 1 is set. If so, set focus on whatever element you want in form 2. Here's an example:
The html forms:
<form id="one">
<input type="text" id="requiredFormField" value="some value previously entered" />
</form>
<form id="two">
<input type="text" id="form2text" />
</form>
And the javascript:
$(document).ready(setFocusIfForm1Completed());
function setFocusIfForm1Completed()
{
var expectedValue = $("#requiredFormField").val();
if(expectedValue.length > 0)
{
$("#form2text").focus();
}
}
I should add that I assume that you fill in form 1, then you submit (do a POST request to the server) which does some work, and then returns the same view but with at least some required value from form 1 populated (otherwise, this solution breaks).