so my view starts off like this
#model ApplicationName.Models.A
and takes in the my database elements from A so if i were to use #Html.DisplayFor(model => model.Whatever) it will display that element from the database in my view.
However i have another attribute that i want to also display on this same page/view. But it is in Models.B
So i need to end up with this
#Html.DisplayFor(model => model.WhateverFromB)
all help greatly appreciated
You should use a view model which encapsulates both an A and a B. For example:
class MyViewModel
{
public ApplicationName.Models.A A {get; set;}
public ApplicationName.Models.B B {get; set;}
}
Then pass this single view model to the controller. You would then of course access your properties like:
#Html.DisplayFor(m => m.A.Whatever)
#Html.DisplayFor(m => m.B.WhateverFromB)
Similarly if you do not need every property from A and B, or the semantic difference between the two database objects is not important to the view, you might consider doing the following instead:
class MyViewModel
{
public object Whatever {get; set;}
public object WhateverFromB {get; set;}
}
Populate the individual properties of the view model and use accordingly. You can of course use a combination of the two, including a full A along with a WhateverFromB.
Realistically you should create a ViewModel which contains all the properties you need and you can populate that ViewModel from multiple Models. Then use the ViewModel as the 'model' in the MVC page.
However to answer your question. Just write an additional Html.Display entry
In your controller
ViewBag.WhateverFromB = b_obj;
and then in your view
#Html.Display(ViewBag.WhateverFromB)
You should use a ViewModel for this. When you require more than one model in your view this is a good way to go. Include what you need from the Models you are using in the ViewModel class and reference it in your view instead of the Model.
This will get you going with ViewModels
http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-3
ViewBags and ViewData will work but there are appropriate times to use each.
http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications
Related
I've been able to successfully return a model to a view and display the results in a strongly-typed fashion.
I have never seen an example where multiple models get returned. How do I go about that?
I suppose the controller would have something like this:
return View(lemondb.Messages.Where(p => p.user == tmp_username).ToList(), lemondb.Lemons.Where(p => p.acidity >= 2).ToList());
Does MVC let you return multiple models like that?
And then in the view I have this line at the top of the file:
#model IEnumerable<ElkDogTrader.Models.Message>
And I frequently make calls to "model" in the view.
#foreach (var item in Model)
If there were 2 models, how would I refer to them separately?
Is this possible with multiple models, or is this why people use ViewBag and ViewData?
You can create a custom model representing the data needed for your view.
public class UserView
{
public User User{get;set;}
public List<Messages> Messages{get;set;}
}
And then,
return View(new UserView(){ User = user, Messages = message});
In the view:
Model.User;
Model.Messages;
The ViewBag is useful because it is dynamically typed, so you can reference members in it directly without casting. You do, however, then lose static type checking at compile time.
ViewData can be useful if you have a one-off on your view data types and know the type and will be doing a cast in the view anyway. Some people like to keep the actual typed view pure in a sense that it represents the primary model only, others like to take advantage of the type checking at compile time and therefore make custom models needed for the view.
I believe ViewModel should be the way to go. Within the customary ViewModel, you can reference other models or define all the related domain models in the viewModel itself.
Just to make it clear, my question is how do you CREATE multiple objects using a single view. My ViewModel works fine, I can display multiple objects no problem.
Its been a while between .NET coding (last time I was coding in 2.0). I have created an MVC 4 project and successfully created a ViewModel (displaying data on a single view from multiple objects).
However, I cheated. I populated the database directly. I now face the question in reverse, what is the best practice for creating multiple objects from a single view?
In my example, I have a User, who has a userId. The userId is a foreign key in UserDetails.
Just trying to get back into the swing of it and wondering what you guys do?
There are 6 ways to pass multiple object in MVC
ViewModel
Partial View
ViewBag
ViewData
TempData
Tuple
Each one have there own pros and cons.you have to decide base on your issue in hand.
For more information you can refer code project article on it: How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
Let me give advantage and disadvantage of View Model
ViewModel :
Advantages
ViewModel allows us to render multiple model types in a View as a
single model.
Great intellisense support and compile time error checking on View
page.
ViewModel is good for security purpose also as Views have only what
they exactly need. Core domain models are not exposed to user.
If there is any change in core domain model, you do not need to
change anywhere in View code, just you need to modify corresponding
ViewModel.
Disadvantages
ViewModels add another layer between Models and Views so it increases
the complexity a little bit. So for small and demo applications, we
can use tuple or other ways to keep the things simple for demo.
Option 1:
The best approach is to use strongly typed views with Model or ViewModel.
For Example, you have two classes User and Education, you want to display all education details of user in a view, you can create a custom view model and pass it to view, where you view is strongly typed view model:
public class User
{
public int UserId {get;set;}
public string UserName {get;set}
-------
------
}
public class Education
{
public int UserId {get;set;}
public int DegreeId {get;set;}
public long Marks {get;set;}
---------------
--------------
}
Now create a view Model like this:
public class EducationViewModel
{
public User user {get;set;}
public List<Education> educationList {get;set;}
}
now pass the ViewModel to View and do this in View:
#model AppNameSpace.ViewModels.EducationViewModel
Tip: Create a folder named ViewModels and put all the viewmodel classes in it.
Option2:
Option 2 is to user ViewBag and pass multiple object from control to your view, ViewBag is accessible when you set some value in it in controller, you can access in the view of that action, after that it is automatically washed out, and its null if you access again it.
you can use ViewBag like this:
ViewBag.Message = "Using ViewBag";
and read value like this in View:
string Message = ViewBag.Message as string;
Option 3:
Option 3 is to store data in TempData, its once read only, means you set value in it, and when you read it, its automatically removed, TempData internally uses Session Variables.You can use TempData like this:
TempData["Key"] = "value";
now you read it in view:
string val = TempData["Key"] as string;
after reading it, it will be automatically removed, but you can keep it if you need it further like this:
TempData.Keep("Key");
I have the following code and I get an error saying:
has no applicable method named 'TextBoxFor' but appears to have an extension method by that name.
My Code:
#Html.TextBoxFor(ViewBag.taglist)
Why don't you use strongly typed model in your view instead of ViewBag. This will make your life easier.
In fact, you must use a model to with TextBoxFor, otherwise it just won't work. See the definition of TextBoxFor - as a second parameter it takes a lambda expression that takes a property form a model.
If you want just a text box, two options:
#Html.TextBox("NameOfTheTextbox", (String)ViewBag.SomeValue)
or just go
<input type="text" value="#ViewBag.SomeValue" />
No complex solutions required.
I agree with other suggestions of using a strongly-typed model, because the compile-time error support is so much better than debugging exceptions. Having said that, in order to do what you want, you can use this:
#Html.TextBox("NameOfTextBox", (string)ViewBag.taglist)
Update: A Simple Example
Now that you've provided some details in your comments, I've taken a guess at what you might be doing, in order to provide a simple example.
I'm assuming you have a list of tags (like SO has per question) that you'd like to display neatly in a textbox, with each tag separated by a space. I'm going to assume your Tag domain model looks something like this:
public class Tag
{
public int Id { get; set; }
public string Description { get; set; }
}
Now, your view will need a list of the tags but will likely need some other information to be displayed as well. However, let's just focus on the tags. Below is a view model to represent all the tags, taking into account that you want to display them as a string inside a textbox:
public class SomeViewModel
{
public string Tags { get; set; }
// Other properties
}
In order to get the data you want you could grab all of the tags like this:
public ActionResult Index()
{
using (YourContext db = new YourContext())
{
var model = new SomeViewModel();
model.Tags = string.Join(" ", db.Tags.Select(t => t.Description).ToList());
return View(model);
}
}
Notice how I'm directly passing model to the view.
The view is now very simple:
#model SomeViewModel
#Html.EditorFor(m => m.Tags)
The model directive is what signifies that a view is strongly-typed. That means this view will expect to receive an instance of SomeViewModel. As you can see from my action code above, we will be providing this view the type that it wants. This now allows us to make use of the strongly-typed HtmlHelper (i.e. Html.XxxFor) methods.
In this particular case, I've used Html.EditorFor, as it will choose an appropriate input element to render the data with. (In this case, because Description is a string, it will render a textbox.)
You cannot use Html.TextBoxFor without explicitly setting a type for your model within the view. If you don't specify a type it defaults to dynamic. If you want to do model binding then you must use an explicit type rather than a dynamic type like ViewBag. To use Html.TextBoxFor you must define a model type that defines the property that you wish to bind. Otherwise you have to use Html.TextBox and set the value manually from ViewBag. As others have said, you will make your life much easier if you use a statically typed model and take advantage of the inbuilt MVC model binding.
You have to use a lambda expression to select the property, plus you will have to cast the ViewBag member to the correct type.
#Html.TextBoxFor(model => (string)ViewBag.taglist)
Ok I just discovered about the EditorForModel in MVC and I want to know when I should use this instead of an EditorFor on each of my property? And why does when I add a strongly typed view it does not use this and build an EditorFor on every property?
I'm late on this... but thanks for the info!
Since the accepted answer is a link-only answer (and was removed), I thought I'd actually answer the question derived from Brad Wilson's Blog: ASP.NET MVC 2 Templates, Part 1: Introduction.
The model expressions are simple helpers which operate on the current model. The line DisplayForModel() is equivalent to DisplayFor(model => model).
TL;DR the same idea can be assumed for EditorFor(model => model) and EditorForModel(); these helper methods achieve the same thing. EditorForModel() assumes the model expression is the #model that was passed to the view.
Take the following models and view for example:
public class Person
{
public string Name {get; set;}
public Address MailingAddress {get; set;}
}
public class Address
{
public String Street {get; set;}
public String City {get; set;}
public String State {get; set;}
}
Create.cshtml:
#model MyNamespace.Models.Person
/* So, you need an Editor for the Person model? */
#Html.EditorForModel()
/*the above is equivalent to #Html.EditorFor(model => model) */
/* you need to specify the Address property that the editor accepts? */
#Html.EditorFor(model => model.MailingAddress)
You should use it when possible, but sometimes you will need the customizability of individual Html.EditorFor uses.
As for why the built-in templates don't use it, that's mainly because they are silly in general, but also because, if I recall, they need to wrap elements (like table rows etc.) around each Html.EditorFor.
#Html.EditorForModel() ?? And give up the fun of writing your own view? smile
Besides the fun, doing so as a habit is rather dicey. Consider the following common scenario - you have a bool variable say IsMale in your database in your customer table. Well obviously you don't want the default version (IsMale with a check-box) - you probably want something a bit more friendly, say a {select, Options .... , /select} tags, right? that's where the view really starts kicking in. That's the customization. Every view is a little different. You have the RAZOR engine, exploit it to the max! In your view you can override anything, or even manually type an entire chunk of HTML code of your own.
For instance I have a model X with properties Title(string) and Valid(bool). I need to show same model on two separate pages with different field labels and input controls.
E.g. "Title" for title and "Valid" for valid on one form while "Destination" for title and "Returning" for valid on the other.
I guess the easiest way would be to have two different views for the same model. But is it really a MVC way to go?
Thanks
Well, let's say you have some View-folder called List, and one called Details - and displaying the Model in the two should be different.
You can create a DisplayTemplates folder within each of the two folders, and create a PartialControl with the same name as your Model, and also strongly type it to your Model.
In your different views you can then do <%= Html.DisplayFor( your model) %> or you can also use the regular <% Html.RenderParital("NameOfPartial", ModelX); %>
Edit
To try and approach the original question, maybe this could help you in some way (I posted this as an answer to a different question How to change [DisplayName“xxx”] in Controller?)
public class MyDisplayName : DisplayNameAttribute
{
public int DbId { get; set; }
public MyDisplayName(int DbId)
{
this.DbId = DbId;
}
public override string DisplayName
{
get
{
// Do some db-lookup to retrieve the name
return "Some string from DBLookup";
}
}
}
public class TestModel
{
[MyDisplayName(2)]
public string MyTextField { get; set; }
}
Maybe you could rewrite the custom-attribute to do some sort of logic-based Name-selection, and that way use the same PartialView for both model-variations?
Yes, two different Views is appropriate, as you are providing two different VIEWS of your MODEL.
However, are you sure you aren't shoehorning your data into a single model, when in fact it represents a different entity in each case?
Is it really the same model?
If they're two different entities with similar properties then I would create two separate view models. Any commonality could be put in an abstract base class or interface.
If it's the same model but just a different input screen then sure, reuse the model.
I would imagine the first case is probably the one that is relevant here.