How can I pass a value from my page to the controller? - c#

I'm using MVC with Razor and C#. I would like to update an element... a counter with ajax. Here is my code:
#model Domain.CounterObject
#using (Ajax.BeginForm("Count", "CounterObject", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "my-control" }))
{
<div id="my-control" class="bid-object">
<div>
<span class="title">#Html.Encode(Model.Title)</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetFinalDate())</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetValue())</span>
</div>
<div>
<input type="submit" value="Count" />
</div>
</div>
}
In my controller I have this code:
[HttpPost]
public PartialViewResult Count(CounterObject counter)
{
// Special work here
return PartialView(counter);
}
The problem is that my CounterObject counter I receive in my Count method is always null. How can I pass a value from my page to the controller?

I receive in my Count method is always null
First of all you are not submitting anything from the form then how does the binding happens?
If the user is not allowed to edit the values but still you want to submit them through the form then you have to use hidden fields along with them.
For ex.
<div>
<span class="title">#Html.Encode(Model.Title)</span>
#Html.HiddenFor(m => m.Title)
</div>
Note that the hidden fields should have the same names as the properties to make the binding happen successfully.
It is better to have properties in the Model that store the GetFinalDate() and GetValue() results so you can easily bind the things like in Title.

You'll have to define a input field with a name and id that the ModelBinder can then Bind to your CounterObject.
You could use #Html.EditorForModel once and then inspect the generated Html to see what kind of name/id pairs it is generating. With those you can go on and handcraft your Html if you wanted to.

use
<span class="title">#Html.Encode(Model.Title)</span>
<div class="editor-field">#Html.EditorFor(Model => Model.Title)<div>
//For other fields
In this way you can bind to your object.

Related

Passing input value to a controller method, not the whole model in Asp.Net Core 3

I have a ToDo items dashboard page where I display the ToDo's, their status and some other app info.
I want to have one input where I can add a string value (the ToDo title) and on the button click
have that passed to the controllers Create get method, so it populates the Create views Title input field with that value.
I want to it without a form if that is possible as the dashboard page already has a model which is an IEnumerable, just pass that value as a querystring parameter to the Create pages get view (or is it doable in javascript?).
Im not an MVC expert and also not as familiar with the new tag helper methodologies. Any help in how to structure thiswould be helpful.
Here is the html
<!-- Add Task -->
<div class="input-group input-group-lg">
<input class="form-control" type="text" placeholder="Add task and press enter..">
<span class="input-group-addon">
<a asp-controller="ToDoItems" asp-action="Create" ><i class="fa fa-plus"></i></a>
</span>
</div>
<!-- END Add task -->
here is the new model
public Class MyModel{
public IEnumerable<your old model> Old Model {get; set;}
public string Title {get;set;}
}
You can create a form like so in html with razor syntax
#model MyModel
...
<form action="/Controller/PostTitle/" method="post">
#Html.TextBoxFor(m => m.Title,new {#class = "...", #placeholder="...",
#requried="required"})
<input id="export-btn" type="submit" value="Download" class="btn btn-info" />
</form>
The #TextBoxFor will create a textbox and the lambda lets you use your strongly typed model.
Here is the controller
[HttpPost]
public IActionResult PostTitle(string Title) {
...
}

Persisting Collections in ViewModel

