MVC ViewModel binding for collection properties - asp.net-mvc

When a model is passed to view, the view has access to all data inside that model. But only for first time. When the view page is submitted say by clicking a submit button , then you don't get any data in the controller. For this you need to explicitly bind each and every model item either by giving a control to populate it or by using Html.HiddenFor(..)
But if my model is having a collection member which in turn having collection member .. upto level 3 or 4, then do I "have to" bind each and every member of these collections in order to get all data in action method after submit? If I am not displaying all these collections items on a view, then why should I bind it by writing huge code? But then I need them in the action method too. Is there any other simpler way to accomplish this other than explicitly binding it on view?
Following is the structure I have.
SalesModel
....IList HomeProducts
....int SalesID
Products
....int ProductID
....IList SecurityProducts
SecurityProduct
....SecurityProductID
....Description
....Price
....IList ProductFeatures
~ SalesModel is boud to aspx (View).
~ From this view, I have called partial view to show Home products (with model=Product).
~ From this partial view I have called another partial view (with model=SecurityProduct).
~ When I first time open the view, I get data at every level. But when I submit the view using submit button, then I dont get anything in SecurityProduct collection evern after binding every thing in FOR loop.
Thanks in advance.

yes, great example here: http://weblogs.asp.net/nmarun/archive/2010/03/13/asp-net-mvc-2-model-binding-for-a-collection.aspx

Resolved : by having hidden fields on both, the root level aspx and the child level ascx. Don't know how this resolves it but it solved the problem.

Related

Mvc How safe is viewbag?

My website is built around tabs. I have one single page with multiple partial views that display each tab.
The problem im facing now is I want to loop through files that the user has uploaded and display them in one of my partial views. This requires me to send the file list as a paramater in my action like this:
//Uploadedfiles is a function that adds the files to a list.
var files = UploadedFiles();
return View(files);
Because im only using one view to display all my partial views, i get:
The model item passed into the dictionary is of type 'Microsoft.WindowsAzure.Storage.Core.Util.CommonUtility+d__0`1[Delamapp.CloudStorageServices.UploadEntity]', but this dictionary requires a model item of type 'Delamapp.Models.LoginFolder'.
This means im required to not send a model item to my index view. Now, the only thing i can think off is adding my file list to viewbag and then display them on my view. BUT.. The files require high security. How safe is viewbag? Can you for example store sensitive login information in there? Can you think off some other way to accomplish this?
Thank you in advance
You can pass a model item to your view, but the model item you are passing doesn't match the type of model that your view uses (that's what the error message says).
So you need to do one of the following:
Modify your view to accept the model type that you are passing to it
Put the data you want to pass into the model type that your view is expecting
Create a new model type for both your data and for the view, and use that
In terms of security, I don't think using a view bag versus model binding really enters into the question of security. Both are just ways of passing data in between the controller and the view, and that all takes place within the ASP.NET process (perhaps you have ViewBag confused with Web Forms' ViewState?).

Divide a user interface into asp.net mvc views

I have a CSS #MainDiv containing a #TreeDiv on the left side and a #DataGridDiv on the right side.
The TreeDiv contains a Javascript Treeview with Department objects and the DataGridDiv
contains a Datagrid with Employee objects.
Changing the selection of a Department in the Treeview should change also the related employee objects in the DataGrid.
I have setup a DepartmentController. Both controls should be able to recieve data via ajax
independently from each other.
1.) What kind of object should my Index method return to display this aggregated data in the view?
2.) How should I divide my controls into what sort of views?
2.) How should I divide my controls into what sort of views?
Create a view with #MainDiv, #TreeDiv and #DatagridDiv. Let #TreeDiv host your tree control (You already know this). Create a partial view to display the datagrid with employee objects. Let #DatagridDiv host this partial view.
Now when a department is selected in tree control, you can make an ajax call to a controller method which accepts the department and returns the partial view containing the employee data. Update the #DatagridDiv with returned data.
Alternatively if you are comfortable with Json, your controller method could return the employee data in Json format (instead of partial view) and You can populate this into an html table inside #datagridDiv using javascript/jquery.
1.) What kind of object should my Index method return to display this aggregated data in the view?
In the Index method you can return your view which contains all 3 Divs and #TreeDiv populated with tree control. On the client side when page loads you can identify the selected department to make an ajax call and update #datagridDiv. This approach will have a it lag on the clientside, however you can use that to display some animation indicating the page is loading/div is updating.
If you dont want to add this lag period, identify the department that will be selected when tree view is loaded and populate the partial view for that department, add this to your #datagridDiv on the server side and deliver.

.Net MVC 4 View Engine WebForm

