I'm new in ASP.NET MVC and I find troubles in some MVC patterns.
It's pretty clear the paradigm One controller -> One View but in a complex scenario where I have a wizard page where at every step I collect data for different models I can't find a straight and simple solution.
Example:
I have these 3 models: Student, Subject, Subscription
I want to make a jquery wizard page to create a subscription in this way:
Ask to select an existent student or create a new one
Ask to select an existent subject or create a new one
Ask to input some other data (date start, date end, payment etc)
This wizard is in view Subscription/Create and is using a Subscription model with some ViewBag data.
How can i achieve this?
It's better posting everything to a single controller action and call inserts in every models involved? Or is better post data at each step to the right Action?
If you're using jQuery for this, then in reality all you need is one viewmodel. That single viewmodel will contain the properties for eveything you intend to collect from the user e.g
public class SubscriptionCreateViewModel
{
// Fields from page 1 of the wizard.
public string Username { get; set;}
// Fields from page 2 of the wizard.
public string Foo { get; set;}
// etc.
}
When the user clicks Create (or whatever) on the last step of the wizard, the jQuery can make an Ajax POST call to the Subscriptions controller e.g
$.ajax({
type: 'POST',
url: 'url to controller',
data : { Username : 'UserName', Foo : 'foo' }
});
[HttpPost]
public ActionResult Create(SubscriptionCreateViewModel viewModel)
{
// Do whatever.
}
This implies that all the fields are shown in the same view though, by some JavaScript that changes what fields are shown to the user, based on the current wizard step.
If you are using separate views, then I suggest you use three controllers and three viewmodels, one for each controller (StudentController, StundentCreateViewModel, SubjectController, etc)
Related
I'm in the process of refitting a website that I'd previously built using ASP.net with VB in the code-behind, into MVC with VB so that it's more responsive to different screen sizes and device types.
So far I've been able to replicate six of the pages plus the Site.Master files. Now I'm turning my attention to the Contact page which in asp.net takes data from a form, validates it for completion and data-type compliance and then passes it to the code-behind which uses it to generate an email.
I've done quite a lot of reading which suggests using a Model but all the examples I've found then use that Model to populate or query a database using LINQ.
How can I do this without a database?
The M in MVC stands for Model, not Mdatabase. You can use whatever you want as the model. Most applications use a database and most .NET applications use EF to access a database (or at least Microsoft want it that way) but you can use whatever you want.
Using a database engine is recommended as permanent storage, but essentially you can create model class for contact page without involving a database like this:
public class Contact
{
[Required]
public String Name { get; set; }
[Required]
public String EmailAddress { get; set; }
}
And you can use LINQ/lambda expressions after wrapping your model class into a collection (e.g. List), as example:
var list = new List<Contact>();
list.Add(new Contact { ... }); // adding items to the list
// Lambda syntax
var name = list.Select(x => x.Name); // returns a value from the list
// LINQ syntax
var email = (from item in list
select item.EmailAddress);
Then you can convert the code-behind logic to a controller action method as ActionResult each for GET and POST request. Afterwards, Redirect, RedirectToAction or simply return View() after data submission can be used for page handling.
About responsive page design to work with different screen sizes and device types, MVC itself not designed to present responsive layouts by default. You need to alter some HTML & CSS-related attributes, as similar problem here:
How to make an MVC web application adjust to automatically fit different screen sizes
NB: Since your problem doesn't include any code, the provided codes are just examples as figure to what should be done.
There's probably a really basic answer to this question but I am new to Entity and MVC and am getting used to the basics.
I'm trying to automatically generate a MVC controller for the main table Sites with a dropdown for server. It seems like I would need a model like this:
public class Sites
{
public TTSites TTSites { get; set; }
public List<servers> server { get; set; }
public Sites()
{
server = new List<servers>();
}
}
This is using the classes TTSites and servers both with string server
But if I set this as my model class and my entity database as data context it says I need to define a key. Should I be using the base classes instead of the model or what? Do i need to set something up in the model or base class?
It seems like you've got some terminology confused. You code the controller actions in a controller class, and the routing engine determines what controller action to call based on the URL. For example, if you have a HomeController class with a default Index action, it might look like this:
public ActionResult Index()
{
// code here
}
This would be invoked with the default routing, if you went to your site with a URL like this (let's say your site can be hit via the www.mysite.com URL:
http://www.mysite.com/Home
That would get you into the Index action in the controller.
Ordinarily, one would use a view model to use on the UI side, and that would be populated from an entiy with the data you need in the view itself. If you had two entities like TTSite and Server, you'd populate the Sites view model like so, as a (very simple) example:
public ActionResult Index()
{
var servers = yourDbContext.Servers.ToList();
var ttSite = yourDbContext.TTSites.GetByID(1); // retrieve one entity by its ID value, this would be acquired dynamically based on some sort of user input rather than hard-coded
var viewModel = new Sites(servers);
viewModel.TTSite = ttSite;
return View(viewModel);
}
I'm not including anything regarding making drop-downs, just illustrating getting data into a view model and then creating a view with that view model.
Note that you would not use the Sites class as an entity but rather a view model, and setting its data based on entities from your database. You wouldn't be setting any primary keys in a view model class; those are the concern of the data model, and you've presumably already got those entities (such as TTSite) set up in a usable fashion in your data layer.
Once you've got a controller action and a view up and working, you can turn to getting the view model data into a form usable by a drop-down list, and going from there.
I need to capture three different types of information from a new user who is registering for the first time in an MVC 3 app (using EF code first). Ideally on the one page (which will have three tabs)
User info
Extended user info
Benefits chosen by user
The register method of the account controller should populate the user table when it fires. I need some advice on how best to capture the other data. DO I create a UserDetails model for the additional data? If so is it possible to update this from the same page? (which would be the Account/Register page. Do I need to do something in the account controller or will the relationship between the models be enough?
Are there any good examples about that would explain this? I tried the MVC Contoso University one but couldn't see if I could do this.
Any advice very welcome :)
Thanks
You can create a view model that combines all the fields you need from the other models, and strongly type your view to that. Once the user submits the info back to the controller, you'll process each property appropriately.
public class RegisterViewModel()
{
//Userinfo
public string UserName {get; set;}
...
//Extended user info
public string FirstName {get; set;}
public string LastName{get; set;}
...
//Benefits
public string BenefitName {get; set;}
...
}
and then
[HttpPost]
public ActionResult Register (RegisterViewModel viewModel)
{
//grab the user info from the view model and process it
viewModel.UserName...
//grab the extended info and process it
viewModel.FirstName...
//grab the benefit info and process it
viewModel.BenefitName...
}
A single view can only have one model. You can put all the information you need there. It's the simplest solution. The model of your view doesn't have to map to classes you're using elsewhere so you can have your User info, Extended user info and Benefits chosen by user all in one model.
Alternatively, you could make this a two- or three-step process, but you said you don't want that.
Here's my situation: I've got a number of specialized object types in my application, and I'm following the standard convention for displaying them with custom templates in the /Shared/DisplayTemplates folder, and editing them with templates in /Shared/EditorTemplates. But I also want to be able to display a custom filter template for each type, so I'd like to add a /Shared/FilterTemplates folder, and implement my own #Html.FilterFor method, so that showing a Filter template is exactly like showing a Display or Editor template.
Does this seem like the best way to handle this situation, or is there a more correct/elegant way to do this in MVC? Thanks in advance.
I'm always using EditorTemplates when data is sent back to server. I assume the user can submit the filter to the server to perform the actual filtering.
When creating filters I prefer to create a model for the filter like:
public class UserListFilterModel
{
public string Username { get; set; }
public bool IsEnabled { get; set; }
}
The view for UserListFilterModel goes into EditorTemplates/UserListFilterModel.ascx.
And then add it as a property on my view model for the page.
public class MyPageViewModel
{
public UserListFilterModel Filter { get; set; }
}
Then I add the filter model to the model for the page and displays it like this:
<%= Html.EditorFor(x => x.Filter)%>
You are probably wrapping the filter in a form to allow the user to submit the values so I think it belongs in EditorTemplates. The users is in fact editing the filter model.
(If you really want to separate them ing you could use the UIHintAttribute but I wouldn't)
Edit: I added some sample code.
I think you misunderstand how Templates work. Templates do not make sense in the context you are describing.
Templates work on a SINGLE data item (although that data item can contain multiple data items, which in turn have their own templates).
The concept of a Filter is to control multiple data items, thus they do not map well to a template.
What you could do is create a DisplayTemplate for your collection class that adds filtering, thus no need to create a custom type of template. Just use DisplayTemplates.
I am using ASP.NET MVC. My requirement is to build a complex object (an object made of other object) through a step-by-step procedure like in a wizard.
Every dependent object shall be build on it's step and shall be validated in it's step. For example
public class ComplexObjectModel {
public Object1 MyObject1 { get; set; }
public Object2 MyObject1 { get; set; }
public Object3 MyObject1 { get; set; }
}
As there is no built-in facility for a wizard I have decided to create 3 model classes and 3 strong typed partial views binded to these models.
On every step of my pseudo wizard I validate the dependent model object and set the property of the complex object to its reference.
I was thinking to save the complex object inside the ViewData/TempData in the following way
In the controller action
[HttpPost]
public ActionResult MyAction1() {
ComplexObjectModel com = (ComplexObjectModel)ViewData["ComplexObjectModel"];
com.MyObject1 = new Object1();
ViewData["ComplexObjectModel"] = com;
return PartialView( "MyAction2", com.Object1 );
}
and in the View
<% using (Html.BeginForm()) { %>
<%= Html.Hidden("ComplexObjectModel", ViewData["ComplexObjectModel"]) %>
... view fields for Object1, Object n ....
<% } %>
But doing this way the object is not passed back-and-forth between the view and the controller and I have experienced that is null when it comes back from the view to the next action.
Is there a way to support this requirement?
thanks for helping
There are a couple of ways I might tackle this.
First; I might decide to store all this in the session object. I am assuming here that the models are quite large and so I wouldn't want them stored on the view and passed back each time I go to the next page.
Second; I might store them in the database and if the wizard didn't complete then delete them as part of a background process.
The one thing I wouldn't do is pass the complex object to each view. The view should really need to know anything about any other view in a restful world and so I'd be inclined not to do it.
Of course that does mean you need to decide a storage place for the data. If I had a Large objcect then I'd choose the database and if was fairly small then I'd choose the session object.
As you have already found, having all the data for each object in each view can be problematic.
However, if you are determined to do this the View way then here is what I'd do;
Create a partial view which deals
only with each object in the complex
model.
On each view, include all three, or
more, of the partial views.
For each partial view which is not
an active participant in the view,
place it within a div that is
hidden.
At least then when you change a property, or add one, you simply set it in the partial view once and not three times. Also if there is an error, you can unhide the divs and see if the data is coming in.
Also each field should then have the id of ModelName.Property so that the controller knows where the property is.
<%= Html.TextBox("MyObject1.MyProperty1", value) %>
Then in the controller you simply do, and this off the cuff;
[HttpPost]
public ActionResult MyAction1(ComplexObjectModel complexModel) {
You could take a look at MVC Futures Html.Serialize helper method which allows you to keep state into a hidden field between the controller actions in a similar way classic WebForms does it.