I've been struggling for quite some time now with trying to maintain a list of objects when the ViewModel is submitted back to the controller. The ViewModel receives the list of objects just fine, but when the form is submitted back to the controller the list is empty. All of the non-collection properties are available in the controller, so I'm not sure what the issue is. I have already read the guide a few people have referenced from Scott Hanselman here
From what I can see, everyone solves this by building an ActionResult and letting the model binder map the collection to a parameter:
Controller:
[HttpPost]
public ActionResult Submit(List<ConfigurationVariable> variables)
{
}
View:
#for (int i = 0; i < Model.ConfigurationVariables.Count; i++)
{
<div class="row">
<div class="col-xs-4">
<label name="#Model.ConfigurationVariables[i].Name" value="#Model.ConfigurationVariables[i].Name" />
</div>
</div>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control" name="#Model.ConfigurationVariables[i].Value" value="#Model.ConfigurationVariables[i].Value" />
</div>
</div>
}
What I really want is to be able to pass my ViewModel back to the controller, including the ConfigurationVariables List:
Controller:
[HttpPost]
public ActionResult Submit(ReportViewModel report) //report.ConfigurationVariables is empty
{
}
View:
#for (int i = 0; i < Model.ConfigurationVariables.Count; i++)
{
<div class="row">
<div class="col-xs-4">
#Html.LabelFor(model => model.ConfigurationVariables[i].Name, new { #class = "form-control" })
</div>
</div>
<div class="row">
<div class="col-xs-4">
#Html.TextBoxFor(model => model.ConfigurationVariables[i].Value, new { #class = "form-control" })
</div>
</div>
}
This will be a complicated form and I can't just put every collection into the ActionResult parameters. Any help would be greatly appreciated
You need to hold the Name property in a hidden input so that it's submitted. Label values are lost.
#Html.HiddenFor(model => model.ConfigurationVariables[i].Name)
Alright, based on your comment you won't be able to utilize mvc's form binding. No worries.
Instead of this controller definition:
public ActionResult Submit(List<ConfigurationVariable> variables)
Use one of these two:
public ActionResult Submit()
public ActionResult Submit(FormCollection submittedForm)
In the first you can access the Request object, you'll need to debug and locate your variable, then you'll need some logic to parse it apart and used the values submitted.
In the second, the form collection will be made up of all the INPUT elements in your form. You will be able to parse through them directly on the object without interference from the other attributes of the Request object.
In both cases you will probably need to use #Html.TextBox, and not TextBoxFor, and you will need to dynamically populate your dropdowns in your view.
I'm not 100% sure about the Request object, but for sure on the FormCollection you will need to create an Input element for each value/collection you want submitted. Including hidden inputs for your textboxes
Your textboxes will need to be SelectListItem collections. those require a key and a value, and when they are submitted you can loop through the collection and check the .Selected attribute.
I would try with FormCollection first, and if that doesn't work fall back to the Request object.
Also note: you are not getting a viewmodel back from the form submission, you will need to rebuild it from the form elements. If you want to post prepopulated data to the view you will need to build a view model and do appropriate parsing on the view to display it.

How add params to my form

<form method="post" class="search-form" action="?">
<fieldset>
<input class="search home_input_search" placeholder="Поиск" type="search" />
<input type="submit" class="subm but_search" value="" />
</fieldset>
</form>
I have a form - search, this is layout and my task consistent in creation link to the controller with params like Products/index?search_name=something. And I dont know how I can transfer value textbox in my link.
Add onsubmit event handler to form, it should:
create Url with query string ?search_name= value from input
set window.location.href to created url
return false
EDIT: Of course, you can implement that in different way, the form is not needed in that case.
You have to give inputs the name they should have on posting and set the right action on the form. The name on the input determines what the key will be in the URL (since you use the GET method). Setting the action on the form will indicate where to send it to.
<form method="post" class="search-form" action="Products/index" method="GET">
<fieldset>
<input name="search_name" class="search home_input_search" placeholder="Поиск" type="search" />
<input type="submit" class="subm but_search" value="" />
</fieldset>
</form>
First of all there it'll be better to call controller paramter "searchName" instead of "search_name". That corresponds with code conventions.
Next, when you call Proudcts/index?search_name=somethink in browser you are initiating GET request. GET requests have no body and communicate with query parameters.
When you create new form and submit 'em to the server you are initiating POST request (by default). Post request has the body-section which contains request parameters.
Then we should start from View. If you want to use query-string you should explicitly create GET-form:
#using (Html.BeginForm("ControllerMethodName", "ControllerName", FormMethod.Get))
{
}
Next you should add name attribute to your input with the same name as in the controller method parameter:
<input class="search home_input_search" name="searchName" placeholder="Поиск" type="search" />
Or you can use HtmlHelper method to generate html:
#Html.TextBox("searchName", string.Empty, new Dictionary<string, object> { { "class", "search home_input_search" }, { "placeholder", "Поиск" } })
Finally you can have as many parameters as you need:
#using (Html.BeginForm("ControllerMethodName", "ControllerName", FormMethod.Get))
{
#Html.Label("Поиск")
#Html.TextBox("searchName", string.Empty, new Dictionary<string, object> { { "class", "search home_input_search" }, { "placeholder", "Поиск" } })
#Html.Label("Включая вложенные")
#Html.CheckBox("includeNested", true)
}

Passing data to a Controller method via POST

