Changes to the model object not passing back to the controller - c#

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">
}

Related

Getting values of input fields in MVC

I'm a bit new to MVC, and maybe I'm just misunderstanding something, but I can't figure out how to do the following in an elegant way:
I have the following Entity that I wan't updated:
Model:
public class Entity
{
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public int FieldInt { get; set; }
public DateTime FieldDate { get; set; }
public int FieldOther {get; set; }
}
}
View:
My view displays a bunch textlines with checkboxes attached. The checkboxes are identified by two data-attributes: data-field-int and data-field-date, which is something along the following.
#html.BeginForm("Confirm", "Home", FormMethod.Post) {
...
<input type='checkbox' data-field-int="1" data-field-date="2014/01/01" />
<input type='checkbox' data-field-int="1" data-field-date="2014/02/02" />
<input type='checkbox' data-field-int="1" data-field-date="2014/03/03" />
...
<button id="ConfirmButton" type="submit" class="btn btn-primary">Confirm</button>
}
What I want in the controller is when the ConfirmButton is pressed, create an Entity object for each checkbox that is checked with the value of fieldInt and fieldDate populated with data-field-int and data-field-date attributes respectively.
I can do it by making the controller action take FormCollection as input and by putting a name attribute on the checkboxes with a concatenation of fieldInt and fieldDate and then seperating them in the controller and updating the db. But it seems like there would be a better way, since MVC is so smart with Entity Framework.
I hope you guys can help me understand
Thank you,
Peter
welcome to MVC .
-Using razor engine with model entities is the best practice.
-In the above mentioned code you need to set something like this
#using ( Html.BeginForm("Confirm", "Home", FormMethod.Post))
-As you are new try using strongly typed views with selected templates which generates razor code for you i.e you can analyse deep
-Finally just use model x as parameter to you [HttpPost] action method and convert these entities to you Entity framework entities and save in DB
Additionally :
Data attributes are not included in the data that's posted with the form, so there is no way to read them in your controller action. Try using a hidden field instead
Like
#Html.HiddenFor(m => m.FieldInt) or
<input type="hidden" name="FieldInt" value="1234" />//do similarly for rest
Passing static then #{Model.phoneno = "1234"}
This question consists of two parts:
1.
It is good to specify #model in razor view and use helper methods that take lambda expressions with the model as parameter.
#model MyType
html.Textbox(model => model.FieldOther,...)
Then you create action that takes the model
[HttpPost]
ActionResult MyAction(MyModel model) {
....
}
Mvc will try to create instance of the model and map form fields to the model properties.
2.
You can use entity as model but, believe me, so called Data transfer Objects and/or View Models were created for a reason and as application evolves, single views evolve too to manipulate data from many related database entities.

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

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.

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)

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)

How to post data through multiple partial view in mvc3

view:
#model
#using (Html.BeginForm("action", "Controller"))
{
#html.action("action1","controller1") //use model1
#html.action("action2","controller2") //use model2
#html.action("action3","controller3") //use model3
<button type="submit">submit</button>
}
Parent Model
{
public model model1{get; set;}
public model model2{get; set;}
public model model3{get; set;}
}
controller
[httppost]
public ActionResult Submit(parentmodel abc)
{
}
So my question is when I post the data the parentmodel is return as null but when I try as
[httppost]
public ActionResult Submit(model1 abc)
{
}
I get the form values in model1. Is my approach right? What should be done to get the form values in the parent model?
First of all always mention your model at top.
#model MyMVCModels
#Html.TextBoxFor(m => m.Model1.Name)
Here is the beauty, Model 1 value has to be appropriate while you are setting in your textboxes or controls.
Also the structuring of your Model's might not also be correct.
It's really hard to tell what you're trying to do from your question, but if I understand it correctly, you want to pass your form values to three separate partials simultaneously?
If that's the case, I'd recommend skipping the form postback and just make three ajax calls to load the partials when you click the submit button.

Categories

Resources