Html.DescriptionFor rendering inside the previous <textarea/> - html

I have a <textarea /> that has the value of a property in my view model. The property is as follows:
[Display(Name="Description", Description="DescriptionOfDescription", ResourceType=typeof(Resources.Admin))]
public string Description { get; set; }
Notice the Display data attribute. This defines the display name and description of the property. With this, I should be able to set up my markup like so:
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(x => x.Description, new { #class="control-label col-md-2" })
<div class="col-md-10">
<textarea data-bind="value: Description" />
#Html.ValidationMessageFor(x => x.Description)
#Html.DescriptionFor(x => x.Description)
</div>
</div>
</div>
The <textarea data-bind="value: Description"/> is using KnockoutJS to bind the value.
In my opinion this should and would work, but for some reason it doesn't. The HTML of #Html.DescriptionFor(x => x.Description) is being rendered within the value of the textarea, which I find very peculiar. I have no idea what's going on, and why it's behaving like this.
Here's an image of the web page:
EDIT
Html.DescriptionFor()
public static class MvcHtmlHelpers
{
public static MvcHtmlString DescriptionFor<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, self.ViewData);
var description = metadata.Description;
return MvcHtmlString.Create(string.Format(#"<p class='help-block'>{0}</p>", self.Encode(description)));
}
public static string DescriptionForRaw<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, self.ViewData);
var description = metadata.Description;
return description;
}
}

The problem is that <textarea> is not a self-closing tag, hence the HTML that comes afterwards is considered part of the element.
You need to close it using:
<textarea data-bind="value: Description"></textarea>

Related

Adding bootstrap CSS class Attribute to textbox ASP.Net MVC