This is a quite interesting question, in my opinion.
I have a strongly typed view using the WebForm view Engine, I don't know if changing to razor would solve my problem.
PROBLEM:
I have one view with a list of cars, so of type IList <Car>.
And I have a button "Create a new Car" that popups, the popup is a form that is hidded and you call a jQuery UI command $('formName').dialog() to popup it, this form has the attributes of the possible new car, so probably a new view with a strongly typed Car. After fill in the form the database should be populated with the new car, and the list of cars should be refreshed using Ajax.
The main problem is that I can't use HTML Helpers to IList <Car> and for Car at the same time.
Briefly: What is the strongly type for that view ? Is it possible to define two views and the other one call using pop-up? Changing it to Razor would solve my problem?
Best regards,
Tito Morais
Don't mix the views for listing the cars and creating a new car together.
For instance, you can make a popup that dynamically loads a "_CreateCar" partial view, using jQuery dialog or similar component. Then when the partial view is completed, reload the list view using another Ajax call.
Maybe not so much an elegant solution is to create a complex view model like:
class ListAndCreate
{
public IList<Car> AllCars {get;set;}
public Car NewCar {get;set;}
}
IMO this is correct since that one view is responsible for listing all cars and creating a new one. Now, I'm assuming that your NewCar has values coming from your controller or something, where you need to pass a model to your view.
The other approach, that #Jonas mentions is also correct and more unitized. You could create a partial view _CreateCar with type Car, render it with Jquery/Ajax to load it into a dialog/popup and have the form POST to a Create(Car c) method in your controller.

Can a controller influence the _layout.cshtml file?

I'm stuck! I'm under the impression that the _layout.cshtml file is used for MasterPage-like content. Everything there is rendered on every page. Naturally, I want to write the code for rendering my sidebar menu in that file.
I want to dynamically display a list of Categories from my DB, but I'm having a problem with passing the actual model of categories to Layout.cshtml since it seems no controller actually touches it.
Any suggestions?
Otherwise please tell me how to approach this problem. I've been wracking my brain for the past three days and still no elegant solution.
I need to:
Dynamically fetch a list of Categories from the DB.
Display this list of Categories on every single view. (Hence the use of _layout.cshtml)
Elegantly handle each different categories click.
I'm at my wits end. :P How would you solve this?
_layout.cshtml
#if(isSectionDefined("Categories"))
{
<div id="sidebar">
#RenderSection("Categories", required: false )
</div>
}
index.cshtml
#section Categories {
<ul>
<li>Category One</li>
<li>Category Two</li>
<li>Category Three</li>
</ul>
}
see this : http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx
Any viewmodel that you pass to your view is automatically available within your master page. If you do not use RenderAction/Action which is the best approach, then you must create the necessary master page data in every action and add it to viewdata - either by having a common base class for your strongly typed viewmodel that contains all master page data or by using the viewdata dictionary.
I would strongly recommend that you go down the html.action approach though. In this way, you have a totally separate controller action for dealing with your list of categories. This action can retrieve the neccesary category data and return the categorylist usercontrol as a partialview and you will not have to worry about polluting all your other actions with this data.
As I see it, ViewData (and its relatives like ViewBag, Model, etc.) is meant for the specific current view. Your _Layout.cshtml is not specific to the current view; and it would be awkward if EVERY controller would have to pass the categories data in addition to whatever else data it needs to pass for the view.
Instead, what I do, is provide a static method in one of my helper classes that retrieves the categories from the DB. I also do some caching there, so that I do not have to hit the DB on every single request. The _Layout.cshtml then simply calls this static method. Simple and elegant.
If you wish, you can bring this out to a partial view, make it a helper method, whatever.
One note of caution though - my custom error view also uses the same _Layout.cshtml, and if the DB goes down, you get an exception trying to display the exception. ASP.NET MVC is smart enough to detect this and abort processing, but you're left with a nondescript default error page. What I did was to place try...catch statements around these dangerous calls, which quietly ignore the exception if the current page is the error view.
I've achieved something similar by having my ViewModels implement an Interface which has members that contain the menu data. In my action method I set that data. Then in my view I check to see if my view-model implements that inteface, pull the menu data out and render the menu (in a partial view actually)

MVC Url relative to variable ActionResult

Reasonably new to MVC. My problem is that I have a controller that has 3 different ActionResult's which are called depending on an enum.
All three action results return the same view but with different lists as the views model. In the view the user should be able to click on an item in the list and view the details based on the ID of the item.
e.g. Site/Facilities/Libraries returns the list of libraries, Site/Facilities/Libraries/1 returns the details. This works fine when you enter the full path but on the View itself clicking the anchor
#item.Name
on an item in the list returns the Url Site/Facilities/1 instead of Site/Facilities/Libraries/1. I cant use an ActionLink as the Action to call is dynamic. I know this could be solved by creating a different View for each type but I wondered if there might be another way?
Thanks in advance.
You can use such code (a javascript trick):
#item.Name
Or, if you want to use href property, you can use such code:
<%=Html.ActionLink(item.Name, "Facilities", ViewData("ActionName"), new {id = item.ID}) %>
(In that case you have to specify ViewData("ActionName") in controller).
I would suggest that you change it so that you only have one Action, but it takes an argument instead, and depending on the argument you push different lists to the View (perhaps using 3 different "helper-functions" instead). That's at least how I would implement what you are describing!
Good luck!

Resources