Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I need to write a mobile Web application (MVC), where I have been given the UI Design that I need to work to and I am not sure of the best approach and was looking for any recommendations.
To simplify the project:
The 1st view asks for a number
The 2nd view asks for a category
Based on the logic of the first two values, I can show up to 6 different forms/views each collecting different data pieces.
This data then gets written to a single SQL table
I am not sure if I should:
Have one controller and one model, and I just keep track of which View needs to be shown within that controller
OR
Have mutiple models, each based on a previous model
OR
Use panels (ie. used to this with WebForms), and make these panels visible again based on tracking which section needed to be viewed.
Any advice would be appreciated,
Mark
It all depends on the Models.
Case 1:
There's only going to be one database table (i.e. one survey)
If there's going to be only one database table, you'll only need one controller and one View.
For example:
public class Survey
{
public String Answer1 { get; set; }
public String Answer2 { get; set; }
public String Answer3 { get; set; }
}
The view can ask the first questions, and accordingly display the appropriate fields. So only the final Submit button will be a HTTP Post. All the previous buttons will just perform a simple JavaScript action.
Case 2:
The first questions are used to decide which survey the user should take.
I'll have an Action that returns an intial View. The view does a HttpPost to another Action (ShowSurvey)
public ActionResult Index()
{
return View();
}
[HttpPost]
public async Task<ActionResult> ShowSurvey(string id)
{
switch(id)
{
// display the appropriate View here.
}
}
ShowSurvey would that take a parameter using which you know which survey you're supposed to display. This action will have it's own View/View(s). (One view if all the survey questions are similar. Else you might need to have more views).
This would be my approach BTW. Critics are welcome!
UPDATE:
I read your question again and you've mentioned you've got only one SQL Table. So yeah Case 1 will be the easiest way.
Display the initial questions. Decide what to show etc. at runtime using JavaScript. Once the user has finished answering all the questions, you can show him (or enable) the Submit button that'll perform a HTTP Post back to your action and commit the data to the Database.
PS: I've used the word survey just because questions remind me of them :P
The question is how these two are related? Is the value entered into the first field have influence on the second? I'd build some simple two field model or - since I like pass to view explicit structures, I would add another field to the model containing list of available options, so it would be:
public class MySimpleModel{
public int MyNumber{get; set;}
public string MyCategory{get; set;}
public List<string> Categories{get; set;}
}
and then post it controller (by regular form submit or ajax):
public class MyController:Controller{
[HttpGet]
public ActionResult Index(){
return View();
}
[HttpPost]
public ActionResult Index(MySimpleModel model){
if(model==null)
return Index();
if (model.MyNumber>3 && model.MyCategory=="xxx")
return View("View1",model);
//etc.
}
}
About user interface - make it user friendly and logical. You didn't wrote anything about requirements, so it's hard do advise you :)
Related
I'm an ASP.NET MVC beginner and currently I use EF with a database-first approach to do my work. Everything goes well and every model have its controller and views files. I face problem when I want to save multi model data on a view.
In my case:
I have ASP.NET MVC form for teacher details data, and another for teacher employment history (this two are auto generate from scaffolding database approach)
I want a view Create.cshtml where user inputs teacher details and employment history and this can be saved into their own tables. Therefore, I use tuple and follow what (Multiple models in a view) and (Two models in one view in ASP MVC 3) did.
As a result, I successfully create teacher details and employment history on a view (Just interface).
But I have no idea how to save the input into the different tables (2 tables: teacher, employmentHistory). Now, when I save the input, nothing happens.
I guess I need to do something on controllers parts, please give me some ideas on how to do it.
Thanks in advance
First, welcome to StackOverflow!
You are correct, you should do something on the controller part.
I would create a ViewModel for the view. By doing this you can project the data from the database in any way that is needed in the view. Also, with this approach you don't return the full entity, maybe there is some sensitive information there. And you can get the benefit of the model validations also. (For example, what if at some point you need to add another field from another entity?)
I would also create partial views for the information in the view model and pass that model to the partial view, this way enabling the re-use of the views, if needed.
When passing the data to the controller you can pass the ViewModel and then save the data in the database.
Since you didn't give no model info of your classes, I give below an example. Either way (view model or tuple example you followed), you should change the controller code similar to what I'm writing below.
public class TeacherViewModel
{
//teacher details
[Required]
public int TeacherId {get; set;}
[Required]
public string TeacherName {get; set;}
// {...}
//teacher employment info
//here you can have a list of information or the last entry in the history,
//or what's required to add a new entry
public string LastWorkPlace {get; set;}
public DateTime From {get; set;}
public To {get; set; }
//{...}
}
public class TeacherController: Controller
{
//{...}
[HttpPost]
public ActionResult SaveTeacherInfo(TeacherViewModel model){
if (ModelState.IsValid) {
var teacher = new TeacherEntity
{
TeacherId = model.TeacherId, //if update otherwise leave blank
TeacherName = model.TeacherName
//{...}
};
//your context name here
_dbContext.Teachers.Add(teacher);
var teacherEmploymentInfo = new TeacherEmploymentHistory
{
TeacherId = teacher.TeacherId,
LastWorkPlace = model.LastWorkPlace,
From = model.From,
To = model.To
//{...}
};
_dbContext.TeachersEmploymentInfo.Add(teacherEmploymentInfo);
_dbContext.SaveChanges();
//_dbContext.SaveChangesAsync(); if using async await
}
return View(model); //return any validation errors from the view model
// to the user to fix.
}
}
If you are using the ErrorHandler as a global filter no need for try..catch block if you are not planing to return custom errors (BusinessException or DatabaseException, for example) from the controller, if not, you should wrap the code in a try..catch block.
What I am Attempting
I am trying to bind my ViewModel to my View which contains a Customer Name and a list of Contacts to reach that customer. Once the view is populated I also want the user to have the ability to add, delete, and edit contacts in the View.
What I've got so far
Currently I am able to bind to the ViewModel using the EditorTemplate and edit the data with no problems. The problem comes in when I want to add or remove rows in the list, if a user deletes row 5 from the middle of the ViewModel bound Editable List only rows 1 - 4 will end up being posted to the server.
The Code
Here is what my ViewModel looks like:
public class CustomerViewModel{
[Required]
public int CustomerUniqueID { get; set; }
[Required]
public string Name { get; set; }
public IEnumerable<CustomerContacts> Contacts { get; set; }
public CustomerViewModel() { }
public CustomerViewModel(Customer customer)
{
ICustomerContactRepository contacts = new LockShop.Domain.Concrete.EFCustomerContactRepository();
this.Contacts = contacts.FindContacts(customer.UniqueID);
this.Name = customer.Name;
}
}
I am passing my ViewModel to my view like this:
public ActionResult Edit(){
Customer customer = repository.Customers.FirstOrDefault(c => c.UniqueID == 23128);
return View(new CustomerViewModel(customer));
}
When it is time to render the list, I simply use the EditorFor helper:
#Html.EditorFor(model => model.Contacts)
What I love about this approach is that when I click the save button all of my changes are automatically posted to the controller!
My Question
What are the best practices of how to add the functionality of adding and removing rows to a list that is generated by an IEnumerable from my ViewModel?
What I Have Tried
I've read Steven Sanderson's blog post which talks about editing a variable length list in ASP.NET MVC. His post seems to only cover binding to a model and doesn't cover the possibility of binding to a list in a ViewModel. When I implemented his solution the post data from the Contacts list that got sent back to the controller was null.
Please feel free to ask any questions for clarification and thanks for your time.
I read this q/a Real example of TryUpdateModel, ASP .NET MVC 3 and was really interested on #ben-foster response.
I started doing a comment on that answer but got quite long, so started a new Question.
Having ViewModels for everything approach (which i like a lot) get me into some 'weird scenarios' that i want advice in how should I do.
Imagine this structure :
public class ProductListEditableViewModel {
List<ProductEditViewModel> products {get;set;}
}
public class ProductEditViewModel {
List<PriceViewModel> prices {get;set;}
}
public class PriceViewModel {
CurrencyViewModel currency {get;set;}
}
and so on ... ? do you really make one view model for each inner class? how then you map all that to the Model Object?
Also, that covers the Edit, but I have an Add, a send via email, and potentially more Views so more ViewModels!! should i end like something :
AddCurrencyViewModel
QuickAddCurrencyViewModel
EditCurrencyViewModel
ListCurrencyViewModel
DeleteCurrencyViewModel
ShareCurrencyViewModel
all having the 'almost same' properties ?
Should all those be packed into one file ?
Also do i need all this all viewModels or a inheritance approach might be better?
If you can, I´ll appreciate elaborate on complex scenarios
Also, I use a DTO approach to expose some of the model objects into web service / apis, so I already have some form of mapping already in place where this DTO are not exactly my ViewModels, should I remove one of them? what´s the suggestion in this scenario ?
I´m using entity framework but i think the question is (or should be) ORM agnostic.
Not using UoW pattern (will this helps?) as looks it´s gets more complicated as the depth of the object increases.
Thanks a lot!
We typically have a view model per view so yes, if you have lots of views you will have lots of view models.
In typical CRUD applications we often have very similar views, for example Add and Update. In these cases, yes we use inheritance rather than writing duplicate code - usually Add subclasses Update.
public class AddFoo : UpdateFoo {
public AddFoo() {
// set up defaults for new Foo
}
}
public class UpdateFoo {
public string Name { get; set; }
// etc.
}
We attempted to "share" view models between views in the past and normally ended up in a world of pain.
With regard to your "weird scenario" - this does look weird indeed, but perhaps because I don't understand your application.
The goal of your view model is to provide the information to the view that is needed and ideally to flatten any complex objects so they are easier to work with. You shouldn't split your view models up like your example unless it makes sense to do so.
Let's say I wanted to a create a view where the customer could change their contact details. Taking the following domain object:
public class Customer {
public string FirstName { get; set; }
public string LastName { get;set; }
public Address Address { get; set; }
}
I'd probably flatten this to a view model like so:
public class UpdateAddressModel {
public string FirstName { get; set; }
public string LastName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressCity { get; set; }
// etc.
}
Of course there will be occasions where it doesn't make sense to do this, for example a dashboard view in an online store where you have a list of products going out of stock and a list of recent orders - these two things are unrelated but are required by your view:
public class DashboardModel {
public List<Product> ProductsGoingOutOfStock { get; set; }
public List<Order> NewOrders { get; set; }
}
how then you map all that to the Model Object?
I'm assuming by Model Object you mean your data/domain model. The key takeaway here is that the view model you use to render your view is unlikely to be the same as the "models" you POST to the server and if they are, you're probably over-POSTing or you have some crazy enter-everything data capture screen that will make your eyes bleed.
I find it helps to think of what you send to your server as Commands and what you use to render your views as view models.
So the answer to your question - how do you map your complex view model to your data model? - Quite simply, you don't. You should send commands to the server that perform a specific task e.g. updating an address.
There's no hard and fast rule in how you structure your view models but generally go with what makes sense and if it starts to feel too complicated you're probably trying to do too much with one view.
I hope this helps. You'll find lots of posts relating to this matter on my blog.
I realize this is an old-ish question but I did want to address one of the questions posed by the OP that was not answered.
Should all those [ViewModels] be packed into one file ?
Most of the examples I see put each ViewModel in a separate file, so the dominant convention seems to be one file per viewmodel, but I found in practice that this seems to be overkill. Instead I put all viewmodels for a particular controller in one file with multiple viewmodels in it. So for example if User is my Controller and I have several viewmodels associated with this controller such as UserAddViewModel, UserEditViewModel, UserDeleteViewModel I put all of the viewmodels for User in one file called UserViewModels.cs
I'm working on my first ASP.NET MVC 3 application and I've got two Controllers with Views, IceCreamController/IceCreamView and RecipeController/RecipeView, and on each the user can make a selection and display the recipe.
Selection causes a PartialView to be displayed which an Edit link on it. When clicked the EditView for this recipe is displayed, allowing the user to edit the attributes of the recipe item selected.
Great. This works fine except currently the POST action in the RecipeController looks like so:
[HttpPost]
public ActionResult Edit(RecipeViewModel viewModel)
{
// updates the underlying model with the viewModel
// other things not germane to the discussion
return View();
}
and that ends up always showing the Index view for Recipe, which isn't what I want. Rather, I'd like to be able to do is send the user back to the appropriate View (IceCreamView or RecipeView) when they've submitted their changes.
I assume that others have done something similar to this. How do you communicate which Controller/Action should be redirected to when the Edit is done?
Note:
I added a bit above to clarify that I've got two separate Controllers (IceCreamController and RecipeController) and each has a View that can select and ultimately do a
#Html.Partial("_Recipe", model.recipe)
to display the details of a particular recipe. My problem is how to get the page redirected back to either IceCreamView or RecipeView by the Edit Action on RecipeController - essentially, how do I communicate where it should go since the recipe details could have been displayed by either path.
Solution Employed:
As you can read below in the comments to Darrin's answer, since I've got more than a single controller involved, a solution is to utilize the viewmodel to pass in the controller/action that should be redirected to following when the Edit post action is completed.
As I've got more than a single instance of this situation (arriving at an Edit page via multiple paths), I think creating a simple BaseViewModel to hold this functionality might be in order and then have all the applicable viewmodels inherit from that BaseViewModel.
I'm don't think it needs to be anything more than something like:
public BaseViewModel
{
public BaseViewModel(string controller, string action)
{
ControllerName = controller ?? string.empty;
ActionName = action ?? string.empty;
}
public string ControllerName { get; set; }
public string Action { get; set; }
}
And then a viewmodel's constructor could just be modified to pass in the controller/action and hand that off to the base class.
There may be other solutions to this and if so, I'd like to hear them.
[HttpPost]
public ActionResult Edit(RecipeViewModel viewModel)
{
// updates the underlying model with the viewModel
// other things not germane to the discussion
return View("IceCreamView");
}
or if you wanted to redirect you could have a controller action that would serve this view and then return RedirectToAction("IceCream"); which is probably more correct rather than directly returning a view from a POST action in case of success.
This came up during one of our retrospectives and wanted some additional feedback and a spot check. We currently have a number of views that enable/disable based on boolean flags (Model.IsNew is an example). I'm of the opinion that views should be as simple as possible and controllers should determine the data for that view, not necessarily how it works. I think views, partial or full, should be -told- what to do and handle that vs the view determining what should be shown/hidden. A very basic example goes as follows but covers both sides of this and is mostly a reflection of what we have ...
A controller has a pair of methods (post/get) called Details. [Get]Details has a single parameter, Id and [Post]Details takes id and a viewmodel. Within the post, the method is ~30 lines long checking for valid model, determining if its new, if a certain value changed (triggers redirect) and so on (I think this is incorrect). The [Get]Details check for empty id, populates the necessary dropdowns, nothing fancy (I think this is right). The detail view itself contains a small bit of logic : If (!Model.IsNew) { RenderAction(History => History.Show(id); } (I think this within an if is incorrect, the Show should know what to display, regardless if its new). The plus to this is the layout for said Detail view isn't done twice. Details/Add would be nearly identical, minus some disabled fields depending on state (maybe these should be partials?) -- the entity could be disabled/deleted making the values editable or not.
Thoughts, opinions, insights?
why not create multiple Views and Actions?
Details
Edit
[HttpPost]
Edit
Create
[HttpPost]
Create
Then they could share a Model object
public ThingModel
{
public Thing Thing { get; set; }
}
or have the Create and Edit actions use a safer (prevent html injection) model which will also let you use the Validation options built in.
public ThingEditorModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public bool IsNew { get { return Id == 0; } }
}
And then for Edit and Create you can create an EditorTemplate (Shared/EditorTemplates/ThingEditor.ascx) that the Create and Edit could share
I think you're on the right track...use the 'main' view for layout and then use Templated Helpers for the 'logic'. Lean on Html.DisplayFor(x=>x.Thing) and EditorFor
You definately don't want the layout in two places.