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.
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 currently working on a project in MVC 3 where I am leveraging Entity Framework to persist one data model over two Views which each contain one HTML Form (similar to wizard-based design).
Yet after the user fills out the appropriate fields on the first View and submits the form, client-side validation for the entire model is triggered, and validation errors are shown for fields that will not even be available for input until the second View instantiates.
I have currently implemented a workaround where I simply turn off client-side validation for the first View entirely, but I am certainly not keen on the idea of populating my model with data that has not been validated at all. This is bad. M'kay.
Is there any way to partially validate the fields on the first View and not trigger valdiation for the whole data model?
That's where ViewModels comes. Instead of directly binding the domain model with the views, you should create view models over them and bind to the views.
If you are not required to put validation on the EF models directly then you can use the MetadataType to do partial validation as needed. Take a look at my long example here on stackoverflow.
Thanks for the input all. However, I was able to obtain a solution in a very simple way. By placing the following code in the HttpPost element of the first View...
if (ModelState.IsValidField("FirstField") && ModelState.IsValidField("SecondField"))
return RedirectToAction ("NameOfAction", model);
else
return View();
...I was able to achieve partial field validation. However, this field-specific approach will ONLY work provided the Submit button on the first View has class "cancel" and the additional validation errors that are generated (for the fields that are NOT present on the first View) are manually cleared before the above if statement. To do this, use:
ModelState["FieldName"].Errors.Clear();
No major change in architecure. No partial Views. No handing off unvalidated Data.
Works very well...
NOTE: If the second View loads with validation errors, use:
ModelState.Clear();
in the Action where the second View is initially called. This will make the second View load clean and error free, while still showing the validation errors later upon final form submission.
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 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.
I've been tasked with converting an existing webforms application to mvc 3 razor.
The application currently has an aspx page which has a static header user control and "n" amount of other user controls which are dynamically created. In the code behind for the file, it is executing the below code in various specific sections to dynamically process user controls with information provided from the database.
I know how to statically create partial views, but being somewhat new to MVC, how would I go about defining this new "aspx" page and also to dynamically find, load and add the partial views (each equivalent to the below webforms code)?
btw, the code will be in C# as well.
Dim parent As Control = Page.FindControl(_moduleSettings.PaneName)
Dim portalModule As PortalModuleControl = CType(Page.LoadControl(_moduleSettings.DesktopSrc), PortalModuleControl)
parent.Controls.Add(portalModule)
I think I can do something like this when the page is rendering. I want to make it as simple as possible.
The "PaneName" will be set in the parent variable which determines where in the page it will be shown (Left, Right, or Main)
The "DeskTopSrc" is the name of the partial view to display.
So, take the code out of the code behind and place it in the main View. Perform the above processing logic in the View (boy, switching from aspx code behind to a View throws me a loop. I gotta get use to doing the processing in the View. Reminds me of Classic ASP, but the Razor syntax will help).
Display the partial view via the #Html.PartialView('partial view name'). This view might have a grid in it associated with a specific model.
Below is the part I am unsure about.
I've done database processing for a main View associated with a Controller, but not with a partial view that needs to do some database processing.
Perform any database processing logic (if any) for this partial view in the Controller associated with the main View (which contains this partial View).
In the Action Index method while looping over these "partial views", I can get the data and display the views....
Ahhh, I think I got it.....
After carefully thinking it through, if someone could help me out with the last statement here, I would greatly appreciate it.
1.Have partial views already statically created with the specific HTML markup that I need in the Views/Shared folder.
2.In the main View, I will already have
#Html.Partial(ViewData["partial_view_left"])
#Html.Partial(ViewData["partial_view_right"])
#Html.Partial(ViewData ["partial_view_main"])
statements in specific locations of the HTML which will render the partial views as I retrieve their names from the database.
3.In the Controller's Index method, I need to do the following:
a) Loop through the converted logic (from the CodeBehind of the existing WebForms page in the PageLoad event) in the Index action method of the new Controller which will load the partial views dynamically.
1) Find out where the partial view will be displayed (left, right, main) from the database via the "parent" variable.
2) Find out the name of the partial view that will be displayed from the database via the “DesktopSrc” variable.
eg: ViewData["partial_view_left"] = "left_view"; OR
ViewData["partial_view_right"] = "right_view"; OR
ViewData["partial_view_main"] = "main_view";
3) Right here is where I am unsure of how to properly display the partial view.
I need to have the equivalent of a webforms "Controls.Add" method to render each partial view from the Controller that I retrieve from
the database from step 3.a.2
What statement can I use in this Index method of the Controller that will accomplish this?
In other words, if I dynamically need to display several partial views inside of a parent view, how is this accomplished in MVC?
I know for each partial view, I can send over the model associated with it, but I just don't know how I can place several partial views inside the main view page at run time from one Action method.
If your partial views need to do some processing, like database retrieval, then you should use
#{Html.RenderAction("ActionName");}
This will call an action method (which doesn't have to be on the same controller) that can dynamically choose a view based on logic, and populate the ViewModel with data from the database.
public ActionResult ActionName()
{
var modelData = GetData();
return View(settings.DesktopSrc, modelData);
}