FormCollection modify keys - c#

How can I override keys in FormCollection (I need this because I have a property bound to multiple CheckBoxes in a View)? I did try this when a post back is in Action:
formCollection["DecisionReasons"] = formCollection["DecisionReasons"].Replace(",false", "").Replace("false,", "").Replace(",","|");
...but when I UpdateModel only the first value is updated in the model (in my model I have a DecisionReason string).
Do I need a ModelBinder (how can I do that?) or is there another way to do this?

Part of View
<div style="width:300px;height:250px;overflow:auto;">
#foreach (var a in (IEnumerable<SelectListItem>)ViewBag.AllDecisionReasons)
{
#Html.CheckBox("DecisionReasons", a.Selected, new { value = a.Value })
<label>#a.Text</label><br />
}
#Html.ValidationMessage("DecisionReasons", (string)Model.DecisionReasons)
if i check more than one checkbox in my View my Model property wich is string is updated with only one value example (if in View i check 2 checkboxes my Model will be updated with first value, so i need that Model property have value "valu1,valu2" and so on.)
sorry for my bad english.

I commented, above, asking for more details, but I get the impression that you're using checkboxes to represent the individual values in a Flags enumeration.
The default model binder doesn't handle mapping flags in this way, but I found a custom model binder that does in this article.
Edit:
OK, I see from your update (which would be better if you added it to your question, rather than posting it as an answer), your model has a comma-delimited string property containing each of the selected DecisionReasons.
I suggest that you consider the use of a ViewModel. The ViewModel is an abstraction of your model that is tailored for the way in which you present it in your view.
You can derive your ViewModel from your Model class, to reduce the amount of work. Consider this (untested) code:
public class MyModel
{
public virtual string DecisionReasons { get; set; }
}
public class MyViewModel : MyModel
{
public string[] DecisionReasonValues { get; set; }
public override string DecisionReasons
{
get
{
return string.Join(",", DecisionReasonValues);
}
set
{
DecisionReasonValues = value.Split(',');
}
}
}
Use MyViewModel as the model for your View and use DecisionReasonValues to render the checkboxes, not DecisionReasons. ASP.NET MVC will populate DecisionReasonValues from your checkboxes but you can access them as a comma-delimeted string through the overridden DecisionReasons property.

Related

Using ViewModel to setup MVC Form but want to bind to object of the viewmodel in the postback. Is this possible?