I have a 'Survey' page which is declared as follows:
#using (Html.BeginForm("Survey", "Home", new { questionList = Model.Questions }, FormMethod.Post))
{
<div class="survey">
<ol class="questions">
#foreach (Question q in Model.Questions)
{
<li class="question" id="#q.QuestionName">
#q.QuestionText<br />
#foreach (Answer a in q.Answers)
{
<input class="answer" id="#a.DisplayName" type="checkbox" /><label for="#a.DisplayName">#a.AnswerText</label>
if (a.Expandable)
{
<input type="text" id="#a.DisplayNameFreeEntry" maxlength="250" /> <span>(250 characters max)</span>
}
<br />
}
</li>
}
</ol>
</div>
<div class="buttons">
<input type="submit" value="Finish" />
</div>
}
When I'm stepping through my code, it hits the method I've set up to process their survey:
[HttpPost]
public ActionResult Survey( List<Question> questionList, FormCollection postData)
{
//Process Survey
}
However, when I step through I am finding that the variable questionList is null and the variable postData does not contain any data from the Form. Trying to access checkboxes via Request[a.Displayname also does not work.
Everything I've read indicates that this is the correct way to persist values from the Model to the submission method, and that I should be able to access the FormCollection this way.
What am I doing wrong?
You have to save questionList as a hidden field on the page. Non-primitive types do not get persisted simply by passing them in.
One way you can do that is
#Html.HiddenFor(m => m.Foo)
Or you could do it directly in HTML like this
<input type="hidden" name="Var" value="foo">
where m is your model.
The fact that the postData is empty is weird, since every input element with id inside a form tag should be passed with the POST request.
But the questionList won't be received that way, since its a list of complex class (not just a string or int), and the default ModelBinder (the thing that turns the HTTP Request Variables into parameters passed to the action method) don't support lists of complex classes.
If you want to be able to receive List you will have to implement your own binding mechanism with CustomModelBinder.
This article can help you implement it.
One problem is your checkbox and your textbox are not properly bound to your model.
You should be using #Html.CheckBoxFor and #Html.TextBoxFor

MVC 4 Clicking a Button to get a Partial Page

I am creating a page with a search property. The user will enter a number in the search field and hit the submit button. I need to be able to call a controller method in order to run the search code.
For now I am just trying to hit a partial page to just get some functionality in there. Below is the code I have so far. As of now nothing happens when I click the button. I hear Ajax was something to use so I have been playing with that a little. I am still learning the framework so bear with me.
<div class="span6 roundedCorners">
<div class="row-fluid Title">
<div class="span6">
Search Area
</div>
</div>
<div class="row-fluid individual">
<div class="row-fluid">
<div class="span4"><span class="pull-right fieldDescription">Number</span></div>
<div class="span8"><input /></div>
</div>
<div class="row">
<div class="span12" id="adminSubmitButton">
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "_adminDetails" }))
{
<button type="submit" class="btn btn-inverse">Submit</button>
}
</div>
</div>
</div>
Your form is empty, it only has a submit button. You will need to move your search button inside the form. Something like this:
Model
public class SearchModel
{
[Required]
public string Query { get; set; }
}
View
#model SearchModel
...
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "_adminDetails" }))
{
#Html.EditorFor(m => m.Query)
#Html.ValidationMessageFor(m => m.Query)
<button type="submit" class="btn btn-inverse">Submit</button>
}
<div id="_adminDetails"></di>
Note: Make sure you have an element with id _adminDetails
Your controller will have to take the model and perform the search. Example:
Controller
[HttpPost]
public ActionResult Index(SearchModel model)
{
//do something with your model (perform search)
return View(results);
}
Alright, I have it partially working now. When i click the button I am able to call the controller method using:
function adminButton()
{
$("#adminDetails").load("#Url.Action("ControllerMethod", "ControllerName")");
}
The #Url.Action helper allows me to call the method which returns a partial view. This is a step in the right direction. But from what I am reading I should be able to use the following Url helper instead of the #Url.Action:
"#Url("ControllerMethod", "ControllerName")/" + submitButton.Value
I have tried some variations and I am still doing some reading to figure out a solution. Is there a helper that would let me do this?
Thanks for the help guys. I did end up getting my problem solved friday evening. Basically what I did was load the partial page when the button was clicked through the help of JS/jQuery and the Razor #Url.Action() to call the controller method that returns a PartialView:
<script type="text/javascript">
function adminButton()
{
var link = "#Url.Action("ControllerMethod", "ControllerClass", new {
number = -1})";
var num = parseInt($("#number").val());
link = link.replace(-1, num);
$("#details").load(link);
}
</script>

Categories

Resources