ASP.Net MVC 3 - Single controller, single action and multiple views - forms

I would like to know what is the best method to have an action return different views. Let's say you have a form for submitting data, but you want to choose the view depending on what data is submitted. I would prefer not using a redirection, since there is stuff I want to be displayed in the data that is posted.
An example of this would be to have an Edit form that displays a Details view when clicking on Save, but without using a redirection.
I know this could be done with a single view containing a conditional if statement to display this or that, but there are cases where I would prefer my views to stay simple without too much code in them. If the controller could just choose the view to display once the data is posted, this would be great.

There is an overload to the View() method that allows you to specify the name of the View you want to return.
return View("DetailsView", model);

You should be using the Post/Redirect/Get pattern. You can still "display stuff." You can pass an ID on the URI and look them up in the new GET or use TempData.
Attempting to circumvent Post/Redirect/Get is not a good solution. Among other things, it breaks the back button.

Related

How to pass a View to my ViewModel so an I*Service can use that View to do something

https://github.com/brianchance/MvvmCross-UserInteraction is a very nice plugin for showing cross platform Alerts!
But for this question, can we assume it can not use a UIAlertView (or some other top level MessageBox type call on other platforms) but needs to show a Message within a given subsection of the screen (i.e. on IPhone you would need to supply a UIView to the plugin which it will use to show the message within).
So, how would you set this up so the ViewModel knows what View to use as its display container?
As a specific example, if I wanted an Error Service, as so -
public interface IErrorPFService
{
void Show();
void Hide();
void SetErrors(List<Error> errors);
}
and I create a platform specific implementation for it.
If I inject this into my ViewModel so it can control Error Show/Hide/Set how do I tell it the UIView (or equivalent) that I want my Errors to show within?
Can I just expose the IErrorPFService field as a public property and do -
MyViewModel.ErrorPFService = new ErrorPFService(View);
in my ViewDidLoad ...
Or is this coupled incorrectly vs Mvvm Practice?
I would expect the ViewModel to subscribe itself to the ErrorService.
When receiving a message it would expose it in a collection(?) and the View would bind to that collection.
This way the View is unknown to the service and the ViewModel has the chance to influence the View contrary to your solution.
It would help if you could give an example for the scenario you are describing.
Sometimes, the way you visually want to display something might not be the best way, so if it's possible for you, you might find a different and simpler way, which spares you from having to find a solution regarding what you are describing.
Generally, I always do the best I can to avoid the idea of having to actually pass a 'view' or an abstraction of it, from the view-model to view. Also, cross-platform wise, things can work very different in terms of UI interaction. You can find yourself in a situation when things are complicated just because UI works differently than what you expected.
But let's try find another perspective:
At any given point, the view knows what data \ feature it's displaying. So when you are calling from the view-model an user interaction action (by a service, property change, event, etc) the view should 'expect' it.
For example, the platform specific user interaction implementation is able to get the currently displayed top-view and interact it in a platform specific manner or based a relationship. In your example, the message-box can be displayed in a specific sub-view of the top level view.
In advanced scenarios, I guess you could try to create a cross-platform approach for this, but you should try to put in balance all the abstraction you want to create just for that. Think about doing this as a plan ... Z. If possible. Again, giving an example might help.

Backbone Model View: Switch between editing (via form) and display

With Backbone I have created a view for a model. I would like to provide the following workflow to the users:
a) Initially, model content is just displayed via a template and there is an edit button
b) if the user clicks the edit button, the model content will be displayed in a form and can be saved back to the model by clicking a save button.
c1) if saved successfully, the new model content we be rerendered via the template and displayed again
c2) if there were any validation errors, the form is updated with the errors.
I came up with the following options on how to implement this. But I am not sure, on the best practices. Any advice is highly welcome.
Option 1: 2 sub views (one for the displaying the content, one for editing it) that are dynamically created on any switch between display and edit (and dropped afterwards).
Option 2: 2 sub views (one for the displaying the content, one for editing it) that are hidden/unhidden on any switch (like toggle)
Option 3: 2 sub views (one for the displaying the content, one for editing it) that are assigned to the parent element on any switch.
Option 4: 1 View to manage the model content and 2 templates (one for displaying and one for editing) that are rendered on any switch between between display and edit.
From my gut feeling, I clearly would prefer option 4, since it will need ony 1 view that could handle all logic. But maybe I have overseen something in terms of performance, event handling, DOM access etc. So any hard arguments on the pros and cons of the 4 options are highly appreciated.
What do you think?
I've been working on something like this except that the edit button is attached not to the whole model, but to individual attributes, which can be edited "in place". To do that I've been using backbone-forms, replacing the element to be edited by a backbone form and then re-rendering it after the form has been submitted. This works quite well.
In your case, since you're editing the whole model at once, it would actually be easier. When the user clicks the edit button, replace the view with a backbone form, and when they submit that re-render the model view with the errors or success message. Backbone forms makes displaying error messages on the form quite easy.
I have tried option 3 (2 subviews) and option 4 (1 view using 2 templates).
Here is an argument for 3:
Switching between readonly view and edit view in backbone js
And here is an article promoting 4, under "Switching a Contact Into Edit Mode":
http://net.tutsplus.com/tutorials/javascript-ajax/build-a-contacts-manager-using-backbone-js-part-4/
I found option 3 to more trouble, because now you have 3 views using the same model. It brings up issues in the DOM, because now there is an el for the parent and an el for each child, nested inside. It also brings up issues with encapsulation, because the child views should really be inherited from the parent, but that's difficult with javascript:
Access parent class member with javascript inheritance?
I wanted option 3 to work more like an abstract base class tied to the el in the DOM. Then view and edit could inherit from it and internally set the el, preventing nesting of two els. But this breaks how backbone.js nests views:
Swap/switch/exchange backbone.js views in place?
Option 4 "just worked" the first time I tried it. It's trivial to have an editTemplate that gets rendered if View.editing is true. And in practice, the read-only view tends to be so small, with so little interaction by definition, that it only adds to an edit view by a few lines.
The downside to 4 is that you dirty your view with switching logic.
An argument for 4 is that it increases the possibility to reuse code and reinforce DRY.
One last argument for 4 is that you might have a "rich" form at some point that is always on, and maybe you only want to enable editing on specific form elements. For example a Contact form might have an Address view inside that handles its own updating. So view/edit might not be mutually exclusive down the road.
I finally resigned myself to going with what worked (option 4) because both options use two templates in the html file. The backbone.js implementation details don't matter to the end user.
I think this is all worthy of some lengthy articles weighing the pros and cons of each approach, with real-world examples. Backbone.js also needs to have backbone-relational built into it, and probably Backbone.ModelBinder, with a better ._super implementation. If some of these concepts were more fleshed out, it would make it easier to implement option 3 IMHO.
But I'm curious what others think, because neither 3 or 4 are perfect as they stand now, and I'd like to know what the best practices are for this, since form handling is one of the primary reasons that people get into backbone.js in the first place.

