Remove required field value from devextreme form - asp.net-mvc

I work with asp.net mvc and devextreme
I have model with bool value and I will add form in the view
my problem is when I uncheck the checkbox I got a validation message the checkForImges field is required
I want to remove it and the red border
view code
#model ArchiveConfigManager.Models.QueryRetrieve
#using DevExtreme.AspNet.Mvc
#(Html.DevExtreme().Form().ID("form")
.ShowValidationSummary(false).ShowRequiredMark(false).
ShowOptionalMark(false).
ShowColonAfterLabel(false)
.ColCount(1)
.Items(items =>
{
items.AddGroup()
.Items(groupItems =>
{
groupItems.AddSimple().DataField("CheckForImages").
IsRequired(false).Label(l => l.Visible(false)).
Editor(e => e.CheckBox().Text("Check For Images"))
;})
;})
.FormData(Model)
)
model code
public class QueryRetrieve
{
public bool CheckForImages { set; get; }
}
the result is

The ASP.NET framework considers any non-nullable properties as required. So, to avoid the issue you can mark your CheckForImages property as nullable:
public class QueryRetrieve
{
public bool? CheckForImages { set; get; }
}

Related

Checkbox adds extra "false" value per selected one

I have this piece of code in my View which belongs to a form
<div class="col-md-10">
#foreach (var l in leads)
{
#: #Html.CheckBox("cbLead", false, new { #value = #l.Id }) #Html.TextBox("worth", "") - #Html.Label(l.Name)
}
</div>
And this is the form with I handle the post:
[HttpPost]
public ActionResult Update(string[] cbLead, double[] worth)
{
// code
}
I have 24 checkboxes, but for each checkbox selected I receive 2 values in the Update method. So for example if I select 3 out of that 24 checkboxes, I receive 27 values in the string[] cblead.
Example with 24 checkboxes:
And this is what I get in the method:
So I receive the value checked and an added false after. Any tips?
That's because the Html.CheckBox helper generates an additional hidden field with the same name and the value false. The reason for that is because if the checkbox is not checked, then no value will be sent to the server and thus the model binder will fail to properly bind to a boolean property on your model. Also notice that the Html.CheckBox helper expects that you are working with boolean values on your models. Your syntax here is incorrect:
#Html.CheckBox("cbLead", false, new { #value = #l.Id })
You seem to be trying to manually set the value attribute of the checkbox (which should not be done when using helpers) to the Id property of your model which I suppose is not boolean but rather a Guid as can be seen from the screenshot.
This is by design and is expected behavior. If you do not want this behavior that you could write your own custom helper or use plain HTML instead.
I suspect that what you need to receive on the server is the list of IDs along with a boolean value corresponding to whether the element was checked or not. For this purpose I suggest you writing the following view model:
public class MyViewModel
{
public IList<LeadViewModel> Leads { get; set; }
}
public class LeadViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Worth { get; set; }
public bool IsChecked { get; set; }
}
and then:
#for (var i = 0; i < Model.Leads.Count; i++)
{
Html.CheckBoxFor(x => x.Leads[i].IsChecked)
Html.HiddenFor(x => x.Leads[i].Id)
Html.TextBoxFor(x => x.Leads[i].Worth) -
Html.LabelFor(x => x.Leads[i].Name)
}

How to omit/prevent data from being sent to the POST method in the Controller in MVC

I have a view that is using a model and I am using that information to create a form.
I have three steps of the form that are optional or may not be shown.
The problem is that these hidden sections get posted along with the form data and break the business logic. (I have no control over the business logic)
So is there a way to tell the framework not to pass certain sections or fields? Perhaps VIA a class or something?
I know I could use AJAX to send certain sections as they are needed, but the site spec is to have them hidden and displayed as needed.
Although you could do this client-side, it won't stop malicious over-posting/mass assignment.
I suggest reading 6 Ways To Avoid Mass Assignment in ASP.NET MVC.
Excerpts:
Specify Included Properties only:
[HttpPost]
public ViewResult Edit([Bind(Include = "FirstName")] User user)
{
// ...
}
Specify Excluded Properties only:
[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
// ...
}
Use TryUpdateModel()
[HttpPost]
public ViewResult Edit()
{
var user = new User();
TryUpdateModel(user, includeProperties: new[] { "FirstName" });
// ...
}
Using an Interface
public interface IUserInputModel
{
string FirstName { get; set; }
}
public class User : IUserInputModel
{
public string FirstName { get; set; }
public bool IsAdmin { get; set; }
}
[HttpPost]
public ViewResult Edit()
{
var user = new User();
TryUpdateModel<IUserInputModel>(user);
// ...
}
Use the ReadOnlyAttribute
public class User
{
public string FirstName { get; set; }
[ReadOnly(true)]
public bool IsAdmin { get; set; }
}
Lastly, and the most recommended approach is to use a real ViewModel, instead a domain Model:
public class UserInputViewModel
{
public string FirstName { get; set; }
}
Show/Hide will not allow/disallow the value from being sent to the Controller.
Elements that are Disabled or just not editable will (99% of the time) be returned as null / minVal.
You can set the elements in the View as Disabled by using JQuery in the script:
$('#elementID').attr("disabled", true);
OR you could use a DOM command:
document.getElementById('elementID').disabled = "true";
So you can set the fields as both Disabled AND Hidden, so that it is neither displayed, nor populated. Then in your Controller you can just base the Business Logic on whether or not certain fields (preferable Mandatory fields, if you have any) are null.
You can check this in C# like this:
For a string:
if (string.IsNullOrWhiteSpace(Model.stringField))
{
ModelState.AddModelError("stringField", "This is an error.");
}
For a DateTime:
if (Model.dateTimeField == DateTime.MinValue)
{
ModelState.AddModelError("dateTimeField ", "This is an error.");
}
Just for interest sake, here is how you can Hide/Show elements on the View using JQuery:
$('#elementID').hide();
$('#elementID').show();

