Still kind of new to MVC, so please bear with me. I'm trying to grab some dynamically generated HTML. In this case, list items in my notifyList. I plan on looping through each one in the controller and adding them as database entries. Any help is appreciated, thanks.
View
#model _BaseViewModel
// The form it's within...
#using (Html.BeginForm("Create", "Leaf", FormMethod.Post, new { id = "createForm" }))
<div class="editor-label bottom-area bottom-header">
Notification List:
</div>
<div class="editor-field bottom-area">
<ul id="notifyList"></ul>
</div>
Controller:
[HttpPost]
public ActionResult Create(_BaseViewModel model)
{
// Some loop here
// get html here
db.UserItems.AddObject(model.user);
db.SaveChanges();
//
return RedirectToAction("Index");
}
As far as I understood, you use jQuery to fetch <li/> elements into notifyList. What you need to do here is to generate a hidden input as well. Sample:
$("#btnAppend").click(function() {
for(var i = 0; i < 4; i++) {
var _val = "Foo " + i;
var $li = $("<li/>").text(_val);
var $hidden = #("<input/>").
attr("type", "hidden")
attr("name", "foo").
val(_val);
$hidden.appendTo($li);
$li.appendTo("#notifyList");
}
});
This code will generate following output inside your DOM:
<ul id="notifyList">
<li>Foo 0<input type="hidden" value="Foo 0" name="foo" /></li>
<li>Foo 1<input type="hidden" value="Foo 1" name="foo" /></li>
<li>Foo 2<input type="hidden" value="Foo 2" name="foo" /></li>
<li>Foo 3<input type="hidden" value="Foo 3" name="foo" /></li>
</ul>
When you make a http form post, you can grab the values by the below controller action implementation:
public ActionResult Index(string[] foo) {
foreach(var item in foo) {
//Work with each individual item
}
//continue your code
}
it doesn't work this way. html only exists in the view. the controller has no concept of html (not should it). data sent to the controller comes in 1 of types (GET, POST). there are others, but these are the main to.
get is typically associated with the querystring www.domain.com/mypage.aspx?key=value
where post is the input values from form
<form action="mypage.aspx" method="post">
<input name="key" value="value"/>
<input type="submit" value="click me"/>
</form>
So adding items to a html list won't provide any meaning to the controller. javascript and ajax provide more options on how the data gets sent to the server, but the data is sent, not the markup. and the data is sent as key value pairs.
Related
I have a model with say 10 properties. A, B, C and so on...
Property A is an array.
For each value in array I generate one tag like this:
<div class="col-sm-10 row">
#foreach (var item in Model.A)
{
<div class="col-sm-1 right-buffer">
<i class="" aria-hidden="true">#item.Text</i>
</div>
}
</div>
When user clicks on some link I should redirect it to the same page, but with Some model property changed. For example:
Current url: my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=
with model ?name=Alex&age=20&from=fr&CurrentA=
If user clicks on <a> with text foo it should be redirected on my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=foo
then is clicks on <a> with text bar and it should be now redirected on my/controller/someaction?name=Alex&age=20&from=fr&CurrentA=bar
So entire query string (except one parameter) should be preserved to send current model state to server while I want to set one value and redirect it to the same page but with new value.
Eventually, it should acts like postback with one extra value setted to model
Is it possible or I should use JS and perform everything myself?
Manually i solved it like this:
First, create hidden fields for every property in model:
<form asp-controller="search" asp-action="index" method="get" role="form" id="searchForm" asp-antiforgery="false">
<input asp-for="SessionId" type="hidden" name="sessionId" value="#Model.SessionId" />
<input asp-for="Quantity" type="hidden" name="quantity" value="#Model.Quantity"/>
<input asp-for="SortField" type="hidden" name="sortField" value="#Model.SortField"/>
<input asp-for="IsAscending" type="hidden" name="IsAscending" value="#Model.IsAscending" />
<input asp-for="Offset" type="hidden" name="offset" value="0" />
...
</form>
Then, use JS to replace value in hidden field and then submit form. Values from inputs will be autimatically converter in query string, so everything works fine:
function sortDocuments(sortField) {
var sField = document.getElementById('SortField');
var isDescending = document.getElementById('IsAscending');
if (sField.value === sortField) {
if (isDescending.value.toUpperCase() === 'FALSE') {
isDescending.value = 'TRUE';
} else {
sField.value = 'rank';
isDescending.value = 'FALSE';
}
} else {
sField.value = sortField;
isDescending.value = 'FALSE';
}
document.getElementById('searchForm').submit();
}
Not very elegant, but it does its job.
I have a view with a list of items. Each item have a textbox and a button.
What is the best way to get the item id of the button clicked in the controller action?
I need the value from the associated textbox in the controller action, so I do not think I can use action links.
There are a number of ways to do this. Some use javascript, others don't. I personally prefer to NOT use javascript for basic functionality, unless your design is itself javascript based (such as using ajax)
For instance, you can have each item be wrapped in it's own form, with a different submit value. Just be careful not to nest forms, as that's not valid HTML.
For instance:
#using(Html.BeginForm("MyAction", "MyController", new { id=1 })) {
<input type="submit"/>
#Html.TextBox("TheValue", "One")
}
#using(Html.BeginForm("MyAction", "MyController", new { id=2 })) {
<input type="submit"/>
#Html.TextBox("TheValue", "Two")
}
public ActionResult MyAction(int? id, string TheValue) {
// if they click the first one, id is 1, TheValue = "One"
// if they click the second one, id is 2, TheValue = "Two"
}
this answer is using jquery - If you do not know how to add jQuery to your view or just simply do not want to use it let me know and I can re-work the answer
I would do something like this
<li>
<input type="text" id="1" name="1" class="whatever" />
<input type="button" value="CliCk mE" class="myButton" />
</li>
<li>
<input type="text" id="2" name="2" class="whatever" />
<input type="button" value="CliCk mE" class="myButton" />
</li>
<input type="hidden" id="myHiddenText" name="myHiddenText" />
then add this jQuery:
<script>
$(function(){
$('.myButton').click(function(){
// this is how to get the closest textbox
// you didn't show your html , maybe .prev() or .next()
var textValue = $(this).closest("input[type='text']").val();
// this sets your hidden field with the value from desired textbox
$('#myHiddenText').val(textValue);
});
});
</script>
now when you submit this form to server you can just use myHiddenText on the server
public ActionResult Index(string myHiddenText = "")
{
// hidden fields in the HTML form automatically get passed to server on submit
return View();
}
The best option would be to use jquery but if you only want to use c# I would suggest the following:
I imagine you are using some sort of repeating statement (for or foreach) to generate your textboxes, so what I would do is create a form inside that foreach this new form would contain your textbox, and foreach item you would pass the textbox id to the form submit.
something like this pseudo code:
foreach(item in array){
<form action="address/"#item.Id>
<input type="text" value=""/>
<input type="submit" value="submit textbox"/>
</>
}
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
I'm having following view page,
#using (Html.BeginForm())
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1"><b>Associate Id : </b>#item.Var_AssoId </label>
<label class="Detail1"><b>Vertical :</b>#item.Var_Vertical</label>
<label class="Detail1"><b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom </label><br /><br />
<label class="Detail2"><b>Associate Name :</b>#item.Var_AssociateName</label>
<label class="Detail2"><b>Account Name :</b>#item.Var_AccountName</label>
<label class="Detail2"><b>Visa ValidDate :</b>#item.Dt_VisaValidTill</label><br /><br />
<label class="Detail3"><b>Grade HR :</b>#item.Var_Grade</label>
<label class="Detail3"><b>Project Name :</b>#item.Var_Project_Desc</label><br />
}
<h2> Response Details</h2><br />
Supervisor Response :<input type="radio" class="radi"
name="radio" value="yes" onclick="javascript:Getfunc(this.value);">Yes
<input type="radio"
name="radio" value="no"
onclick="javascript:Getfunc(this.value)">No
<div id="es"></div>
<input type="submit" id="insert" value="Submit"
name="Submit" onclick="javascript:InsertDetails(item);"/>
</fieldset>
}
I want pass all the values of this view page to the controller as parameters for inserting these values into the new table.How can i Achieve this?
Use #Html helpers for your controls.
Have a look at this blog entry from Scott Gu. It's about MVC2 but still applies to MVC4.
For a more concrete example, have a look at this question regarding #Html.RadioButtonFor().
Also, I would recommend hooking your events using jquery instead of inline onclick= html attributes.
<script type="text/javascript">
$("form radio").click(function(){ // or whatever selector you need
Getfunc($(this)[0].value);
});
</script>
Finaly, you will need to make sure your #Html.BeginForm posts to an [HttpPost]-decorated action on your controller that takes your Model as parameter.
What is the Problem in Existing code ?
There is no Input Type Text Control in the form and that's the reason information is not being sent to server. TextBox like controls forwards the data for sending the information to Controller Action Method.
Corrective Action
Let's say TextBox is not Required in you case. Then, you can place Hidden Fields for those View Model Properties which are required to be sent to Controller Post Action method.
Example
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post))
{
<fieldset class="fs">
#foreach (var item in Model.lstTravelReadyEntities)
{
<label class="Detail1">
<b>Associate Id : </b>#item.Var_AssoId
</label>
#Html.HiddenFor(i=> item.Var_AssoId) //Added Hidden Field to send this to server
<label class="Detail1">
<b>Vertical :</b>#item.Var_Vertical</label>
#Html.HiddenFor(i => item.Var_Vertical) //When post this Hidden Field will send
<label class="Detail1">
<b>Visa ValidFrom :</b>#item.Dt_VisaValidFrom
</label>
#Html.HiddenFor(i => item.Dt_VisaValidFrom)
<br />
}
<h2>
Response Details</h2>
<br />
</fieldset>
}
For explaining point of view, I excluded some of the controls. Now, You can add Hidden Fields for those Properties which are required to be sent to Action Method.
Also you should use View Models instead of Passing Individual parameter to Action Method.
Hope this will help you.
Hi try like this,
View
#using (Html.BeginForm("SaveAudit", "Controller", FormMethod.Post)
{
}
Controller
[HttpPost]
public ActionResult SaveAudit(AuditModel model, FormCollection collection)
{
}
I try to bind an OrderedDictionary to a view but when the post method gets invoked the Dictionary is always empty.
Here is my code:
[HttpGet]
public ViewResult Edit(string username, string password)
{
Xml test = new Xml(#"c:\Users\pc\Desktop\xml - Copy.xml");
XmlNode userNode = test.GetUserNodeByUsernameAndPassword(username, password);
User user = new User();
user.BindData(userNode);
return View(user.user);
}
[HttpPost]
public ViewResult Edit(OrderedDictionary attributes)
{
return View(attributes);
}
And here is the view:
#using (Html.BeginForm("Edit", "Users")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<p>
<input type="submit" value="Save" />
</p>
#{int counter = 0;}
#{string name = "";}
#foreach (DictionaryEntry attribute in Model)
{
{ name = "[" + counter + "].key"; }
<input type="hidden" name=#name value=#attribute.Key />
#attribute.Key #Html.TextBoxFor(m => attribute.Value)
counter++;
<br />
}
</fieldset>
}
And the result Html looks like this is:
<input type="hidden" value="Username" name="[0].key">
Username
<input id="attribute_Value" type="text" value="Anamana" name="attribute.Value">
So the content of the OrderedDictionary appears fine in the view but when I make a post back the binding isn't working and the directory remains empty.
Concept
To bind a dictionary you have to change the name attribute in the html input tag. Something like this:
In your controller:
[HttpPost]
public ActionResult Edit(IDictionary<string, string> attributes)
{
}
In your HTML:
<input type="text" name="attributes[0].Key" value="A Key" />
<input type="text" name="attributes[0].Value" value="A Value" />
<input type="text" name="attributes[1].Key" value="B Key" />
<input type="text" name="attributes[1].Value" value="B Value" />
The attributes name should be before the index [0] on ther name attribute, because your action expect it.
Tips
I would use the HiddenFor and TextBoxFor HTML Helper of the Asp.Net MVC.
#Html.HiddenFor(model => model[i].Key)
#Html.TextBoxFor(model => model[i].Value)
And it will render in the format that the asp.net mvc will understand and get it working.
For more samples about databind take a look at this link.
Meantime I have found the solution.
I can pass an OrderedDictionary to the view page.
It process it by the following Razor code:
#model System.Collections.Specialized.OrderedDictionary
(...)
#{int counter = 0;}
#{string name = "";}
#foreach (DictionaryEntry attribute in Model)
{
{ name = "[" + counter + "].key"; }
#Html.Hidden(name, attribute.Key)
{name = "[" + counter + "].value";}
#attribute.Key #Html.TextBox(name, attribute.Value)
counter++;
<br />
}
The result HTML's structure fits to the samples which is found in a book, the values from the dictionary appears fine on the page.
After POST was invoked the POST handler function gets the modified values in a Dictionary.
[HttpPost]
public ViewResult Edit(Dictionary<string, string> attributes)
{}
I don't know why but I can't use OrderedDictionary here.