Rendering bootstrap components in EditorTemplates - c#

I have the following property in my QuoteSalesRep class:
[Display(Name = "Commision %")]
[UIHint("Percentage")]
public decimal CommisionPercentage { get; set; }
I would like to create an Editor template that would render anything with the [UIHint("Percentage")] like so:
Under Views/Shared/EditorTemplates I added Percentage.cshtml. I currently have the following code:
#model decimal
<div class="input-group">
<input type="text" class="form-control">
<span class="input-group-addon">%</span>
</div>
I am new to working with templates. What do I need to do to correct the above code so it renders the input-group properly for any property tagged with [UIHint("Percentage")]?

I think all you're missing is a generic way of generating the text input:
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue.ToString(), new { #class = "form-control" })

Related

Access a Model class from Razor Page .cshtml file

I am trying to create a simple drop-down menu populating it with categories from a local database. I am using .NET Core 2.2. I am following a demo that uses an earlier version of ASP.NET MVC where they use ViewBag to transfer a list from the controller to view. For some reason, ViewBag doesn't work giving me a compiling error of "ViewBag does not exist in the current context". After a little bit of research, I opted to use ViewData which seems to work from the controller but I am having a little bit of trouble displaying the category Name from my model as when I run the page the drop-down options display "Model.Visportfolio.Category" rather than the category Name itself.
I am fairly new to HTML so I tried replicating the code from the demo but I am having trouble accessing the fields of my Category class. I tried using ViewBag as from my research, ViewData and ViewBag are "interchangeable" but no luck.
HTML for where I call my drop-down menu, code does not compile as it says CategoryName and CategoryId does not contain the definition and no accessible extension method
<form asp-controller="my_dropdown" asp-action="CreatePortfolio" method="post" class="form-horizontal" role="form">
<div class="form-group">
<div class="row">
<div class="alert-danger" asp-validation-summary="ModelOnly"></div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
<label asp-for="CategoryName" class="control-label"></label>
<select asp-for="CategoryId"
class="form-control"
asp-items="#(new SelectList(ViewBag.categorylist, "CategoryId", "CategoryName"))">
</select>
#Html.DropDownList("categorylist",
new SelectList((System.Collections.IEnumerable) ViewData["categorylist"]), "Select Category","CategoryName" )
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-xs-12 col-sm-6 col-lg-4">
<input id="Submit1" type="submit" value="submit" />
</div>
</div>
</div>
</form>
This is the code behind the html
public void OnGet()
{
// ----- Getting Data From Database Using EntityFrameworkCore ----
categorylist = (from category in _context.Category
select category).ToList();
// ----- Inserting Select Item in List -----
categorylist.Insert(0, new Category { CategoryId = 0, CategoryName = "Select" });
// ----- Assigning categorylist to ViewBag.ListOfCategory -----
// ViewBag.categortyList = categorylist;
ViewData["categorylist"] = categorylist;
}
Model
namespace Visportfolio.Models
{
[Table("Category")]
public class Category
{
[Key]
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
}
You are looking for
new SelectList(ViewData[categoryList], "Value", "Text")
SelectList has alot of overloads that you can use see here
So use
#Html.DropDownList("categorylist",
new SelectList((System.Collections.IEnumerable) ViewData["categorylist"], "CategoryId", "CategoryName"), "Select Category","CategoryName" )

#Html.EditorFor asp.net core doesn't work for file

I try to make #Html.EditorFor(model => model.file) to put file on web page (file is IFormFile type) in my ASP.NET Core application. But file is null, when i click submit,for some reason, and exception arises.For string everything is OK. Here is HTML code:
#using (Html.BeginForm("tt", "Home", FormMethod.Post))
{
<div class="row">
<div class="col-md-4">
#Html.EditorFor(model => model.file)
</div>
<div class="col-md-8">
<button type="submit" id="btnUpload" class="btn btn-primary">Upload</button>
</div>
</div>
<br />
<div>#Html.DisplayFor(model => model.content)</div>
}
controller code:
public ActionResult tt(Models.FileInfo f)
{
var r = f.content1 + f.file.FileName;
f.content = r;
return View("Demo_index", f);
}
and model:
public class FileInfo
{
public IFormFile file { get; set; }
public string content { get; set; }
public string content1 { get; set; }
}
Is it possible to make #Html.EditorFor(model => model.file) work? Or is there some similar way to make form with file uploading?
The issue is that you're posting as x-www-form-urlencoded, which doesn't support file uploads. You need to use multipart/form-data, instead, which can be achieved via adding the enctype attribute to your form tag:
<form ... enctype="multipart/form-data">
This is possible using Html.BeginForm, but you have to use an overload that requires you to specify a ton of parameters, and it's more pain than it's worth. Besides, in Core, using the tag helpers is much better anyways. Literally all you need is:
<form asp-action="tt" asp-controller="Home" method="post" enctype="multipart/form-data">
...
</form>
If you're doing a postback, i.e. to the same page you're already on, you can remove the asp-action and asp-controller attributes entirely. This will be processed by the built-in FormTagHelper and the right action and such will be generated for you.
FWIW, the same applies with your input as well. Instead of EditorFor, you can simply do:
<input asp-for="file" />
The InputTagHelper will fill in everything else.

Passing value of an input control to controller

