Pass data from view to controller method - asp.net-mvc-4

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.

Related

Mvc 6 taghelper asp-action route not working

I'm using Areas in Mvc 6 and trying to route to each specific area.
For example I have this:
My controller looks is decorated with a Area and route attribute, like so:
[Authorize]
[Area("Test")]
[Route("[area]/[controller]")]
public class TestController : Controller
Then, I have two HTTPGET methods defined like below:
public IActionResult Index()
{
var model = new TestViewModel();
return View(model);
}
public IActionResult Create()
{
var model = new TestViewModel();
return View(model);
}
Finally my form looks like this:
<form asp-route-area="Test" asp-controller="Test" asp-action="Create" asp-antiforgery="false" method="get">
<input type="submit" value="Generate test"/>
</form>
When I try to post the form it throws the following:
AmbiguousActionException: Multiple actions matched. The following
actions matched route data and had all constraints satisfied:
Areas.Test.Controllers.TestController.Index
Areas.Test.Controllers.TestController.Create
You would think that it would bind to my Create method when I define it in the asp-action, but when I check the rendered markup of the form it looks like this:
<form method="get" action="/Test/Test">
<input type="submit" value="Generate test">
</form>
My method Create isn't handled, It only renders Test/Test (area/controller).
I've also tried to decorate my method with [Route("Create")] and [HttpGet("Create")] without results.
Am I missing out on something obvious here?
If you are using RC1 then you can't use areas in tag helpers.
Areas in tag helpers are supported in RC2 link to issue

MVC - why code after ajax.beginform being executed

Form for AJAX call:
#using(Ajax.BeginForm("RefineSearchResults", "Search", new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "resultsSec" }))
{
<input type="submit" value="submit" />
<div id="resultsSec"></div>
}
after form tag:
#{Html.RenderAction("Index", "NewsLetter", new { area = "" });}
but, it throws exception on second piece of code when posted back although it's not supposed to be execued because it's an AJAX call and it's outside the Ajax form.
Exception message:
Error executing child request for handler
'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
Can anyone please tell me what's going wrong here. Thanks!
oops!!! My mistake!
Actually, I was returning the main view again that's why code that wasn't supposed to be rendered was being rendered.
Now I have added the view code that was to be refereshed through Ajax.BeginForm() to a partial view.
My openion:
You should apply Ajax form on partial view preferably because from
controller when you return a view then the target view have to be rendered
again (it's ok when you have to show only a string through Content()
method.)
So, refreshing the partial view through Ajax form would be an ideal way to use Ajax.BeginForm() in my humble openion.

Passing textbox value from View to action without using Html.begin form and Submit button

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")`

Form submission for mvc model enumerable using editor template

I have an editor template for my model view ViewSetup. My view to use template is simplified as
#model IEnumerable<ViewSetup>
#Html.EditorFor(s => s)
My ViewSetup editor template has form submission like below:
using (Ajax.BeginForm("Edit", new AjaxOptions() { HttpMethod = "Post" }))
{
#Html.HiddenFor(p => p.TradingPartner.ID)
<input type="submit" value="Save" />
}
So basically i need a form to be submitted for each element of the Enumerable. But I'm facing a problem on form submission. My controller to process post is:
public ActionResult Edit(ViewSetup formDataSent)
{
formDataSent.Save();
}
As per default model binding I'm getting null for TradingPartner property since the name in the html is :
<input name="[0].TradingPartner.ID" type="hidden" value="1"/>
What I need is to submit only the ViewSetup object on each element instead of an array. If I can get the index part in the name removed that could work for me. But I'm not sure how to get just the ViewSetup object on form submission.
I bet that if you base your editor on one item instead of a list of items then you would gain more flexibility.
#model IEnumerable<ViewSetup>
#foreach (var item in Model)
{
#Html.EditorFor(modelItem => item.TradingPartner)
}
I had the same issue, what resolved it for me was this:
#foreach (var item in Model)
{
#Html.EditorFor(modelItem => item.TradingPartner, null, "")
}
The third property of the EditorFor being blank will get rid of the "[0]" from your objects.

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).