What's the best way to render Navigation in MVC3? In my app the Controller has to decide what should be in the Navigation but as far as I know there's no way to pass a Model up to the _Layout file (where the Navigation html lives) to give it this information.
You can make the model available to your layout.
Define a base class, MyBaseModel, with the properties you want available to the layout.
Have your models subclass MyBaseModel, and ensure that you populate the properties
Have your layout specify #model MyBaseModel
Use the properties
See also this blog post where a similar problem ("we often find ourselves needing to include the same information in every page") is tackled.
Best is a relative and subjective term. I would usually go with an approach similar to druttka's answer but another option is to use RenderAction() to invoke a controller action
<div>#Html.RenderAction("action", "controller")</div>
I will offer some counterpoints to #druttka's answer. But mostly, you have to decide which trade off you want to make.
If you use a model for your view, you are now forcing 2 things:
Every view must be strongly typed
Every action must call the function to populate all levels of nav included in your view model
The first point isn't so bad, because there are very few pages in a typical non-static site which wouldn't derive from a model anyway, and its easy enough to create an empty model for those pages. The second point is much more annoying however. Each function has to instantiate it's own model, and then populate the nav properties for every level of nav provided by the model. This can be quite cumbersome, but can be fairly elegantly handled in OnActionExecuted for at least nav which is not specific to a given action.
The alternative is to add the nav to the ViewBag. This can be done whenever and does not force you to specify a model for every view, which is great for the flexibility in those cases where you do not need to specify a model. It should be noted however that the ViewBag in asp.net mvc 3 is of type dynamic, which you cannot use as a parameter in a lambda function, thus preventing you from doing something like #Html.DisplayFor(viewBag => viewBag.MainNav) in your layout, which is a real drag. You can still render partial and specify the appropriate DisplayTemplate however.
Related
I have a Course Model which goes the controller and views in a restful way.
For my Course show, it is fully featured. I now want another Course show which will have a simplify page and it like to the original course show.
How can I implement this? I want it to be restful, so in my controller there should only be show, update, index, etc.
Should I create another controller that have an different name from the Model? E.g. Course2?
If it is an admin view vs. public view, I would have entirely different namespaces for two different RESTful controllers. Or if you think you're going have this summary vs. full view thing a lot, create namespaces based on that distinction.
Another option is to encoded the differences in a single ERB template. Or you could actually have the show action render different templates from the same action using some conditional logic.
Without more context though, I can't really say what's the best option. I am personally against creating non-RESTful actions unless it's really going to be a one-off thing. Non-RESTful actions tend to get out of hand in my experience and controllers can get really ugly and unintuitive.
If this is truly just displaying a subset or a different arrangement of the same information, then I think this is a job for the view. At most the controller can use the same action, but select a different view to render, such as might be done if the user wanted to see html vs plain text.
The controllers job is to interpret the model and the views job is to collect and display information. I think you would be concerned about the view having logic in it if you what you describe as a "summary" were more than just a subset of the info, for example if you started to calculate the distances being traveled or how long it would take or how much it would cost based on the data that is provided, then that would be bad.
So I this is just a subset, then I would suggest either rendering partials based on some variable set by your controller, or if organization of the display needs to be substantially difference, then the controller can select a different template to render.
I have a create page and an edit page for an entity. The pages are similar so I have a base view model which contains common fields between the pages, and a view model for each page which inherit from the base.
One of the differences between the two pages is that the create page has a search form where the user can enter criteria and search using an ajax query. The search criteria fields are not part of the entity. I created a "SearchCriteria" sub model with its own properties for the different search criteria so that I could simply post this model when performing the search, and potentially add more search criteria in the future without having to modify method parameters.
It turns out I do need to add something else, but that something else is one of the properties of the base view model. I'm not sure what the best way do this is. I'm thinking that I will have to consider the property to be no longer common and move it into my Edit view model and my SearchCriteria model, but then I lose my common mapping to the entity and will have to repeat code.
I think I may have gone wrong somewhere so some design advice would be appreciated.
Thanks
I have faced a similar problem. First, with the search functionality. You can create a SearchServiceController. Then, add a partial view and pass it a model when you want to display the search bar, otherwise pass null and display nothing. This way you separate concerns by keeping the search functionality in its own process.
As far as adding a property that won't be used, I don't feel that this presents much of a problem. The .NET framework is filled with subclasses that do not implement parts of the base. Instead, you can throw a NotImplementedException. To me, its well worth the trade off to gain consistency and DRY.
Personally, I have found sharing viewmodels between controllers to not be a good thing (but in this case you may be using a single controller). Using IoC with Ninject, I get plenty of Cyclical Redundancy errors when binding my interfaces to the same viewmodels across controllers. For this reason, I took out Ninject. But, perhaps you can bind at another layer...have not tried it.
I was thinking if it is possible to re-use the views.
I have few strongly typed view pages within the same controller, and the code in these views to display the are same. The only difference is the model is served via different action.
So, is there a way to have a single view which can be re-used by these actions.
Please note: I am aware of partial view/view usercontrols, but these still requires me to have and maintain separate files. Hence my question. If no other options, I will use these. My question is to find alternatives, so dont suggest the above.
The choice of the view does not necessarily have to be convention-based. You can very well specify the name of the view to be used like so:
return View("MyStandardView");
And, of course, if you need to pass a model—and you probably do—simple pass a second parameter:
return View("MyStandardView", myModel);
I wonder - what is the best way to supply contextual (i.e. not related to any particular view, but to all views at the same time) info to a view (or to master page)?
Consider the following scenario.
Suppose we have an app that supports multiple UI languages. User can switch them via UI's widgets (something like tabs at the top of the page). Each language is rendered as a separate tab. Tab for the current language should not be rendered.
To address these requirements I'm planning to have a javascript piece that will hide current's language tab on the client. To do this, I need current's language tab Id on the client. So, I need some way of passing the Id to master page (for it to be 'fused' into the js script).
The best thing I can think of is that all my ViewModels should inherit some ViewModeBase that has a field to hold current language tab Id. Then, whatever View I'm rendering, this Id will always be available for the master page's hiding script.
However, I'm concerned that this ViewModelBase can potentially grow in an uncontrolled fashion as number of such pieces of contextual info (like current language) will grow..
Any ideas?
If this contextual information is needed by all views then having a base view model seems like a good solution. The question is where to populate this information to avoid cluttering all your controller actions. A custom action filter seems like a good place. In the OnActionExecuted method you could get the view model returned by the controller action and populate the contextual part if it derives from the base type.
Another option is to put the contextual information into the ViewData (strongly typed views can also use ViewData) but personally I hate having magic strings and doing casting in my views (this could be overcome by using HTML helpers that will handle this ViewData).
If you think that ViewModeBase will grow to much you can also have viewmodels implement an interface.
The View or Partial can have the type of that interface.
Thats especially usefull if only some pages have that functonality.
I have a question regarding keeping the controller and view separate. It seems to me that the controller should only pass a model to the view, and the view decides how to display the model. This way, the controller and model stay separate and can be independently developed. However, a lot of tutorials I see online and even in the book Pro ASP.NET MVC Framework, I see a lot of examples using either ViewData["string"] or TempData["string"].
Doesn't this introduce two problems? The first one is that the view is now somewhat coupled to the controller in that it has to know the name of the strings that the controller is setting in ViewData/TempData. The second is that these are loosely-typed, meaning there's no Intellisense. If I was developing the controller, I can't just tell another developer working on the view to just use Intellisense for the model, I'd have to give him the name of the strings, and if I ever change the string names, I'd also have to change it in the view.
I guess ultimately what I'm asking is, is this right? Or am I not understanding something?
View Data is one of the a way to pass information between the view and the controller but, as you said, there's no intellisence and it increase coupling. Instead, you should consider using a ViewModel. See Scott Gu NerdDinner example (freely available) about the way to use ViewModel and about the pros and cons of ViewDate vs ViewModel.
I hope it will help.
I think that the tutorials and book are using this method to try and make things a little easier to start out. However, I my opinion is that this might be starting some bad habits as you suggest.
The way I do it roughly based upon this article by Jimmy Bogard:
All views are strongly-typed
One specific ViewModel class per View
The View determines what data is in the ViewModel
I don't use the Auto-Mapper as he does though. I usually use a utility method to convert my Model object to the associated ViewModel object.
Yes you are right, it's considered best practice to create a class often called ViewModel that is being sent to/used in the View. The ViewModel usually contains the model as well as any other data the view might need, such as page number for a paginated list view, or values for a list for the view to display.