I have seen many posts about when to use ViewBag/ViewData vs ViewModel but i have not been able to find an explanation of the lifecycle of the ViewBag.
For example, i have two Action methods in one Controller:
// POST: /MyModel/Edit/5
[HttpPost]
public ActionResult Edit(MyModel _mymodel){}
and
// GET: /MyModel/Edit/5
public ActionResult Edit(int id){}
If i put some values in the ViewBag in the GET action method, to set up some Form labels, then when they user clicks 'Submit' button and the Form is posted back to the server via HTTP POST, the ViewBag values are no longer within the POST action method.
Can someone please explain (or provide reference to good article) the lifecycle of the ViewBag/ViewData ?
The data you put in the ViewBag/ViewData is only available during the life-cycle of the request within which you populated it. MVC does not have post backs. If you need something to persist over more than a single request, you should use Session.
Here is a decent article about the differences between ViewData, ViewBag, and TempData: http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications
The accepted answer here doesn't really describe the lifecycle of ViewBag/ViewData. It's unfortunate there appears to be no clear documentation about this. However, based on this:
http://blogs.msdn.com/b/varunm/archive/2013/10/03/understanding-of-mvc-page-life-cycle.aspx
It would seem the lifecycle is:
IIS request -> Routing -> MVC Handler -> Controller (with ViewData) -> View (with ViewData) -> Disposal
So, the ViewData (which ViewBag simply wraps) would actually be instantiated with the ControllerContext, at the same time TempData is instantiated. This occurs a few steps after Step 4: MVC Handler Executes.
There's an interesting step later where "If the Page has ViewData, the ViewData is set" during the handoff from Controller to View. ViewData is clearly available prior to this, so set can't mean instantiate. It appears to instead mean it's transferred from the Controller (which remember isn't available to a View) to the ViewContext (the container that provides the View access to ViewBag/ViewData, and Model).
The ViewData is presumably disposed of at the same time as the rest of the View.
It's important to also note that MVC Views are rendered from the inside out, so the particular View and any assignments it makes to the ViewBag will occur likewise in the order of inside to outside. That means something set on a View child page will be available to a Layout, but adding something to a ViewBag in a Layout and then reading it in a View child page will fail.
From MSDN - ViewBag: The dynamic view data dictionary, ViewData: The dictionary for the view data.
So these/this is a dictionary for a given view. You set its values in your action and you use it in your view. As Zach said it's not coming back with the subsequent request. You can send its values back to any given action as a form field, in querystring, etc, but these values won't be automatically available as VieBag's properties.
ViewBag and ViewData are used for the same purpose. They are used to pass data from controllers to the View. When we assign any data or object to them they are accessible in the View.
ViewData: ViewData is a dictionary of objects and they are
accessible by string as key.
ViewBag: Uses the dynamic feature. It allows an object to add
dynamic properties to it.
Related
I am a learner in MVC, I am facing a issue in passing data, I want to pass a data from one view to another view in MVC, How can I do this? help me,
I will select the firstname in one view and I want to pass the firstname to another view?
Views don't communicate with other views.
Consider this illustration from the Wikipedia page:
A view doesn't connect to another view. It is simply an interface presented to the user. Data which originates in a view (such as user input) would then be passed to a controller, which in turn directs (controls) the data/logic flow of the application. (Not the logic itself, the flow of the logic.)
That controller will then interact with the models (if necessary, sometimes the only action for a controller to perform is to immediately render another view, such as a redirect in a web application) and present the next view.
If data sent to the controller is needed in the next view, it would be the responsibility of the controller to include it in the next view.
I am developing multi step form with sitecore and mvc. In each step I need the sitecore context and I am using controller rendering for the same. Now as sitecore works I need to add the controller name and action for my rendering so basically I can only use one controller action for each rendering.
In my case I have used the same action name but different parameters type for each step in multi step form. Ideally I would like to have different controller action name for each step within multi step form. Can anyone please help me with that?
Thanks
I'm not sure I understand the question completely. Are you trying to use a single .cshtml file for all the steps? If so, you can define multiple controller renderings for the same View in the Sitecore CMS. In the renderings section, define each step of your multi-step form as separate controller renderings. You can use the same controller for each, but specify a different action.
In your controller logic, you can specify to return the same View, but pass different properties into your Model object.
For example, you might do something like this:
public ActionResult Step2(){
var context = RenderingContext.Current.PageContext.Item;
var otherParams = "SomethingForStep2";
var model = new MyModelObject(context, otherParams);
var view = this.View("Path/To/My/View", model);
return view;
}
In the example above, I assume you have defined some sort of Model object where you can pass in whatever parameters you need so that your view can use this to render.
If you are using different views, then you will just return a different view for each action, again passing in a model to the View to help it render.
If you are using AJAX (which I would assume) I would recommend the following:
Serve each view/step of your multi-step form using a unique HttpGet action in your controller
Represent each view/step of the form with a unique item and a unique view (assign the views to the items and use an empty Layout to enable the form/view to be rendered on its own)
Handle each form's post action with a unique HttpPost action in your controller
From the HttpPost action, return a JSON object which can be handled client-side. Include in this result properties such as success, failure, validation errors and the next step of the form to display (a URL for the following AJAX request - call this property NextStepUrl)
In your client-side JavaScript have a function to handle the JSON result object returned by your controller's POST action. If successful read the NextStepUrl property then use this to perform an AJAX GET request for the next step of the form
This approach means that on each GET request you will have a valid RenderingContext from which to read your controller rendering's datasource.
If you need to have the RenderingContext during your HttpPost actions you can simply include a hidden field with the ID of the datasource item and read this in the HttpPost action, or you can use some custom model binding to achieve the same thing in a slightly cleaner way.
I'm trying to use a html.dropDownList helper with a strongly typed view model with ajax. I can't the post the code because of the nature of the project.
Here basically what I'm doing...
loading a mvc view via a strongly type view model
clicking a button which does an ajax post to a controller method
using the TryUpdateModel to parse the view model
processing the request
rendering a parital view for the ajax request
According to the article listed below, the problem is that "ASP.NET MVC assumes that if you’re rendering a View in response to an HTTP POST, and you’re using the Html Helpers, then you are most likely to be 'redisplaying a form' that has failed validation."
http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx
Instead of "redisplaying the same form value", I need the html.dropDownList to be set to the same value in the view model.
Does anyone know of any custom dropDownList helpers or have any ideas of how to achieve this?
Things I've already tried/considered
per the blog, manually removing the modelstate item...didn't work - didn't pick up the value in the view model - just defaulted to the first item in dropdown list
considered just writing a regular select list...but this is sloppy and cumbersome since I'm rending multiple select lists in a loop
writing my own custom dropDownList helper...wanted to avoid reinventing the wheel
Thanks in advance
Its not fully clear to me what your problem exactly is, but I've had a similar problem. I used the Html.DropDownListFor(, SelectListItem[]) helper. At postback it sets the value to the choosen one. Your postback view doesn't require to have all the fields of the original model.
#Html.DropDownListFor(model => model.SelectedValue, MyModels.DropDownSelectables());
Here I want the selected value as the model.SelectedValue variable and within my (seperate) model I made a array of selectlistitems. The rest is automagic.
Hope it helps, D
I have 2 Cotrollers.
First one sets the ViewData property like this
ViewData["Error"] = "something";
I am able display this message on the page.
Second Controller loads the grid.
When i try to set the ViewData property from that Cotroller, It does not show up on the page.
Do you why? Am I doing anything wrong here?
Please let me know.
Thanks!!!!
Using two controllers for a single view is a bit of a no-no.
Look into ViewModels to pass all of the required data to your view. You can then create a PartialView for your grid, and pass the necessary model to the Partial View as well. Consider ViewData / ViewBag a last resort when a ViewModel doesn't work.
Are you trying to use two separate controllers to render the same view? If so you should probably consider, breaking the view logic of your "grid" into a partial view that you in turn render within your primary view.
As you mentioned "ViewData" twice, another item for consideration is the implementation of the ViewModel Pattern. The Viewdata dictionary approach is fast and fairly easy to implement. however, it is not type-safe and errors due to typo's will not be caught at compile time.
I have an ASP.NET MVC3 application developed with C# and Razor.
I have a View, View1, mapped to and Action Method, ActionMethod1. In order to respect naming conventions I would like to rename View1 to View2 and still keep it mapped to the same action method.
The problem is that when I change the name to View2 the View is not anymore recognized by ActionMethod1.
I know that I can specify the name of the View explicitly as first parameter in the overload method View(viewName, model) but since there is already a mapping between ActionMethod1 and View1 I found this solution quite "dirty".
How can I make the Action Method ActionMethod1 understand that it should refer to View2 and give up on looking for View1?
I think you should look into the ActionNameAttribute. That will allow you to change the name of the action although I am thinking that you most likely will have to use the method where you explicitly return
View(viewName, model)
in order to get the results you want.