Dynamically Modify value of #Html.HtmlHelper - c#

I am trying to modify a behavior for DataAttributes (Maxlength[int] or StringLength[int]), where it would add a "maxlength" attribute inside (textarea) tag along with its "int" value. I have already performed some research, and the closest answers I obtained were this post and that question.
However, I hope to go one step further.
I already know that StringLength adds "data-val-length-max" and "data-val-length" attributes to the tag.
I spent a lot of time trying to implement solution in JavaScript unobtrusive validation file by using logic
if tag has data-val-length-max attribute
add maxlength attribute to this tag
assign its value equal to data-val-length-max value
However, in my project, Javascript files are constantly loaded/unloaded and it is extremely time-consuming to keep track of the logic flow, so I decided to change the approach, and try to implement it within C#.
Inside my .cshtml file, there are lines like following:
#Html.myLabelFor(model => model.Project.ProjectDescription, new { #title = "Enter a description for this project" })
#Html.TextAreaFor(model => model.Project.ProjectDescription, new { #class = "textfield_Paragraph", #id = "ProjectDescription" })
#Html.ValidationMessageFor(model => model.Project.ProjectDescription)
I learned that it successfully adds maxvalue if it adds #maxlength at the end:
#Html.TextAreaFor(model => model.Project.ProjectDescription, new { #class = "textfield_Paragraph", #id = "ProjectDescription", #maxlength = 50 })
However, I do not want to manually add #maxlenght this line to every TextAreaFor line in solution; I want to turn it into reusable code, that would dynamically perform such action to every variable within TextAreaFor inside the .cs file, which are marked like following:
[MaxLength(50)]
[Display(Name = "Project Description")]
public string ProjectDescription { get; set; }
So I am thinking of implementing it by using the logic
if metadata has a MaxLength flag
htmlAttributes += " ', #maxlength = ' + maxLengthValue"
So, physically it will still be
#Html.TextAreaFor(model => model.Project.ProjectDescription, new { #class = "textfield_Paragraph", #id = "ProjectDescription" })
while the final value that will be loaded will be
#Html.TextAreaFor(model => model.Project.ProjectDescription, new { #class = "textfield_Paragraph", #id = "ProjectDescription", #maxlength = 50 })
I want to know if something like this is even possible to implement, so I know beforehand if I should continue thinking in that direction.
Again, links I have posted above were the closest answers I could get, so I am curious if it is as far as I can get, or there is even more room to improve. My huge preference would be NOT touching .js files unless I absolutely HAVE to.

Related

MVC5 DropdlwonList: Set individual column length

I have a dropdown list that populates with two fields. Old_ItemID and ItemDescription. The user needs to see both of these fields in the dropdown.
Problem is that is messy. Originally it puts both fields next to each other without any spacing. It looks messy and is hard on the eyes. As you can see from the code below, I added some spacing. And that is much better.
The problem now is that it's not aligned because each Old_ItemID is a different length and depending on how many characters the Old_ItemID is, it pushed the ItemDescription left or right. And so it looks unorganized.
Is there a way to justify these columns in a tab setting, or somehow get the alignment correct?
Controller Code
List<SelectListItem> SuppliesList = db.ICS_Supplies.Where(s => s.InvType == "G").Select(x => new SelectListItem { Value = x.Supplies_ID.ToString(), Text = x.Old_ItemID + "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0" + " | " + " " + " Description: " + x.ItemDescription, Selected = false }).DistinctBy(p => p.Text).OrderBy(p => p.Text).ToList();
ViewBag.SuppliesList = new SelectList(SuppliesList, "Value", "Text");
View Code
<div class="form-group">
#Html.Label("Supplies Requested:", new { #class = "form-control" })
#Html.DropDownList("SuppliesList", null, "Select", new { #class = "form-control", #onchange = "supplychange()" })
</div>
Note: I did a bit of research before asking this question, which is where I found how to add the spaces. But I can't seem to find a resource to show how to align with proper spacing so that it looks professional and not sloppy. Should be a common request, I would imagine?

Change class of #Html.EditorFor / customize template | ASP .NET MVC 4

