I'm new to MVC.
I have a partial view with editable fields and not editable fields:
<li>
<b>
#Resource.Field1:
</b>
#model.Field1
</li>
<li>
<b>
#Resource.Field2:
</b>
#Html.TextBoxFor(sb => sb.Field2)
</li>
<input type="image" src="~/Resources/Images/DoSomething.png" border="0" alt="Submit" value="DoSomething" name="DoSomething"/>
The controller function:
[HttpPost]
[MultipleButton]
public ActionResult DoSomething(MyModel myModel)
{
DoSomethingToManipulateTheModel(myModel);
return PartialView("~/Views/MyPartialView.cshtml", myModel);
}
But I have a problem:
In the myModel object, that is passed the doSomething function, only the fields that are editable in the view are filled, all other fields are null. So I can't send the model back to the view because the view will only show the editable values.
Has anybody an idea how I can get all values back without making them all editable?
Store your data in Session, or use HiddenField in Razor.
Like this
#Html.HidddenBox(sb => sb.HiddenVariable)
Related
I am having trouble with a simple Visual Basic Code for MVC using Check Boxes.
I am trying to create a Form where the user could choose which Office Department will have access to a particular Document.
Here is the output in the browser:
The data gets displayed correctly from the Model to Controller to View.
However, I cannot get the clicked values from the View back to the Controller.
Here is the Model:
Public Class Department
<Required>
<Display(Name:="Department ID")>
Public Property DepartmentID As Integer = 1
<Required>
<Display(Name:="Department Name")>
Public Property DepartmentName As String = ""
<Required>
<Display(Name:="Department Image")>
Public Property DeptImage As String = ""
Public Property IsSelected As Boolean = False
End Class
Here is the View
<section class="checkBoxListFor">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Access Rights</h3>
</div>
<div class="panel-body">
#For Each oDept As Department In Model.DeptList
#<text>
#Html.CheckBoxFor(Function(m) oDept.IsSelected)
#oDept.DepartmentName
#Html.HiddenFor(Function(m) oDept.DepartmentID)
#Html.HiddenFor(Function(m) oDept.DepartmentName) <br />
</text>
Next
</div>
</div>
</section>
I have read an article here about NOT using a For Each Loop to display the collection of Form Controls since when you look at the generated HTML Code, the "name" will not be correct and hence it won't bind to the Controller when POST Back is called.
The problem is I do not know how to do it.
Any help is appreciated on how to properly implement this simple task.
Thanks!
Ok, I found the problem.
It is because of the
<fieldset>
</fieldset>
tag.
The checkbox collection loop is outside of these tags.
Although all of the fields and the Check Boxes are under the html helper "BeginForm"
the checkboxes loop is outside of the tag.
This is the reason why these checkbox's values were never passed back to the controller during post back.
I put the loop inside the tag and viola, they are now populated on the "POST" controller.
I am having multiple forms in one page and that page inherits one single model.Every form submission requires a common value. So, common value is stored in hidden field. The hidden field is kept global i.e outside of all the forms but my problem is whenever I submit form, that hidden field is coming to be empty.The hidden field is #Html.HiddenfieldFor(m=>m.FkId) and this FkId is of string type proprty in model i.e public string FkId{get;set;} .Can somebody please guide me how to handle this situation. If I keep hidden field in one of the forms then , it is coming in controller but only for that form submission where I have kept it. But I want that property to be set once and can use in all the form submissions.Please help me. How can I sort out this problem
Some related code
<div id="tabs">
<ul>
<li>Nunc tincidunt</li>
<li>Proin dolor</li>
<li>Aenean lacinia</li>
</ul>
<div id="tabs-1">
#using (Ajax.BeginForm("Evaluation","SaveTab1"{new AjaxOptions { Onsucess= "DisplayMessage" }))
{
#Html.HiddenFieldfor(m=>m.fkID)
<input type="Submit" id="btnTab1" value="Submit" onclick="CheckUser();"/>
}
</div>
<div id="tabs-2">
#using (Ajax.BeginForm("Evaluation","SaveTab2"{new AjaxOptions { Onsucess= "DisplayMessage" }))
{
#Html.HiddenFieldfor(m=>m.fkID)
<input type="Submit" id="btnTab2" value="Submit" />
}
</div>
<div id="tabs-3">
#using (Ajax.BeginForm("Evaluation","SaveTab3"{new AjaxOptions { Onsucess= "DisplayMessage" }))
{
#Html.HiddenFieldfor(m=>m.fkID)
<input type="Submit" id="btnTab3" value="Submit" />
}
</div>
</div>
<script type="text/javascript">
function DisplayMessage(Json)
{
alert( $("#fkID").val(Json.hdn));
// and Alert is showing the value
$("#fkID").val(Json.hdn);
}
</script>
In the Controller I have:
public ActionResult SaveTab1(Model obj)
{
tbl ob =new tbl();
ob.FkId=Obj.fkID;
// after saving, I return
return json(new{hdn=Obj.fkID})
}
public ActionResult SaveTab2(Model obj)
{
tbl ob =new tbl();
ob.FkId=Obj.fkID;
//after saving, I return
return json(new{hdn=Obj.fkID})
}
Similar for tab three, but unfortunately the hidden filed only comes for first form submit. Then I return value to view by json and again set the hidden field property but then it comes null for second form.Please help
First of all, your View does not inherit the Model, it is strongly-typed to the type of your Model. These two are completely different.
But, to answer your question, there's no such a thing as a global hidden field. Fields are not variables. If you want a field to be posted to your Controller, you need to put it inside the form. If you have multiple forms in your View, then you'll have to put the same hidden field inside all the those forms. So, you need to put #Html.HiddenFor(m => m.FkId) inside all the forms in your View.
UPDATE: By the way, it's not Html.HiddenFieldFor, it's Html.HiddenFor.
I have solved the problem. Instead of taking same field in all the forms which was not working, I have taken a unique and different Hidden field properties and after on seperated success function of each form and set the every hidden field a value in success method.
When I post back to the server when tab2 is active viewModel.FirstName is null in the action method. How do you tell the modelbinder that it should take #Html.EditorFor(m => m.FirstName) from tab2 when that tab is active? Everything works fine for tab1.
jQuery hide() and show() are used for switching between tabs.
Controller
[HttpPost]
public ActionResult Index(MyViewModel viewModel)
View
<div id="tab1">
#Html.EditorFor(m => m.FirstName)
</div>
<div id="tab2">
#Html.EditorFor(m => m.FirstName)
</div>
It sounds like you have both FirstName input fields inside the same form.
Something like:
<form>
<div id="tab1">
#Html.EditorFor(m => m.FirstName)
</div>
<div id="tab2">
#Html.EditorFor(m => m.FirstName)
</div>
</form>
When you post this, the form is submitted as:
FirstName=valueFromField01&FirstName=valueFromField02
From the behavior you are describing, it seems that once the model binder sets the FirstName field in your MyViewModel, it ignores the second one (but I'm not really sure about that).
Solutions:
Rather than have a form with different tabs inside of it, have a form inside each tab. This will ensure you only have one FirstName inside a form.
Update the model so that you get both fields. You would need to use an array of string: string[] FirstName.
Update:
Instead of updating your ViewModel, it might be easier to simply add another parameter to your action method so you can get both FirstName values and then figure out which one was actually provided:
public ActionResult Index(MyViewModel viewModel, string [] FirstName).
Then you can have logic in your action method to set the FirstName in your viewModel:
if(!string.IsNullOrEmpty(FirstName[0]))
{
viewModel.FirstName = FirstName[0]
}
else if(!string.IsNullOrEmpty(FirstName[1]))
{
viewModel.FirstName = FirstName[1];
}
You could achieve that disabling the duplicated name form elements. By default, disabled form elemnts will not be passed to the request, and your Controller problably will receive the name corectly from the tab2 when it is shown active.
So. here follows one example
$('#tab1')
.hide()
.find('input[name="FirstName]"')
.prop('disabled',true);
$('#tab2').show()
.find('input[name="FirstName]"')
.prop('disabled',false);
Latter I suggest you should wrap this behaviour inside a function.
Hope it helps.
I use an ajax form for removing items from a list. The first time I submit something, it works but the second times, the reference of the item submitted is not correct: it is the first reference that is still used.
Here is my ajax form:
<div>
<table>
#foreach (var item in Model.ProjectTechnology)
{
<tr>
<td>#Html.DisplayFor(m => item.TechnologyID) </td>
<td>#using (Ajax.BeginForm("RemoveLinkedTechnology", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "AddedTechnologies" })) {
#Html.Hidden("projectID", item.ProjectID)
#Html.Hidden("removedTechnologyID", item.TechnologyID)
<input type="submit" value="Suppr" />
}</td>
</tr>
}
</table>
</div>
Here is the action in my controller:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
// some code here...
}
Example:
Lets say I proceed the submitting like this: first submit: AA; second submit: BB.
For the first call: removedTechnologyID contains AA.
For the second call: removedTechnologyID still contains AA.
Any idea?
Thanks
I suspect that in your controller action you are returning a partial view which updates the contents of the <table> you have shown. Now since Html helpers such as Hidden or TextBox first look for values in ModelState before binding and then in the model what happens is that #Html.Hidden("removedTechnologyID", item.TechnologyID) sees that there is a removedTechnologyID="AA" in the model state and completely ignores your model value which is item.TechnologyID. So if you have looked at the DOM after the first AJAX request you would have seen that all hidden fields have the old values inside them.
To fix this you have 3 possibilities:
Clear the item in model state in your controller action:
[HttpPost]
public ActionResult RemoveLinkedTechnology(int projectID, string removedTechnologyID)
{
...
ModelState.Remove("removedTechnologyID");
ModelState.Remove("projectID");
return View(...);
}
Don't use helpers to generate the hidden fields:
<input type="hidden" name="projectID" value="#item.ProjectID" />
<input type="hidden" name="removedTechnologyID" value="#item.TechnologyID" />
Write a custom Html.Hidden helper which will first use the values in the model before looking at modelstate (out of scope for this answer)
Suppose I have a simple search form with a textbox. And upon submitting the form I send the contents of the textbox to a stored procedure which returns to me the results. I want the results to be displayed on the same page the form was, except just below it.
Right now I'm doing the following but it's not working out exactly the way I want:
"Index" View of my SearchController
#using (Html.BeginForm("SearchResults", "Search", FormMethod.Post, new { #class = "searchform" }))`{
<fieldset>
<legend>Name</legend>
<div class="editor-label">
#Html.Label("Search")
</div>
<div class="editor-field">
#Html.TextBox("Name")
</div>
<input type="submit" value="Search" class="formbutton" />
</fieldset>
#{ Html.RenderPartial("SearchResults", null);
This is my "SearchResults" View:
#model IEnumerable<MyProject.Models.spSearchName_Result>
<table>
#foreach (var item in Model)
{
<tr>
<td>
#item.Name
</td>
</tr>
}
</table>
This is my Controller:
// GET: /Search/SearchResult
[HttpPost]
public ActionResult SearchResult(FormCollection collection)
{
var result = myentity.spSearchName(collection["Name"]);
return PartialView("SearchResults", result);
}
I can only seem to get the results to display on an entirely new page (not being embedded as a partial view), or I get an error when I load the search page because there are no results (since I hadn't searched yet).
Is there any better way to achieve what I'm trying to do? I feel like I'm going against some of the best practices in MVC.
You could return the results in a ViewData object then only show on the view it if is not null.
Very similar to this question MVC 3 form post and persisting model data
For this instance it looks like you are not passing the results to your partial view. Try this?
#{ Html.RenderPartial("SearchResults", Model.Results);
Since you are not persisting your search information using a model, the search information will be lost when the search form is posted.
Given your design and stated goal, it would be best to convert the form in your Index view into an Ajax form, then your controller can send your partial view back to populate a div below your Ajax form.
counsellorben