Just need to know if this is possible to do or what exactly is standard practice in MVC as this is my first large scale MVC application.
So I've got a form I want the user to be able to edit and on that form page to pull up all the necessary data I need I'm bringing in a viewmodel,
public class Tier2IssueFormViewModel
{
public Tier2IssueDTO Tier2Issue { get; set; }
public IEnumerable<SelectListItem> VersionList { get; set; }
public IEnumerable<SelectListItem> BugList { get; set; }
public IEnumerable<SelectListItem> IssueStatusList { get; set; }
}
Then once I've finished collecting the form data from the user using things like,
#Html.TextBoxFor(m => m.Tier2Issue.Tier2Notes, new { #class = "form-control"})
#Html.DropDownListFor(m => m.Tier2Issue.FishbowlVersion, Model.VersionList, "Select Application Version")
#Html.HiddenFor(m => m.Tier2Issue.ID)
I want to post back to this action with the following signature for my model to bind to,
[HttpPost]
[Route("Issues/{id}/Edit")]
public ActionResult EditIssue(Tier2IssueDTO model)
{
...
// Update DB with the DTO model
...
}
But so far nothing really gets bound to this object. I thought the model binder might be smart enough to pair the two but I'm guessing this logic is incorrect. So I'm currently doing a workaround by using this,
[HttpPost]
[Route("Issues/{id}/Edit")]
public ActionResult EditIssue(Tier2IssueFormViewModel model)
{
...
// Get Tier2IssueDTO values from viewmodel
// Update DB with the DTO model
...
}
I mean it works, but it seems odd to me that you would model bind to a view model. Is this standard practice or is there a way to bind to an object contained within the viewmodel directly?
This will not work because the input text box names are differnt from the model inside your action, ex: the text box will have a name Tier2Issue.Tier2Notes while the model parameter in your action is expecting a property name Tier2Notes only without the Tier2Issue prefix.
You can overcome this issue by either making the model the same as the action parameter or give an explicit name and value to the text box, ex:
#Html.TextBox("Tier2Notes",Model.Tier2Issue.Tier2Notes, new { #class = "form-control"})
This should make it work
You have the right of it. It often seems pretty repetitive to have a viewmodel, dto and entity that all seem to have the same properties, but they all do different jobs an usually end up diverging a bit. A dto could act as a viewmodel, but it's a square peg in a round hole. If you're not using automapper to map these objects to one an other (this may be opinion baesed but it's broadly shared) - then use automapper to save you mindless keystrokes.

Reusing same dropdownlist for multiple fields and populating with db value mvc4

I have the same drop down list for 30 fields on a view. Is there any way to use the same selectlist in the viewbag for all 30 with the default value or do I have to have 30 separate viewbag items with the same select list and default value?
I add the selectlist to the viewbag in my contoller edit method:
ViewBag.Pulmonary_01 = new SelectList(PulmonaryList(), "Text", "Value", admission.Pulmonary_01);
The fields are Pulmonary_01 through Pulmonary_30. In my view I use:
#Html.DropDownList("Pulmonary_01", String.Empty)
If I use ViewBag.Pulmonary instead of the _01 it doesn't match it on save. Two obstacles are matching a general "Pulmonary" view and to all the fields so they save and the other is having the selected value. I don't see a way to avoid having 30 ViewBags.
This is not a problem at all. You can use the same view bag as many times as you want, you just have to cast the ViewBag into a SelectList. So for example if you have a model like:
public class Pulmonary
{
public int Pulmonary_01 { get; set; }
public int Pulmonary_02 { get; set; }
public int Pulmonary_03 { get; set; }
and in your action you create a viewbag like this:
ViewBag.Pulmonaries = new SelectList(PulmonaryList(), "Text", "Value");
you should be able to do the following in the view:
#model PulmonaryClassFullNamespace.Pulmonary
// Form declaration
#HtmlDropDownListFor(model => Model.Pulmonary_01, (SelectList)ViewBag.Pulmonaries)
#HtmlDropDownListFor(model => Model.Pulmonary_02, (SelectList)ViewBag.Pulmonaries)
//.....
// Form closure
The only thing you really have to watch is that ViewBag property name does not match any model property names. For example if you name your ViewBag.Pulmonary_01 and you have a model property called Pulmonary_01 then this will cause mapping issues because these values will be overwriting each other in form collection.

Dropdowns in strictly typed views

I'm creating a C# application using MVC 4, LINQ to SQL, and Razor Syntax.
I have created a class that gets the contents of a given row in the db based on a requested id.
I have made a controller that has a get and post handler. I created a strongly-typed view based on one of the model classes, and everything works great. Data is retrieved and displayed in the form. Data can be updated and submitted.
The problem is the dropdowns. I don't want it to show a textfield for the id. I want the dropdowns. I have about five dropdowns, all to be generated from the database. I've created models to create them.
I can use ViewData or ViewBag to pass in the dropdowns with no problem. But then, how do I select the selected option when the user loads the page?
The "model" in MVC is supposed to model the page, not your data. If you have dropdowns on your page, then you should have a collection of some kind (likely a List<T>) on your model that represents the choices, along with another property that represents the selected value. This property will be used to populate the initial value of the dropdown as well as send the selected value back up to the controller.
I would recommend avoiding ViewData or ViewBag in favor of a ViewModel.
A ViewModel is essentially a hybrid Model that aggregates all of the data that your View needs into a single entity. Rather than typing the View to a Model and passing the additional information needed by your View that is not in the Model in ViewData or the ViewBag you have everything you need in the Model that your View is typed to.
In your case the ViewModel might look something like this:
public class MyViewModel
{
public DropDown1 DropDownA { get; set; }
public DropDown2 DropDownB { get; set; }
public Model ModelData { get; set; }
}
public class DropDown1
{
public int SelectedValue { get; set; }
public List<T> DropDownValues { get; set; }
}
public class DropDown2
{
public int SelectedValue { get; set; }
public List<T> DropDownValues { get; set; }
}
Your View would by typed to MyViewModel. At this point, setting the data source of the drop downs to the drop downs in your ViewModel and setting the SelectedValue would be trivial.

Sending IEnumerable to a view that already contains a model

This is the view:
#model tgpwebged.Models.sistema_DocType
...
this model is an entity used with textBoxFor and others html helpers
This is the controller.
public ActionResult AdminSettingAddTipo()
{
IEnumerable<string> indices;
using (tgpwebgedEntities context = new tgpwebgedEntities())
{
var obj = from u in context.sistema_Indexes select u.idName;
indices = obj.ToList();
}
return PartialView(indices);
}
I have all I need here, I am using a model to create with the view so I am not allowed to send ´indices´ as a model because it´s not allowed to have 2 models in one view.
I don´t want to use ´Tupe´ now a parent view. I just want to know how is the best way to send my IEnumerable to the view.
I was thinking of ViewBag for the last option but I am avoiding ViewBag.
thanks
ViewBag is not a good choice. Create ViewModel using your list and your current Model:
public class YourViewModel
{
public sistema_DocType Type { get; set; }
public IEnumerable<string> Indices {get;set;}
}
Hope,it will help.
If you don't want to use ViewBag for whatever reason, you could create a Model specifically for the view that contains the info from the old model and the new indices you want. This is a common pattern in MVC development. You can even have the ViewModel be a Decorator for your current Model.
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
Use strongly defined where you can, apply this to a model and send that model:
Model
public class MyModel{
public List<sistema_Indexes> indecies {get;set;}
}
Controller
MyModel model = new MyModel();
model.indecies = context.sistema_Indexes.Select(u=> u.idName).ToList();

MVC3 strong typed model with multiple inputs

How can I have multiple inputs in a page all feed into a list of my model where the model is defined as
public class MatrixSet
{
List<MatrixPoints> matrixPoints { get; set; }
}
public class MatrixPoints
{
double x { get; set; }
double y { get; set; }
}
I am not sure what to use in the view to have say, 4 input fields which all input matrix points and then when posted the controller will have the model of type matrixset which will contain a list of the matrix points entered in the view. I know how to do this without passing the model but I am trying to adhere to best practice methods. Can I just have each input field be #Html.TextBoxFor() and then it will just fill a list of MatrixPoints in MatrixSet assuming that at the top of my view I am using #model Models.MatrixSet?
Found the answer:
#Html.TextBoxFor(model => model.matrixPoints[0].x)
#Html.TextBoxFor(model => model.matrixPoints[0].y)
In this regard you can add items to your model objects iteratively and dynamically while still holding the entire model when the form is posted and retaining the validation from the defined model.
You have to look for binding collection to View and later when you post form all collection get collected in ActionResult.
This is the link that help you
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
It works for me.
Thanks.

Categories