How do I use DisplayNameForModel? - c#

I tried using this as a header for a view but it returns an empty string. In the Razor layout, I have something like:
#model IEnumerable<MVCApp.Models.Model>
<h2>#Html.DisplayNameForModel()</h2>
Do I need to set something on the model definition itself? I tried a data annotation [Display(Name="Model Name")] but it is a build error:
Attribute 'Display' is not valid on this declaration type. It is only valid on 'method, property, indexer, field, param' declarations.
The documentation DisplayNameExtensions.DisplayNameForModel Method is terse. The syntax calls for a parameter, but says:
No overload for method 'DisplayNameForModel' takes 1 arguments
As the Usage section says "When you use instance method syntax to call this method, omit the first parameter"
So, how do I use this method to return something?

I just used the default MVC 5 template project in VS2013 and have the #Html.DisplayNameForModel() working with no issues.
First, you are using the wrong data annotation on your view model. You want to use [DisplayName("My Model Name")] and not [Display()]
[DisplayName("Test View Model")]
public class TestViewModel
{
public string TestProperty { get; set; }
}
Second, the html parameter you are seeing on MSDN is a required parameter for any Html helpers in MVC. You do not have to pass anything for this value, the view engine does this for you. So, in your view, you would use the following to get the Display Name that you set on the model as so.
<h2>#Html.DisplayNameForModel()</h2>
Now, your result should output the display name attribute you set in your html. *Note the Test View Model above the Log In text.

try
#Html.DisplayNameFor(m => m.Name)

Related

In asp helper tags, what is the difference between Model.PropertyName and just PropertyName

Here is an example:
cshtml >>
<label>List of products: </label>
<select asp-items="Model.ListOfProducts" asp-for="ProductToSearch">
<option value="">All</option>
</select>
cshtml.cs >
public class IndexModel : PageModel
{
...
public SelectList ListOfProducts{get; set;}
[BindProperty(SupportsGet=true)]
public string ProductToSearch{get; set;}
...
}
In cshtml why is one named Model.ListOfProducts but other one is named just ProductToSearch.
What does Model in this case do?
It has to do with the actual types for those attributes on the tag helper(s). The asp-for attribute, for example, is backed by a property on the tag helper class that is typed as ModelExpression. As such, what you're passing to the attribute in the view is expected to be something that can be interpreted as a ModelExpression, i.e. a representation of a specific property at some level on the model. In other cases, such as with asp-items, the type is IEnumerable<SelectListItem>, so you're expected to pass a value that is of that type.
Simply, the syntax of #Model.Property is a dereference: you're retrieving the value of that property, whereas when you just do Property, you're passing an expression representing that property.
There is a scenario that blurs the lines a bit: when the model is a list and you're specifically trying to reference a particular item in that list as an expression. In that scenario, something like [0].Property is not a valid expression, so you must use #Model[0].Property.
The list you supply to asp-items could potentially come from somewhere external to the model, so you have to specify the full namespace/class path to the object (or method to generate the object) you want to use.
Whereas in the asp-for you're expected to always specify a property from the current model, so there's no need to prefix it.

Difference between #Html.Display() and #Html.DisplayText()

What is the exact difference between #Html.Display() and #Html.DisplayText()? Both are giving the same output.
I have a model class Employee which has a property
Name = "my Name".
And I am using Html helper in following way -
#Html.Display("Name")
#Html.DisplayText("Name")
The output for both methods is "my Name"
You can inspect the source code for Display and DisplayText.
#Html.DisplayText(propertyName) will only output the the value of the property (defined by the SimpleDisplayText of ModelMetadata).
#Html.Display(propertyName) provides far more options. If you have provided a DisplayTemplate from the property type, it will use the html in that template by default. You can also specify a specific template name to be used to generate the html. In additional, you can use the additionalViewData parameter of Display() to pass additional information to the template.
In your case, you property is string and you have not defined a DisplayTemplate for string, therefore Display() uses the default (in-built) template which generates the same output as DisplayText()

Set a default value to the model being passed to Partial View

I have a partial view that is called from another partial view (kind of nested partial views).
The outer partial view is called Company and the inner partial view is a custom control called searchHelp. Both accept a parameter.
Now the Company view gets a parameter of type company and searchHelper accepts an optional string. This part works fine as I am testing the model value for null and assigning is default text as #((Model==null)?"Enter Text":Model) when used in other views even without passing a parameter.
In my case of nested views, if I dont provide a string as model for searchHelper then it takes company as model from the outer view i.e company and gives an error.
The #model definition is not a value setter, it's merely telling Razor what type of view to instantiate. You can't define a default value here. If you don't pass a model to your partial, then it will use the model of the parent view, which is Company in this case. Company is not a string, obviously, so you get that error. If you want to pass a default value for the partial, do that in the second parameter to Html.Partial:
#Html.Partial("searchHelp", Model.SomeStringProperty ?? "Enter Text")
You can assign a default value to the string-as-model from where it's called in the view:
//null coalesce to default string value:
#Html.Partial("searchHelp", Model.searchHelp ?? "default value")
...though you might do better using an htmlhelper, where you can define the default value just one time:
public IHtmlString SearchHelp(this HtmlHelper html, string searchHelp = "default value")
{
// make html here
}
Then
#Html.SearchHelp(Model.searchHelp);

How do you put a ViewBag item into a Text Box?

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)

Extend HiddenFor Templates in ASP.NET MVC

I thought Html.HiddenFor could use Templates like Html.DisplayFor or Html.EditorFor. Unfortunately the method doesn't accept a TemplateName like the others.
I know, the workaround would be to use a DisplayFor/EditorFor Template which has HiddenFors. But I would like to find out how to extend the Html.HiddenFor method. Anyone?
Regards
Seems like you are mislead by wrong analogy. HiddenFor corresponds exactly to the <input type="hidden"/> tag. Just like TextBoxFor, CheckBoxFor etc. These methods are not designed to use templates. DisplayFor/EditorFor on the other side are specially created to be used with templates defined in the project. Thus what you are asking for is not possible out-of-the-box.
However you can always define your own overload for HiddenFor with whatever set of parameters and whatever logic you might require.
There is an overload which accept additional parameter - htmlAttributes. And you can use it for add some attributes to the result tag.
Also the second way is to create razor partial view in one of the folders
~/Areas/AreaName/Views/ControllerName/DisplayTemplates/TemplateName.cshtml
~/Areas/AreaName/Views/Shared/DisplayTemplates/TemplateName.cshtml
~/Views/ControllerName/DisplayTemplates/TemplateName.cshtml
~/Views/Shared/DisplayTemplates/TemplateName.cshtml
with name HiddenInput.cshtml
Here's what you do, you create it as an editor template, because as Andre pointed out, HiddenFor is equivalent to the helper methods like TextBoxFor and CheckboxFor.
It's likely that you'll want to have an actual editor too, so place your real editor under ~/Shared/EditorTemplates. We're going to put our "hidden editor" under the controller you wish to use it on.
~/Views/ControllerName/EditorTemplates/ModelName.cshtml
Lets say we have a Person model.
public class Person
{
public string First { get; set; }
public string Last { get; set; }
}
We'll create a partial view.
#Model Person
#Html.HiddenFor(p => p.First);
#Html.HiddenFor(p => p.Last);
And then we'll pretend we have a model that contains a Person as a property. From our main view, we call our "hidden editor" like so.
#Model Foo
#Html.EditorFor(f => f.Person)
Easy peasy lemon squeezy. A bit hacky, but it works like a charm.

Categories