Creating reusable widgets

I`m using asp.net mvc 2.0 and trying to create reusable web site parts, that can be added at any page dynamically.
The problem I have is how to load a partial view with all related js and data? Ive tried the following ways to do that:
Use partial view and put all the js into it. In main view use render partial. But to initialize partial view I need to add model to current action method model to be able to make RenderPartial("MyPartialView", Model.PartialViewModel).
Also I do not have a place to put additional data I need to fill my form(like drop down lists values, some predefined values etc).
Use RenderAction, but it seems it have same problems as RenderPartial, except for I do not need to add anything to any other model.
Any other oprions are greatly appreciated.
As I understand it, RenderAction performs the full pipeline on the action, then renders the result - so what is rendered is the same as what you'd see if you'd browsed to the action.
I've used RenderAction to render 'widgets' throughout a site, but in my view they should be independent of the page rendering them, otherwise they're not really widgets and should be part of the rendering page's code instead. For instance, if there's a log in form, you will always take the user to a page that can process the information, no matter what page they are currently on, so this makes for a good widget. Other ways I've used it is to show a shopping basket or advertising. Neither of which are dependent on the page being shown.
Hope this helps a little!

ASP>net MVC reusable partials

Having worked with .net in both winforms and ASP.net for a few years I am now starting to get into MVC (a little late I know). One major confusion for me is the concept of reusable 'components', similar to the concept of a usercontrol in webforms.
For example, I would like to have a number of 'widgets' within the members area of my site, one of which is the details of the logged in users account manager. I can create this as a partial however when the page loads the data needs to be passed in as part of the ViewModel / View Data. I would like to use this widget in a number of different sections which would then mean that I need to put the code to pass the data in into a number of different controllers. This seems to violate the DRY principle, or am I missing something here? I would ideally like everything to be encapsulated within the 1 partial which can then be used in any page.
You can go three ways:
1) For simple controls without much logic, you can create new instance of the custom view model for the control:
Html.RenderPartial("YourControl", new YourControlViewModel () { Param1="value1", Param2 = Model.AnotherValue });
2) If you need some back end logic for the control, you can use
Html.RenderAction("ActionName", "SomeControllerName", RouteValuesDictionary);
It will call standard controller action, use the view, and insert the resulting output back to the page. You can add [ChildActionOnly] atribute to the controller method to ensure that the method will be available only from the Html.RenderPartial. It is slightly violating the MVC principle (view shouldn't call controller), but its great for widgets, and it is used in the Ruby on Rails world without much issues. You can check great article from Haacked
3) Create custom html helper for tasks like custom date formatting, calculating etc..
In your case, I would choose the number two.

Returning object model to a view, that is handled by different controller

how can I pass an object model to a view, that is partial view on a master page?
regards
You might consider creating an another object that more closely represents the view you are trying to render.
Let's say i have an MyDomain.Order object, so I make a view page that looks something like ViewPage<MyDomain.Order>. Now, let's say that I have a menu that is driven off of a logged in user, as example. It wouldn't make sense to have menu as a property of MyDomain.Order. I would create another object, specifically for the view, call it something like OrderPageModel and have MyDomain.Order and List<MenuItem> as properties of this new object, my view being set up as ViewPage<OrderPageModel>.
The other thing to consider might be something like Html.RenderAction(). Same scenario, I have a view, and as you mention in your question, it has a master page, and as in my example, lets say it hosts a menu common to your site. You could create a partial view (UserMenu.ascx) and a controller (SiteController.cs) with an action (UserMenu) that calculates the items for the menu. Inside your master page, you can then call <% Html.RenderAction("UserMenu","SiteController") %>.
I would use the first example if it could be something made for a particular view: just make it a part of the model. I would use the second example if it was something more generic to the site, like a menu.
You could specify the location of the view:
return PartialView("~/Views/SomeOtherController/SomePartial.ascx", someModel);
Best bet here is RenderAction over RenderPartial. Your child controller can easily figure out if the user is logged in and render the right partial rather than making your master page worry about these details.