I have the following:
#Html.BeginForm("AddComment", "Shared", new { guid = Model.VideoGuid, content="", userid = authenticatedUserId.ToString()}){
<div class="input-group">
<input name="txtCommentContent" type="text" class="form-control"><span class="input-group-btn">
<button class="btn btn-default">
<img src="~/Content/images/Message-Add.png" /></button>
</span>
</div>
}
I need to pass the text input inside the input control to the control as part of the routeValues. The above content="" is going to do that.
How can this be done?
You should be using the HTML Helpers:
#Html.EditorFor(m => m.CommentContent);
This will model bind the value in CommentContent (Which should be a property in your model) and pass it back up to the server when the form is POSTED.
As an alternative solution, you can also serialize the form and pass it up via AJAX.
As #Ic has pointed out you could also use:
#Html.TextBoxFor(m => m.CommentContent, new { #class = "form-control" });
Which will change the input type to text and also add your CSS class form-control.

Auto Tooltip Validation in MVC 4?

Where the heck are these things coming from? I like them, and I would like to leverage them elsewhere in my site. It appears they only show when I do regular expression validation in model:
[Display(Name = "Residential")]
[RegularExpression(#"[-+]?[0-9]*\.?[0-9]?[0-9]", ErrorMessage = "Must be a number")]
public Byte? residentialExperience { get; set; }
<div class="editor-label row">
#Html.LabelFor(model => model.residentialExperience)
</div>
<div class="editor-field row">
#Html.EditorFor(model => model.residentialExperience)
#Html.ValidationMessageFor(model => model.residentialExperience)
</div>
How can I use these validation tooltips elsewhere? Also, how can I turn them off?
Also: It's not displaying the same message as I have in my model. It says, "Please enter a number" whereas I have written "Must be a number."
This is because you are outputting a numeric field. If you look at your HTML you will see that you have something like this:
<input type="number" ... />
By defining the type as a numbber, the browser knows what to expect and it will give you a generic message. This is part of Html 5 spec.
If you want to override the default behavior you could do this:
#Html.TextBoxFor(model => model.residentialExperience, new { #type = "text" })

Data Annotation doesn't not work if control generates from List View Model

I have below view model
public class QuestionarrieAnswersViewModel
{
public long QuestionID { get; set; }
public string Question { get; set; }
[Required(ErrorMessage="required")]
[StringLength(255, ErrorMessage = "Maximum 255 characters are allowed.")]
public string Answer { get; set; }
}
and i am generating view in below way
#model List<BusinessLayer.Models.ViewModel.QuestionarrieAnswersViewModel>
#using (Ajax.BeginForm("SaveQuestionarrie", "Member", FormMethod.Post, new AjaxOptions { OnBegin = "OnBegin", OnComplete = "OnComplete" }, new { #class = "form-horizontal" }))
{
for(int i=0;i<Model.Count;i++)
{
<div class="control-group">
<div class="head_form">
<label class="control-label">#Model[i].Question</label>
<div class="controls">
#Html.TextAreaFor(m=>m[i].Answer)
#Html.ValidationMessageFor(m => m[i].Answer)
#Html.HiddenFor(m=>m[i].QuestionID)
</div>
</div>
</div>
}
<div class="control-group">
<div class="controls">
<button class="btn" type="submit">Save</button>
</div>
</div>
}
I have set dataannotation on Answer field in above model but its not applying in above view while it works if i generate view in below way
#model BusinessLayer.Models.ViewModel.QuestionarrieAnswersViewModel
#using (Ajax.BeginForm("SaveQuestionarrie", "Member", FormMethod.Post, new AjaxOptions { OnBegin = "OnBegin", OnComplete = "OnComplete" }, new { #class = "form-horizontal" }))
{
#Html.TextAreaFor(m => m.Answer)
#Html.TextAreaFor(m => m.QuestionID)
<div class="control-group">
<div class="controls">
<button class="btn" type="submit">Save</button>
</div>
</div>
}
What's going wrong here...
In order to fire those validation rules, you'll need to use an EditorFor instead of a TextAreaFor.
It's because there's an outstanding issue with validation of TextArea's, see here: http://aspnet.codeplex.com/workitem/8576.
This is due to a bug in the version of jquery.validate.unobtrusive.js that was released with ASP.NET MVC3. This answer is on the same bug, the solution to this is to upgrade to the latest version of jquery.validate.unobtrusive.js - either grab it from an MVC4 project or update using NuGet.
The jquery.validate.unobtrusive.js script doesn't seem to have a version number so if you search in the script for a function called escapeAttributeValue, then this is a version of the script that has this bug fix.
The problem that is addressed in the bug fix is how to handle markup generated having name attributes containing characters that need escaping in a jQuery selector. In this case
<textarea cols="20" name="[0].Answer" rows="2"></textarea>
needs this selector
$('[name=\\[0\\]\\.Answer]')
The client-side DataAnnotation (validation) does not work for the Html.TextAreaFor() helper.
To make it work, you have to decorate the 'Answer' property with the [DataType(DataType.MultilineText)] attribute. And in the view, use Html.EditorFor() helper instead of the Html.TextAreaFor() helper mehthod.
See similar SO answer asp.net mvc TextAreaFor is not getting validated as a required field.

Categories