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.
Related
A few similar questions have been asked before but my use case is a bit different.
So this is my model:
public class YourModel
{
public string[] Suburb { get; set; }
}
And my view:
<input name="Suburb" type="checkbox" value="sydney" /><span>sydney</span>
<input name="Suburb" type="checkbox" value="melbourne" /><span>melbourne</span>
Controller:
public ActionResult AdvancedSearch(YourModel s)
{
// logic
}
So MVC is smart enough to retrieve the multiple checkbox values to put them in the Suburb array in YourModel model. I can inspect all values there. But my use case is that the YourModel is just the nested model inside another model MyModel:
public class MyModel
{
//other properties
public YourModel m { get; set; }
}
So now how do I make MVC post the checkbox values to a deeper model MyModel.YourModel? I have tried #Html.CheckBoxFor and #Html.CheckBox but neither of them worked.
Right now my work around is to add a temporary array placeholder in the outside model and then assign all the data to the inside model when available, but that is definitely not ideal.
You need to use add MyModel
<input name="m.Suburb" type="checkbox" value="sydney" /><span>sydney</span>
<input name="m.Suburb" type="checkbox" value="melbourne" /><span>melbourne</span>
In Razor, you don't have to define the name of the top-most Model, only the names of the properties of inner models:
<input name="m.Suburb" type="checkbox" value="sydney" /><span>sydney</span>
<input name="m.Suburb" type="checkbox" value="melbourne" /><span>melbourne</span>
However, I'd strongly suggest you to change that m name to something more significant.
I know it would be a basic question but I'm a newbie to ASP.Net MVC. I have fetched data from database using LINQ but there is an issue. I wanna bind that data with input fields of a customized webform. (I'm using MVC). I wanna populate the input fields of webform with fetched data. I'm using EF Database first approach.
My Controller and view is attached.
Controller ActionMethod
public class HomeController : Controller
{
public ActionResult Index()
{
AutoRTGSEntities_1 dc = new AutoRTGSEntities_1();
//dc.policies.Where(cb => cb.Section_Key.Contains("SenderBIC"));
return View(dc.policies.Where(cb => cb.Policy_Section.Contains("RTGS")).ToList()); //get RTGS policy section data
}
}
View
#model IEnumerable<Swift_MT_103.policy>
#{
ViewBag.Title = "Home Page";
}
<div> #Model{ #Html.TextBoxFor(x => x.data_Value)) } </div>
<div> <input type="text" name="ReceiverBIC" id="ReceiverBIC" /> </div>
Rest is HTML and CSS. Snap is attached.
Here's a very basic example of how to this. Let's say you have following class:
public class User
{
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "E-mailaddress")]
public string E-mail { get; set; }
}
In the controller you get the user:
public ActionResult Index(int id)
{
var user = Db.Users.FirstOrDefault(x => x.Id == id);
if(user != null)
{
return View(user);
}
//Return to the 'Error' view as no user was found
return View("Error");
}
You also need a View to show everything on screen. Make it a strongly typed view, this way you can pass a Model to it. This class will hold all data you want to pass to the view. Code of the view:
//This line lets the view know which class represents the model
#model User
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
More reading:
Getting started with ASP.NET MVC 5
ASP.NET MVC Overview
Update:
In case you have a list of objects, you need to enumerate them in the view:
#model IEnumerable<string>
#foreach (var value in Model)
{
<div>#value</div>
}
And if the model is a class and has a property that is a list:
//Let's say a user has lots of names
public class User
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
//View:
#model User
#Html.TextBoxFor(m => m.Id)
#foreach (var name in Model.Names)
{
<div>#name</div>
}
Try to implement a correct ASP.NET MVC architecture. To get this completed, you'll need to use proper Razor (.cshtml type) Syntax in your Views. Best practice:
Create a dedicated ViewModel class in the Model directory. You might call it CustomerCreditTransferViewModel for example. It should contain all Properties you want to display/edit anywhere on the page.
Once you selected your data from your DBContext in your Action, create an instance of CustomerCreditTransferViewModel and populate all fields from the result.
Update your View to use #model CustomerCreditTransferViewModel instead of Swift_MT_103.policy (believe me, this is going to make your live much easier in future)
Copy-paste your raw HTML Code into the page and start looking for all Fields you want to bind, e.g. Text fields (<input type="text" name="accountno" value="" />) and replace them with the Razor Syntax for Data Binding (#Html.TextBoxFor(x => x.AccountNo)). If done correctly, they should be populated now.
Next step is probably the POST. Follow the base MVC Post technique from the Tutorials. Ensure that the Posted Value is of type CustomerCreditTransferViewModel) again, so you can easily validate values and map back to type of Swift_MT_103.policy.
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">
}
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)
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.