MVC "Write-Once" Fields in Model and View

I want DRY/reuse as much editor code (View and Model) as possible. Some of my fields can only be set at creation, and never edited. Are there any pre-existing MVC/DataAnnotation features I should look at?
For example, maybe there is a data attribute that causes EditorFor to operate like DisplayFor if the value is non-null.
Model.cs
[Unchangeable]
string UserReferenceId { get; set; }
string Description { get; set; }
edit: to clarify my goal, I've added an answer with sample code for the approach I'm currently planning. If there's a better way/pre-existing feature for this, please let me know.
There are both the System.ComponentModel.ReadOnlyAttribute and System.ComponentModel.DataAnnotations.EditableAttribute (I think EditableAttribute is .NET 4). When model metadata is created for properties marked with either of these, you can see ModelMetadata.IsReadOnly will be set correctly.
Frustratingly, however, the built-in editor templates will still show editable fields, even if ModelMetadata.IsReadOnly is true.
You can, however, create your own shared editor template for each data type where you want this metadata property respected, and handle it specifically.
~/Views/Shared/EditorTemplates/String.cshtml
#model String
#if (ViewData.ModelMetadata.IsReadOnly)
{
#Html.Hidden(string.Empty, Model)
}
#(ViewData.ModelMetadata.IsReadOnly ? Html.DisplayText(string.Empty) : Html.TextBox(string.Empty))
View Model
[Editable(false)]
public string UserReferenceId { get; set; }
You'll note that in the event the metadata for the model indicates IsReadOnly, I draw a hidden field. This is so the value of that property is persisted across posts.
If you don't want the field displayed at all, but persisted across posts, you can use System.Web.Mvc.HiddenInputAttribute. In this case, only the hidden is drawn.
[HiddenInput(DisplayValue=false)]
public string UserReferenceId { get; set; }
Here's what I'm thinking of implementing if nothing similar is pre-existing:
EditableWhenNewModel.cs
public class EditableWhenNewModel : IIsNew
{
public bool IsNew { get { return recordId == 0; } }
string UserReferenceId { get; set; }
string Description { get; set; }
public void Save(RepositoryItem record) {
if (IsNew) { record.UserReferenceId = UserReferenceId; }
record.Description = Description;
... etc.
View.cshtml
#model EditableWhenNewModel
#Html.EditorWhenNewFor(m => m.UserReferenceId)
#Html.EditorFor(m => m.Description)
EditorWhenNewFor.cs
public static MvcHtmlString EditorWhenNewFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression
) where TModel : IIsNew {
return htmlHelper.ViewData.Model.IsNew ?
htmlHelper.EditorFor(expression) :
htmlHelper.DisplayFor(expression);
}

DataAnnotations on public fields vs properties in MVC

Why don't DataAnnotations work on public fields? Example:
namespace Models
{
public class Product
{
[Display(Name = "Name")]
public string Title; // { get; set; }
}
}
public ActionResult Test()
{
return View(new Models.Product() { Title = "why no love?" });
}
#Html.LabelFor(m => m.Title) // will return 'Title' if field, or 'Name' if property
#Html.DisplayFor(m => m.Title)
If Title is a field, then the Display attribute seems to have no effect. If Title is changed to a property, it works as expected as displays "Name".
It would seem easy in this example to just change to a property, but I am trying to use the types from F# where they get compiled to a class with fields and not properties.
This was tested in ASP.NET 4 and MVC RC 3.
The reason why DataAnnotations do not work with fields is because the reflection-like mechanism that is used to retrieve the attributes (TypeDescriptor) only supports properties.
While it would not be easy, we could look into making this work with fields if there is enough demand.

ASP.NET MVC - Stop Html.TextBoxFor adding a dot to the Name attribute

I'm fairly new to ASP.NET MVC and I've got a problem with Html.TextBoxFor() - it's giving the rendered input's name attribute a dot.
<%= Html.TextBoxFor(m => m.Box.Name, new { id= "txtName" }) %>
renders the following HTML:
<input type="text" value="" name="Box.Name" id="txtName">
I'm using the jQuery Validation plugin for client-side validation. It can't validate this input because of the dot in Box.Name (causes a javascript error).
My Model looks like this:
public class Box {
[Required(ErrorMessage = "Please enter a name")]
public string Name { get; set; }
public int BoxMaterialID { get; set; }
}
My ViewModel looks like this:
public class BoxViewModel
{
public Box Box { get; set; }
public List<BoxMaterial> BoxMaterial { get; set;}
}
My Controller looks like this:
public ActionResult New(FormCollection postData)
{
Box box = new Box();
try
{
UpdateModel(box, "Box");
boxService.SaveBox(box);
}
catch
{
return View(new BoxViewModel(box));
}
return RedirectToAction("Index", "Boxes");
}
Server-side validation is working like a charm using DataAnnotations on the Model. The only problem I seem to be having is with the client-side validation because of the "." in the name attribute.
Thanks for your help!
The dot added to the name is used by the default model binder when the form is submitted in order to correctly populate the model. As far as validation is concerned you could set it like this:
$("#myForm").validate({
rules: {
'Box.Name': {
required: true
}
},
messages: {
'Box.Name': {
required: 'some error message'
}
}
});
Try specifying the name attribute as well:
<%= Html.TextBoxFor(m => m.Box.Name, new { id= "txtName", name = "txtName" }) %>

Resources