When adding a css class attribute using new { #class="form-control"} to a textbox generated using html helpers, the attribute is added as a value while the same approach works fine with the textarea control.
#{
ViewBag.Title = "New";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>New</h2>
<div>
<div class="col-md-4">
#using (Html.BeginForm())
{
<div class="form-group">
#Html.Label("Title");
#Html.TextBox("Title", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Body")
#Html.TextArea("Body", new{ #class="form-control"} )
</div>
}
<div class="form-group">
<input class="btn btn-default" name="edit" value="edit"/>
<input class="btn btn-default" name="save" value="Save" />
</div>
</div>
</div>
Try doing this instead #Html.TextBox("Title","", new { #class = "form-control" })
The over load you're currently using is
HtmlHelper.TextBox(string name, object value)
You are using this overload of Html.TextBox for method
public static MvcHtmlString TextBox(
this HtmlHelper htmlHelper,
string name,
object value
)
and the second parameter sets the value of the input, if model state dictionary does not contain one for the input. So your code will render something like this
<input id="Title" name="Title" type="text" value="{ class = form-control }">
You should use this overload which takes the value and htmlAttriubutes
public static MvcHtmlString TextBox(
this HtmlHelper htmlHelper,
string name,
object value,
IDictionary<string, object> htmlAttributes
)
Use it like this
#Html.TextBox("Title", null, new { #class = "form-control" })
Interesting thing to note here is, the helper method will look for the value in model state dictionary and view state dictionary as well. So if your action method is setting the ViewBag.Title to some value, that value will be used as the value of the input if you pass null as the value when calling this method. The default MVC project template uses ViewBag.Title to set the page title. So you probably are going to see that value in the input.
To solve that, you can explicitly pass an empty string instead of null
#Html.TextBox("Title", string.Empty, new { #class = "form-control" })

Spring Thymeleaf + Textarea

I created form with one input text and one textarea. The input text works fine, but textarea isn't even displayed:
<div id="news" th:fragment="admin_panel">
<form method="POST" th:action="#{/addNews}" th:object="${news}" id="myform">
Tytuł:
<input type="text" th:field="*{title}"/>
<input type="submit" value="Wstaw"/>
</form>
<textarea name="news_content" rows="20" cols="80" th:field="${news.content}" form="myform">
...
</textarea>
</div>
When I delete the th:field the textarea is displayed and when I use th:value instead of th:field it's displayed too but doesn't save the written text to news.content (news.title is saved ok).
I don't have any idea... I read thymeleaf references but can't find answer, so please help good people!
You have to use the selected object expression *{content} AND place the textarea tag inside the form tag!
In the end its all about the generated name attribute in the resulting form. The name needs to correspond to the propertyAccessor from the selected root object th:object.
The form is processed by spring (without any thymeleaf interception).
The docs about spring integration are really good: http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html
They state this:
Values for th:field attributes must be selection expressions (*{...}), which makes sense given the fact that they will be evaluated on the form-backing bean and not on the context variables (or model attributes in Spring MVC jargon).
EDIT:
Thanks to the link to the project, the fix was easy:
Thymeleaf 3.0.0.BETA03 had a bug in the textarea processor, moving to 3.0.0.RELEASE fixed this issue
Additionally I have moved the textarea inside the form element.
My textarea input was working fine when i was saving some data through it(in clean state when i was performing a save to DB) but in case of edit form(where my textarea input was supposed to show the prefilled description from the model property book.description) was blank, the reason for that was the th:value attribute, i changed it to the th:field attribute and it started working as expected.
<textarea class="form-control" id="description" rows="5"
name="description"
placeholder="Description" th:field="${book.description}"
required="required"></textarea>
You don't need the form text field. Linking the textarea with the form by the form id is sufficient.
<textarea rows="8" cols="120" name="lines" form="usrform" th:text="${message}"></textarea>
<form method="POST" enctype="multipart/form-data" th:action="#{/}" id="usrform">
<button type="submit" name="action" value="submitlines">Submit</button>
</form>
and the controller:
#RequestMapping(value="/", method=RequestMethod.POST, params="action=submitlines")
public String handleForm(
#RequestParam("lines") String input,
RedirectAttributes redirectAttributes) {
}
About exceptions :
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/eniupage] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring4.processor.SpringTextareaFieldTagProcessor' (template: "templates/fragments" - line 144, col 60)] with root cause
java.lang.StringIndexOutOfBoundsException: String index out of range: 0
In my form, there are text input and textarea as You see. news.title is saved ok, but news.content don't. When I replace for test these parameters (in the text input I use news.content and in the textarea there is th:field = ${news.title}) it works well too. Maybe should I use another expression instead of th:field?
News.java
package eniupage.domain;
public class News
{
private String title;
private String content;
private Date date;
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content)
{
this.content = content;
}
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
}
HomeController.java
package eniupage.web;
#Controller
#RequestMapping( "/" )
public class HomeController
{
#Autowired
AddNewsService addNewsService;
#RequestMapping( method = GET )
public String home( Model model )
{
model.addAttribute( "newses", addNewsService.getNewses() );
return "home";
}
#RequestMapping( value = "/addNews", method = POST )
public String addNews( News news )
{
addNewsService.addNews( news );
return "redirect:/";
}
}
AdminController.java
#Controller
#RequestMapping( "/admin" )
public class AdminController
{
#RequestMapping( method = GET )
public String admin( Model model )
{
model.addAttribute( new News() );
return "admin";
}
}
There isn't any resulting of HTML form, because it isn't even displayed in div. There are only text input and submit button.
Edited html:
<form action="#" method = "POST" th:action="#{/addNews}" th:object = "${news}" id = "myform">
Tytuł: <input type = "text" th:field = "*{title}" />
<input type = "submit" value = "Add" /></br>
<textarea rows = "20" cols = "80" th:field = "*{content}" form = "myform" >... </textarea>
</form>
I'm using thymeleaf 3.0. Maybe this is the reason?
In reference I read :
The th:field attribute behaves differently depending on whether it is attached to an , or tag (and also depending on the specific type of tag).
But I can't find what is this difference between using th:field in input and textarea.

Incorrect byte[] value when html tag is used