I want to change the class/style of my #Html.EditorFor field. I read something about customizing the template, but there is no template folder in my porject (Views/Shared/ONLY_FILES_HERE). Sadly I am NOT working with MVC 5.1.
Also I DON'T want to use TextBoxFor, because of inputvalidation.
How can I achieve this?
Here is a snippet of my model:
public class CreateTableColumnModels
{
[RegularExpression(#"^[A-Za-z0-9]+$", ErrorMessage = "Use letters and numbers only please")]
[Display(Name = "Name")]
public string Name { get; set; }
I tried this:
#model QlikViewStammdaten.Models.CreateTableColumnModels
<div>
#Html.EditorFor(x => Model.Name, new { #class = "form-control" })
</div>
As already mentioned in the comments, it is better to add a class to Html.TextBoxFor and NOT #Html.EditorFor. Why? because #Html.EditorFor renders a template and that template could contain multiple controls (now to which one of those controls do you want to add the class?)... see Adding a class to EditorFor
If you want numeric type, then add #type = "number"
#Html.TextBoxFor(m => m.Name, new { #class = "form-control", #type = "number" })
Note: it is not x => Model.Name but m => m.Name
I am sure you already know this, but [Display(Name = "Name")] is redundant in your model, as the default display name is the variable name itself.

How do you add a placeholder using #Html.NopEditorFor

I am trying to add a placeholder to my text field.
I am fairly new with MVC and only been working on it for the pass month.
My code looks like this:
Branch Hours Description: #Html.NopEditorFor(model => model.Description)
BRHOURID: #Html.NopEditorFor(model => model.BrHourCode)
is it possible to add a place holder for these 2 fields?
You need to add a HTML attribute
Branch Hours Description: #Html.NopEditorFor(model => model.Description, new { #placeholder = "Add Your Placeholder Text Here" } })
and that should do it for you

Knockout doesn't bind selectedValue in a select properly

It seems impossible and I have tried a few different ways to create a select list and bind a value to it.
Firstly, and more desirably, I want to do it with Razor:
#Html.DropDownList("SelectedTemplate", Model.Templates, new { #data_bind = "value: Template()" })
The options are just an array of strings. When I bind with Razor then it's a List of SelectListItem objects with Text and Value equal to the same string.
So it renders like this:
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
When I bind via Knockout then the Templates is an array of strings:
var Templates ='["A", "B", "C"]';
which I generate in the cshtml file:
var Templates ='#Html.Raw(Json.Encode(Model.Templates.Select(x=> x.Value)))';
Both create the same markup in HTML. This renders the select list correctly. Template() prints out the correct value, for example "B". However, the drop down doesn't pick the option that is equal to Template(). I also tried:
<select name="SelectedTemplate" data-bind="value: Template(), options: JSON.parse(Templates)"></select>
Same problem here. And I tried all kinds of variations:
#Html.DropDownListFor(m => m.SelectedTemplate, Model.Templates, new { #class = "form-control layoutTemplateSelector", #data_bind = "value: Template(), options: JSON.parse(Templates)" })
#Html.DropDownListFor(m => m.SelectedTemplate, Model.Templates, new { #class = "form-control layoutTemplateSelector", #data_bind = "value: Template()" })
#Html.DropDownList("SelectedTemplate", Model.Templates, new { #data_bind = "value: Template(), options: JSON.parse(Templates)" })
Ideally, I want to use DropDownListFor because on post back I want m.SelectedTemplate to be processed.
The postback works well so far for DropDownListFor, but on load it doesn't show the data-bind: value:Template(), which definitely contains the correct value.
I also tried your idea to use observable array with no success:
self.SelectedContent({
Template: ko.observable(content.Template()),
TemplateList: ko.observableArray(JSON.parse(Templates))
});
#Html.DropDownListFor(m => m.Form.Template, Model.Templates, new {#data_bind = "value: Template(), options: TemplateList()" })
Any ideas what could be wrong here? I'm using Knockout 2.3 and MC.
UPDATE
I found the error.
The value returned from the database contained a space: "A "
whereas the values binding the to the drop down didn't have that space.
This caused all the errors.
As far as I can see the simplest of implementations works well now:
#Html.DropDownList("SelectedTemplate", Model.Templates, new { #data_bind = "value: Template()" })
Even though it was entirely my mistake, I hope it helps someone in the future. The error wasn't immediately apparent

when i use .ToShortTimeString()....templates can only be used?

#Html.TextBoxFor(x => x.ActiveDevice.LastUseDate, new { #readonly = "readonly" })
Displays my date textbox as read only, which is fine, however it shows both date and time. I only want date so iv used .ToShortTimeString() with:
#Html.TextBoxFor(x => x.ActiveDevice.LastUseDate.ToShortTimeString(), new { #readonly = "readonly" })
and I get the error:
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Anyone know how to resolve this?
Thanks
You can insert formatted date with HtmlAttributes:
#Html.TextBoxFor(x => x.ActiveDevice.LastUseDate, new { #readonly = "readonly", #Value = Model.ActiveDevice.LastUseDate.ToShortTimeString() })
This happens because TextBoxFor (as well as other template extensions) needs an expression that refers to a model property, so that the model binder could serialize the data:
Need to verify the expression is valid; it needs to at least end in
something that we can convert to a meaningful string for model
binding purposes
(Check out the relevant code in ModelMetadata.FromLambdaExpression)
There are several ways to solve this, one is adding DisplayFormat attribute to your model:
[DataType(DataType.Date)] //try this as well? maybe Orchard intervenes into rendering...
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime LastUseDate { get; set; }
And then you use the property as usual is the view:
#Html.TextBoxFor(x => x.ActiveDevice.LastUseDate, new { #readonly = "readonly" })
Thanks to help from andreister I was able to solve the problem. Changing it to a 'textBox', removing the lamba, ad adding in the name of the textbox in quotes:
#Html.TextBox("LastUseDate", Model.ActiveDevice.LastUseDate.ToShortDateString(), new { #readonly = "readonly" })

Categories