how to pass entire model (with data) from view to controller? - c#

I don't know, it may be silly question but now I trying to find the way to solve this. I need return entire model information (data) to controller even though some of the model properties are not using in the view. but I need them in controller action. example id, lable value.
Example
<div class="col-md-6">
#Html.LabelFor(model => model.AbstractTitleInEnglishLabel,
Model.AbstractTitleInEnglishLabel, new { #class = "control-label mandatory" })
</div>
from above first time I am able to see label with property value like Abstract Title (in English). after submitting to controller I am not getting that value in controller model.. If return to same view from controller.
I can see only property namel ike this AbstractTitleInEnglishLabel, not its value. That means value of property not storing in the model when passing to controller.
[HttpPost]
public ActionResult Index(MeetingAbstract meetingAbstract)
{
if (!ModelState.IsValid)
{ // re-render the view when validation failed.
return View(meetingAbstract);
}
}
How to handle this without using #Html.HiddenFor?. because I have lots of lables I want show.

I think, to my best understanding of your needs from the question, you may have to add Data annotations on your models.
using System;
using System.ComponentModel;
namespace MyProject.Models
{
public class MyModel
{
[DisplayName("Abstract Title")]
public string AbstractTitleInEnglish { get; set; }
}
}
Data annotation ([DisplayName("Abstract Title"]) will serve as a display text for your label. And when you use your helper method like below, label text will be displayed with "Abstract Title" regardless of post or get.
You have to use your helper method like this:
#Html.LabelFor(model => model.AbstractTitleInEnglishLabel, new { #class = "control-label mandatory" })

An HttpPost action will put whatever properties you give it into meetingAbstract. If you want to pass extra properties back to the View you'll have to get them from the database. That means you need the ID or something to select the correct row. If you have the ID, then you can do
meetingAbstract = db.MeetingAbstracts.Find(meetingAbstract.id);
return View(meetingAbstract);

Html.LabelFor does not create an input control which is required to post data back to the controller. It makes me wonder why you need those back in the post method. Have you looked into using the UpdateModel method in the post method which applies properties received in the post to the object you pass to this method, while leaving other properties unchanged. So you can get the object from your database and call UpdateModel to just update the values gotten back.
If that's not the case then you will have to generate hiddens to get the property values back.

Related

Changes to the model object not passing back to the controller

I'm loading the model to view and display it just fine. Then I make the changes to one of the fields and send it back. According to the break-point, I'm hitting the right action method but the model that's passed in contains no changes.
I suspect that I've unbound controls in the view. I've tried both the below, same problem both times.
#Html.TextBoxFor(bike => bike.Color)
<input type="text" value="#Model.Color" />
Am I not binding it correctly? How should I do this?
The controller being hit with break-point looks like this. Note that the bike that's passed in contains no changes according to the intellisense. If I make the change manually in VS, they are stored to the DB.
public ActionResult BikeStore(Bike bike)
{
...
return RedirectToAction("Bikes");
}
The model is Code First generated.
public partial class Bike
{
[Key]
public Guid Id{get; set;}
[Required]
[StringLength(999)]
public string Color { get; set; }
}
The submitting is done using this.
#Html.ActionLink("Submit", "BikeStore", "Home", #Model, null)
But if I do the following, it works, as in - the addition comes in to the controller. Not the actual contents of any of the controls on the page, though. So I'm very sure those are not bound and I can't figure out why or how to make them.
#Html.ActionLink("Submit", "BikeStore", "Home", new Bike
{
Id = Model.Id,
Color = Model.Color + "!"
}, null)
The submit action is wrong. You're passing #Model but this will be the model as it is when the view is rendered. You should be using a form with a submit button. This will bind the user edited values to the model on post.
#using (Html.BeginForm("BikeStore", "Home", FormMethod.Post)
{
// your inputs
// ...
<input type="submit" value="Submit">
}

MVC Send back model properties after POST

I have a Model that I send to the view in a GET method and is bounded successfully to TextFor and ListFor's
e.g.
#Html.ListBoxFor(x => x.MultiChoice, new MultiSelectList(Model.property, "Id", "Name"), new { multiple = "multiple", #class = "multiselect" })
When the user submits the form, the Model is successfully passed back to the POST action method with its properties.
[HttpPost]
public ActionResult POST(Model quiz)
{
string Q1 = quiz.Q1 // = will equal what the user has put in. good
return View("Quiz", quiz);
}
However, when the Model (quiz) is returned to the view, the properties inside the quiz model are NULL, how do I retain the properties that come through to the POST method?
** Edit **
The GET Method
[HttpGet]
public ActionResult Quiz()
{
try
{
Quiz quiz = new Quiz();
// Of course, I could do this in the constructor of the model..
InitialiseQuiz(Quiz);
return View("Quiz", quiz");
}
catch (Exception ex)
{
}
}
Thanks
If I understood well, when you do this:
#Html.ListBoxFor(x => x.MultiChoice, new MultiSelectList(Model.property, "Id", "Name"))
the Razor will create a <select> tag with x.MultiChoice values as selected options. BUT, nowhere will be persisted the Model.property values (as it may be a collection, right?).
So, when you do the POST, you will only send the x.MultiChoice value back to the server, and the Model.property collection will be missed.
Knowing that, you just need to fill this property with the collection again during the POST action, like:
[HttpPost]
public ActionResult POST(Model quiz)
{
// some code here
quiz.property = new CollectionOfSomething();
return View("Quiz", quiz);
}
Is that what you are looking for?
The modelbinder news up an instance of that class with whatever POST data it has. Anything that's null has no posted data. The easiest way to make it not be null, then, is to create an HTML input for that property so that something is posted for it.
However, in situations where you're dealing with existing data, it's preferable to only post what you need to post, and then lookup the original object again in order to map the original property values back onto the version that was passed into your action:
[HttpPost]
public ActionResult Quiz(int id, Quiz model)
{
var quiz = db.Quizzes.Find(id);
// assuming `Foo` was a property that was not posted
model.Foo = quiz.Foo
...
}

Is passing the Viewmodel to the Controller a good idea?

I am fairly new to MVC and had a question about a form I am creating. The page has a form at the top and a grid at the bottom. As people enter data into the form and click the button, the form data is added to the grid below.
My plan is to use a BeginForm and send the form to an HttpPost controller method for processing and then bounce back to the view. Currently, I am using this for the form on the view:
#using (Html.BeginForm("AddRefund", "Refund", FormMethod.Post))
In the controller, I have this:
[HttpPost]
public ActionResult AddRefund(RefundModel refund)
{
if (ModelState.IsValid)
{
(etc...)
My problem is that the "refund" object in controller always arrives from the view empty. From my research, it seems that the model reference in the controller is just there to provide model structure, and NOT to receive the actual model from the view. I don't understand why this is, however, as it would seem very valuable to be able to send a populated viewmodel from the view to a controller.
Also, how would you guys handle the code for this problem? How would you collect all of these form submissions from the user, present them to the user in the grid below the form, and then ultimately submit the page and insert all of the items in the grid into the database?
edit: here is my view
#model RefundsProject.Models.RefundModel
#using (Html.BeginForm("AddRefund", "Refund", FormMethod.Post))
{
(all of the form elements are here)
<input id="button-add" type="submit" value=" Add Refund to List " />
}
Eventually, there will be another button at the very bottom of the view that will submit all of the items the user entered into the grid to the database.
From my research, it seems that the model reference in the controller is just there to provide model structure, and NOT to receive the actual model from the view.
This is completely the opposite of the way ASP.Net MVC was designed. ASP.Net comes with default ModelBinders that are used to Bind data from a Form, Querystring, Ajax (Json and XML) to a strongly typed object for a Controller Method.
My problem is that the "refund" object in controller always arrives from the view empty.
This is most likely due to a lack of knowledge or a misunderstand of how model binders work.
Also, how would you guys handle the code for this problem?
I would Ajax Post the RefundModel back to the controller to validate the refund. If it is valid, then dynamically create fields in the form that will eventually model bind back to an IEnumerable/List on a new method that will then verify all the refunds, one at a time (to validate the data again).
Here is an Extremely broken down example (probably needs some work, but the important parts are there):
Classes:
public class AddRefundsViewModel
{
public RefundModel Refund { get; set; }
}
public class RefundModel
{
public string Reason { get; set; }
public Decimal Amount { get; set; }
}
Methods:
public ActionResult AddRefunds()
{
var model = new AddRefundsViewModel()
model.Refund = new RefundModel();
return this.View(model);
}
[HttpPost]
public ActionResult ValidateRefund(AddRefundsViewModel model)
{
var result = new { isValid = modelState.IsValid };
return this.Json(result);
}
[HttpPost]
public ActionResult ValidateRefunds(IEnumerable<RefundModel> model)
{
var isRefundsValid = true;
foreach (var refund in model)
{
isRefundsValid = TryValidateModel(refund);
if (!isRefundsValid )
break;
}
if (isRefundsValid)
{
}
else
{
// either someone hacked the form or
// logic for refunds changed.
}
}
Views:
#model AddRefundsViewModel
// assuming RefundController
#using (Html.BeginForm("Refund", "ValidateRefunds", FormMethod.Post))
{
#html.EditFor(m => m.Refund.Reason)
#html.EditFor(m => m.Refund.Amount)
<input type="button" id="addRefundButton" name="addRefundButton" value="add"/>
<input type="submit" id="submitRefundButton" name="submitRefundButton" value="submit all"/>
}
<!-- jquery -->
$(document).ready(function()
{
$('#addRefundButton').on('click', function()
{
$.ajax({
url: '/Refund/ValidateRefund',
data: $("addRefundForm").serialize(),
success: function(result)
{
if (result.isValid)
{
// create new hidden imput elements, and grid
$("addRefundForm")[0].reset();
}
else
{
// Refund isn't valid
}
}
});
});
});
From my research, it seems that the model reference in the controller is just there to provide model structure, and NOT to receive the actual model from the view. I don't understand why this is, however, as it would seem very valuable to be able to send a populated viewmodel from the view to a controller.
Your a bit wrong. There is a difference between ViewModel and Domain Model. View Model is a class that you use to process the logic between views and your domain (business).
Then there is Domain Model (in .net) this is usually some data container objects (POCO). This is anemic. Based on DDD there is a little difference.
So what is the best practive?
It is always good to use a ViewModel object to transfer data between your views and controller.
Then in controller you can use a mapper (automapper or valueinjecter) to transform them.
Now you have your domain object that you can process.
Using ViewModels to pass data both up and down between controllers and views is completely acceptable.
To help with your model coming up empty issue, inputs, such as <input id="FirstName" type="text" /> need to have name attributes for the MVC model binder to map what you posted into your RefundModel object. In your View code you shared, you only showed a submit button, so it is unclear if your other elements you expect to get mapped have names or not.
To fix my above example of an input tag, you would do <input id="FirstName" name="FirstName" type="text" /> or use a Razor helper: #Html.TextBoxFor(m => m.FirstName)

Missing model collection after submit

Hi I have simple model which looks like this:
public class HomeModel
{
public HomeModel()
{
Buildings = new List<Building>();
}
public List<Building> Buildings { get; set; }
public int SelectedBuildingId { get; set; }
}
and on view i display combo like this:
#Html.DropDownListFor(model => model.SelectedBuildingId, new SelectList(Model.Buildings, "Id", "Name"), "Choose Building... ")
and now when I click submit button, then the buildings list dissapears
so I tryid to keep it with hidden field
#Html.HiddenFor(model => model.Buildings)
but it doesn't work, any help ?
#Html.HiddenFor(model => model.Buildings) -> this is working just for primitive types like int string and so on.
I will not recommend you to serialize a list into the view but if this is necessary for you,you can do it like this:
#for (int i = 0; i < Model.Buildings.Count; i++)
{
#Html.HiddenFor(c => c.Buildings[i])
}
And now after post you will have full list in your view.
If your view is strongly typed to your HomeModel, then you can return your model in your postback event and return the model again to your view:
[HttpPost]
public ActionResult GetHomePostResult(HomeModel model)
{
//do whatever with your model data
return View("YourHomeGetView", model);
}
You don't need the list again... just load it again in the Post action.
EDIT:
If you insist in having it posted along with the important data. You should serialize that list to a string, and then rebuild the list in the server after the post.
Remember you are in MVC not plain ASP.NET... so each action is somehow atomic. For the case of dropdownlists, this is the normal behavior: reload the list in the server (independently from where you load it).
1)
and now when I click submit button, then the buildings list dissapears so I tryid to keep it with hidden field
#Html.HiddenFor(model => model.Buildings)
but it doesn't work, any help ?
Just Inspect element and see what is the name rendered for this hidden field, Make sure you have the same name as in your Model (only then the values get binded). If you see a different name in element, change the syntax to
#Html.HiddenFor(model => model.Buildings, name {Name = Buildings })
and on post back the values will be binded in the model
**OR**
2) If you are retrieving the values from DB using some Id or something. Pass this Id to the view. And keep this in hidden field. On post back catch this value in controller with proper parameter name (Name must be same as the hidden field element in view). Use this Id to retrieve the DropDown again and continue...

How to post a c# object to an action from a view?

I have a view which is rendered by calling an action and I'm passing a view model to it e.g. Vm1 then populating some drop down lists.
On this view, I have a "Filters" section with some text boxes and a "Filter" button and I'd like to call another action passing the values of the text boxes and then rendering the second view partially on the page within a div.
So I have done this and my action looks like below which is called by ajax when the "Filter" button is clicked:
ActionResult ActionName (string inputText1, string inputText2, string inputText3, ...)
Because I have about 10 text boxes, I'd like to create a new c# object and passing that object to this action to look like this which is simpler:
ActionResult ActionName(MyActionFilters myFilters)
How to achieve this?
you can have a model as below
public class MyActionFilters
{
public string Property1{get;set;}
public string Property2{get;set;}
public string[] Property3{get;set;}
// add any number of properties....
}
you can pass the empty model in Get Action method
ActionResult ActionName()
{
MyActionFilters myEmptyActionFilers= new MyActionFilters();
View(myEmptyActionFilers)
}
in the form
Html.TextBoxFor(model => model.Property1)
Html.TextBoxFor(model => model.Property2)
then in the post method you can access the model that is populated in the form
I have removed the previous code. the new code is after the Edit Tag :)
Edit:
Sorry I was not around. This kind of functionality can be achieved easily using AJAX :)
It goes as below.
[HttpPost]
PartialViewResult ActionName(MyActionFilters myActionFilers)// this is magic
{
/*you can access the properties here like myActionFilers.Property1 and pass the
same object after any manipulation. Or if you decided have a model which contains
a variable to hold the search results as well. That is good.*/
return PartialView(myActionFilers);
}
So far this is a good example to refer.
And do not forget to add jquery.unobtrusive-ajax.js script reference to your view. If not Ajax will not affect.In the given example he has done it in the _Layout as you can see.
PS: Choose properties of models that is going to be passed to views, wisely and Enjoy Ajax!!
You need to set the form input names to the properties of your ViewModel, then MVC will do some magic to make For example:
public class FormViewModel {
public string input1 {get;set;}
public string input2 {get;set;}
// and so on
}
then on your Action:
public ActionResult FormPost(FormViewModel model) {
// you'll have access to model.input1, model.input2, etc
}
Lastly, for example, on your HTML Form you'll want to create:
<input type="text" name="input1" />
<input type="text" name="input2" />
or you could use Html.TextBoxFor(model => model.Input1) and the helper will name everything correctly.
The name property of your input tags, should be prefixed by the object name ("MyActionFilters")
for example:
<input type="text" name="MyActionFilters.YOUR_PROPERTY_NAME" />
btw, your action method should be annotated with HttpPost attribute.
[HttpPost]
ActionResult ActionName(MyActionFilters myFilters)

Categories

Resources