MVC Populate dropdownlistfor in CREATE view from another model - asp.net-mvc

So I basically have the same issue as this post: ASP.NET MVC - How to populate dropdownlist with another model?
The solution works... technically.. as long as the model is populated. However, I'm working with a CREATE view where the controller's action simply returns a blank "View()" obviously because it's creating something so you don't have any data yet.... yet I obviously still want the dropdownlist to populate from a model which gets it's data from the DB. If I try to run this code on a view with an empty model I get "Object reference not set to object" when it tries to grab the property that returns the list.
I tried instantiating a new, blank model in the Create action with the USING statement and set only PropertyTypeList property with a new instance of the Type model, and passed it to the view and it sort of worked... the view showed up with the dropdown of the other Type model populated, but it pre-filled in a bunch of the int/date types with 0's and 1/1/1900's because I have non-nullable fields. This is the closest I've gotten so far to simply letting the user create a new record with a pre-populated dropdown from ome of the fields that comes from a model.
I could just create a new Type model in the Create Action and assign it to the Viewbag or Tempdata, which I've done in the past, but this idea just makes me feel DIRTY. Viewbag disappears if the person refreshes the page so they get an error and is totally unprofessional. And I don't use Tempdata much because it relies on session state which gets very problematic if a user has my form open in mulitple tabs which could easily happen.
I feel like the solution from this post is SO close. It works fine when you're working with the EDIT action because you're passing a full model. But does anyone know how to get a dropdownlist to populate like this with an empty model? I tried something like adding an extra class to my secondary Type model
namespace blablanamespace {
public partial class PropertyType {
.. bla bla bla propertytype ID and name here
}
public class ViewModel
{
private readonly List<PropertyType> _keytypes;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
}
and
#Html.DropDownListFor(model => model.TypeID, new SelectList(new blablanamespace.Models.ViewModel().PropTypeItems))
but then I just get this error:
Value cannot be null. Parameter name: items
If I change the ViewModel class to instantiate a new list of types like so
public class ViewModel
{
public class ViewModel
{
private readonly List<PropertyType> _keytypes = new List<PropertyType>;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
I don't get the error this time, but I just get a blank form(yay) with a blank dropdownlist(boo!!). I figured this latter method would work since when I want to populate a new fresh list in the controller I basically do the same thing
List<ApplicationKeyType> _keytypes = new List<ApplicationKeyType>();
That behavior doesn't appear to be the same in the model.

Related

Two models in a single view without using a VM-class

I'm trying to put two partialviews together but I keep getting errors.
I've got a Subject-model and a Category-model, and I've made partial views which seem to work perfectly, but when I put them together in a single view this pops up:
Error 1 'Myproject.Models.Subject' is a 'type', which is not valid in the given context
this is the only code in my view:
#{Html.RenderPartial("_CategoryPartial", Myproject.Models.Category);}
#{Html.RenderPartial("_SubjectPartial", Myproject.Models.Subject);}
I guess I will have to create a seperate viewmodel if all else fails, but I thought on checking on here first
The problem is that you are passing in the type of Model rather than an object.
void HtmlHelper.RenderPartial(string partialViewName, object model)
You could do this if you changed your code to;
#{Html.RenderPartial("_CategoryPartial", new Myproject.Models.Category());}
#{Html.RenderPartial("_SubjectPartial", new Myproject.Models.Subject());}
Then you would need to populate the properties within each object.
An alternative is to change your code to call a class which returns the populated objects, e.g.
#{Html.RenderPartial("_CategoryPartial", Myproject.Models.CategoryRepository.GetCategory(id));}
#{Html.RenderPartial("_SubjectPartial", Myproject.Models.SubjectRepository.Get(id));}
You need to be passing instances of those models to the partials, whereas you are just specifying the types, hence the error.
So yes, for this view, I would create a view model, something like:
public class ExampleViewModel
{
public Category Category {get;set;}
public Subject Subject {get;set;}
}
and then do:
#{Html.RenderPartial("_CategoryPartial", Model.Category);}
#{Html.RenderPartial("_SubjectPartial", Model.Subject);}

Entity - Automatically Create MVC Controller with dropdown

There's probably a really basic answer to this question but I am new to Entity and MVC and am getting used to the basics.
I'm trying to automatically generate a MVC controller for the main table Sites with a dropdown for server. It seems like I would need a model like this:
public class Sites
{
public TTSites TTSites { get; set; }
public List<servers> server { get; set; }
public Sites()
{
server = new List<servers>();
}
}
This is using the classes TTSites and servers both with string server
But if I set this as my model class and my entity database as data context it says I need to define a key. Should I be using the base classes instead of the model or what? Do i need to set something up in the model or base class?
It seems like you've got some terminology confused. You code the controller actions in a controller class, and the routing engine determines what controller action to call based on the URL. For example, if you have a HomeController class with a default Index action, it might look like this:
public ActionResult Index()
{
// code here
}
This would be invoked with the default routing, if you went to your site with a URL like this (let's say your site can be hit via the www.mysite.com URL:
http://www.mysite.com/Home
That would get you into the Index action in the controller.
Ordinarily, one would use a view model to use on the UI side, and that would be populated from an entiy with the data you need in the view itself. If you had two entities like TTSite and Server, you'd populate the Sites view model like so, as a (very simple) example:
public ActionResult Index()
{
var servers = yourDbContext.Servers.ToList();
var ttSite = yourDbContext.TTSites.GetByID(1); // retrieve one entity by its ID value, this would be acquired dynamically based on some sort of user input rather than hard-coded
var viewModel = new Sites(servers);
viewModel.TTSite = ttSite;
return View(viewModel);
}
I'm not including anything regarding making drop-downs, just illustrating getting data into a view model and then creating a view with that view model.
Note that you would not use the Sites class as an entity but rather a view model, and setting its data based on entities from your database. You wouldn't be setting any primary keys in a view model class; those are the concern of the data model, and you've presumably already got those entities (such as TTSite) set up in a usable fashion in your data layer.
Once you've got a controller action and a view up and working, you can turn to getting the view model data into a form usable by a drop-down list, and going from there.

ASP.NET MVC Model

I have a View which can be accessed when the Model is populated with data and when the Model is completely empty.
When the Model is empty, it means that the user clicked on "Create New".
At the moment, I am getting a NullReferenceException because there obviously isn't anything inside Model. If I pass an object over to the view then the browser just freezes because the object contains null items inside it.
Is there a quicker/better way of doing this instead of doing:
MyObject myObj = new MyObj();
myObj.InnerObj = new Object(){data = ....};
...
I hope that makes sense :)
You can use the NullObject pattern:
Create a subclass of MyObject that has all properties prepopulated and methods that purposefully implement no behavior. For instance:
public sealed class NullObject : MyObject
{
public object InnerObj { get; private set; }
public NullObject()
{
InnerObj = new Object { ... };
}
}
It may not be the most clever way to deal with it, but I will sometimes wrap the Model-dependent code in the view in
#if(Model.Property != null)
So if you're having a single view for 'Create' and 'Edit', with the difference being the population of properties in the model, test those properties with an 'if', then code accordingly.
A better solution (I think) that we eventually implemented is an enum that we call "EditState" with two values: 'create' and 'edit'. Make the EditState a property in the viewModel. Set or check it's value and render the view accordingly (either with inputs for create, or displays or however you're setting it up.) It's a nice and easy to read way to differentiate between the create flow and the edit flow.

How to transfer value from a DropDownList to a property of a serialized model object

I'm testing some concepts in ASP.NET MVC multisteps (Style Wizards) with a small application which allow me to records organizations in a database.
To make things easier, I've a class OrganizationFormModelView that contains an object of class Organization and a property called ParentOrgList of SelectList type. The only purpose of the selectList property is to be used by a DropDownList.
I've also serialize OrganizationFormModelView to get the multisteps Wizard effect.
In my first view (or first step), I use a dropdownlist helper to assign a value to one of the the Organization's property called ParentOrganization, which draws data from the ParentOrgList.
...
<% = Html.DropDownList("Organization.ParentOrganization", Model.ParentOrgList)%>
...
The first time the page loads, I'm able to make a choice. And, my choice is reflected in my object Model all along the wizard' steps(see Visual studio in debugging mode).
But, when any time I'm redirected back to the first view (first step), I get the following error message:
"The ViewData item with the key 'Organization.ParentOrganization' is of type 'System.String' but needs to be of type 'IEnumerable'."
Thanks for helping
After considering carefully my code, I understand now what's going on. OrganizationFormModelView is the class that is being serialized, and here's its definition.
[Serializable]
public class OrganizationFormViewModel
{
public Organization Organization { get; set; }
[NonSerialized]
public SelectList ParentOrgList = null;
public OrganizationFormViewModel(Organization organization, SelectList cList)
{
Organization = organization ?? new Organization();
ParentOrgList = pList;
}
}
From that, I've concluded that, After each serialization process, ParentOrgList is set to null, so I need to find a way of re-assigning value to it. So, below is what I did:
public ActionResult CreateOrganization(string nextButton)
{
//Omitted for brievety
if (formViewModel.ParentOrgList == null)
formViewModel.ParentOrgList = repository.CommuneList;
//Omitted for brievety
}
I also, modified the View so that, even if the value of the ParentOrgList is continuously re-assigned, but the DropDownList keeps the user's choice. So, I choose an Helper overload with default value.
...
<% = Html.DropDownList("Organization.ParentOrganization", Model.ParentOrgList,
Model.Organization.ParentOrganization)%>
...
Now, everything is working perfectly.
However, If someone knows how to proceed differently with the Serialization business, it'd be helpful to share.
Thanks

Using LLBL as Model in MVC

I have settled on trying to use ASP.NET MVC but the first part I want to replace is the Model. I am using LLBL Pro for the model.
I have a table called "Groups" that is a simple look up table. I want to take thhe results of the table and populate a list in MVC. Something that should be very simple... or so I thought.... I've tried all kinds of things as I was getting errors like:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[glossary.CollectionClasses.GroupCollection]'.
private GroupCollection gc = new GroupCollection();
public ActionResult Index()
{
gc.GetMulti(null);
return View( gc.?????? );
}
This is all I am trying to do, I've tried lots of variations, but my goal is simply to take the data and display it.
Not sure if this would work, but you could try wrapping the EntityCollection into a ViewModel class and passing it to the View like so:
public class GroupsViewModel()
{
public GroupCollection Groups { get; set; }
// other items in your view model could go here
}
then convert your controller method to
public ActionResult Index()
{
GroupCollection gc = new GroupCollection();
gc.GetMulti(null);
GroupsViewModel vm = new GroupsViewModel();
vm.Groups = gc;
return View(vm);
}
I like this approach because each ViewModel is an object in-and-of itself.
You can use the AsEnumerable extension where your ????? are or change the type of your ViewUserControl(in the markup) to be of type System.Collections.Generic.List. Basically what you need to correct is the mismatch between the type of the View and the Model being passed in.
I'm not sure about your exact error, but I'd venture a guess that one of two things are happenging:
You are making some sort of invalid / illegal call on your LLBLGen object. If this is the case make sure you are setting it up right / calling right method / property etc.
The model you are passing to the veiw is too hairy for it to deal with. In this case, and in general, you should create a light 'View Model' class with just the data you want displayed and populate it from your LLBLGen object first then pass it to the view, which will be able to easily handle your view model class.
Here are some references:
http://stephenwalther.com/blog/archive/2009/04/13/asp.net-mvc-tip-50-ndash-create-view-models.aspx
http://nerddinnerbook.s3.amazonaws.com/Part6.htm
http://www.codinginstinct.com/2008/10/view-model-inheritance.html
Stemming off what Yuriy said, it looks like your view is strongly typed to a "collection" of a collection of your groupentity, and you are trying to pass just the collection of your groupentities. Make sure your "collection" type (IEnumerable, IList, etc) matches what type of collection you are sending in your controller, along with the type of the actual object in the collection.
View:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Controller:
System.Collections.Generic.List1[glossary.EntityClasses.GroupEntity]
Just a thought

Resources