I have an html helper method for a hidden field. It is bound to a byte[] and I have no problem as it displays the result correctly. But instead of the helper function if I use an html tag, the correct value is not displayed. Instead it displays its type.
following code and image will clarify what I am trying to say.
HTML code:
foreach (var path in Model.PathToImages)
{
<div class="form-group">
<div class="col-sm-6" style="vertical-align:central;">
<input type="button" value="Delete" class="btn btn-primary delete-property" name="#path.ImagePath" />
#Html.HiddenFor(m => path.ConcurrencyCheck)
<input id="#path.ImagePath" name="#path.ImagePath" type="hidden" value="#path.ConcurrencyCheck">
</div>
</div>
}
Property in my model:
public byte[] ConcurrencyCheck { get; set; }
Ignoring the names and id's of the control (this is just to reproduce the problem), following is the html generated:
Now as the image says when i use #Html.HiddenFor(m => path.ConcurrencyCheck) the value is correctly displayed but when I use <input id="#path.ImagePath" name="#path.ImagePath" type="hidden" value="#path.ConcurrencyCheck"> the value is the type System.Byte[].
So why I am not getting the value when I am using the html input tag or the problem is with the way model value should be displayed.
This because byte[] is a a complex array and needs to be converted to Base64String. The Html.HiddenFor() method takes this into account but #path.ConcurrencyCheck does not, and is using the .ToString() method of the properties value to generate the output.
You can view the source code here, but the relevant lines of code are
private static MvcHtmlString HiddenHelper(HtmlHelper htmlHelper, ModelMetadata metadata, object value, bool useViewData, string expression, IDictionary<string, object> htmlAttributes)
{
....
byte[] byteArrayValue = value as byte[];
if (byteArrayValue != null)
{
value = Convert.ToBase64String(byteArrayValue);
}
....

HtmlHelper inside HtmlHelper

Is it possible to make a HtmlHelper for parts where another htmlherlper is already used.
like in this case:
<div class="control-group">
#Html.LabelFor(model => model.cLinks.Link2Privates)
<div class="controls">
#Html.TextBoxFor(model => model.cLinks.Link2Privates, new { #class = " span7"})
#Html.ValidationMessageFor(model => model.cLinks.Link2Privates)
</div>
</div>
I'm assuming you simply want a helper that will generate all this information for you. While it's technically possible to create a custom helper that will do just that, it's actually better to use editor templates:
Views\Shared\EditorTemplates\BootstrapControlGroup.cshtml
<div class="control-group">
#Html.Label("")
<div class="controls">
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { #class = " span7"})
#Html.ValidationMessage("")
</div>
</div>
Form
#Html.EditorFor(m => m.cLinks.Link2Privates, "BootstrapControlGroup")
That basically says to use this template to render the "editor" for this property. If you don't want to have to specify the template name, there's other ways. You can decorate your property with the UIHint attribute:
[UIHint("BoostrapControlGroup")]
public string Link2Privates { get; set; }
Or you can rely on a particular C# type or DataType. For example, if you wanted all strings to be handled this way, you could name that template String.cshtml instead and then just do:
#Html.EditorFor(m => m.cLinks.Link2Privates)
Razor would see that it was a string and use the String.cshtml editor template automatically if it existed. You can also use the DataType attribute, for example:
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
And, then create a Views\Shared\EditorTemplates\EmailAddress.cshtml template. Razor will use this template, then, any time you call Html.EditorFor for this property.
I have created a HtmlHelper extension library that works well with Twitter Bootstrap scenarios.
http://buildmvc.codeplex.com
There's even a HtmlHelper add-on for Twitter Bootstrap Form Groups:
https://www.nuget.org/packages/Build.Mvc.TwitterBootstrap
#using ( Html.BuildForm().Begin(FormRenderStyle.Horizontal) )
{
Html.UpdateFormBuilderContext(ctx =>
{
ctx.RenderValidationMessages = true;
});
<fieldset>
<legend>User Information</legend>
#Html.BuildTextBoxGroupFor(m => m.FirstName, b=> b.TextBox(t=> t.Autofocus()))
#Html.BuildTextBoxGroupFor(m => m.Nickname)
#Html.BuildTextBoxGroupFor(m => m.LastName)
</fieldset>
}
Note: The library expects you to be using TwitterBootstrap > v3. The example above has version 2.3.2 class names.

Missing case of value on input type="hidden"

I faced with missing case sensitive string value, how it can be fixed?
Example is following:
..
entity.Value = "Some Test Value";
entity.Name = "SomeTestName";
..
When I place it in View like following (I am using Razor),
<input type="hidden" name="#entity.Name" value="#entity.Value">
Then it will be rendered as following:
<input type="hidden" name="SomeTestName" value="some test value">
I used
<input type="hidden" name="#entity.Name" value="#Html.Raw(entity.Value)">
but result is the same.
So, its missing case. How it can be fixed?
Doesn't seem to be the case (status no-repro).
Model:
public class Entity
{
public string Name { get; set; }
public string Value { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var entity = new Entity();
entity.Value = "Some Test Value";
entity.Name = "SomeTestName";
return View(entity);
}
}
View:
#model Entity
<input type="hidden" name="#Model.Name" value="#Model.Value" />
Generated HTML:
<input type="hidden" name="SomeTestName" value="Some Test Value" />
See? Everything works perfectly fine. So we can draw only a single conclusion here: you haven't shown your full code allowing us to reproduce your problem rendering your question meaningless.