I have this situation:
Model class:
public class ContatoModel
{
private string nome;
private string email;
private string telefone;
public ContatoModel()
{
}
public ContatoModel(string nome, string email, string telefone)
{
this.nome = nome;
this.email = email;
this.telefone = telefone;
}
public string Assunto { get; set; }
[Required(ErrorMessage = "Nome Obrigatório")]
public string Nome
{
get
{
return this.nome;
}
set
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Nome" });
nome = value;
}
}
[Required(ErrorMessage = "Email Obrigatório")]
public string Email { get; set; }
[Required(ErrorMessage = "Telefone Obrigatório")]
public string Telefone { get; set; }
public string Comentarios { get; set; }
}
A View with:
#using (Html.BeginForm("EnviarContato", "Contato"))
{
<div style="float: left; margin-bottom: 15px;">
#Html.Label("Assunto")<br />
#Html.DropDownList("ddlAssunto", assuntos, new {#class="dropdown"})
</div>
<div style="clear: both"></div>
<div style="float: left; margin-bottom: 10px;">
#Html.Label("Nome Completo", new { #class = "textfield" })<br />
#Html.TextBox("txtNome", "", new { #class = "textfield" })
#Html.ValidationMessage("Nome", "*")
</div>
<div style="clear: both"></div>
<div style="float: left; margin-bottom: 10px;">
#Html.Label("Email")<br />
#Html.TextBox("txtEmail", "", new { #class = "textfield" })
</div>
<div style="clear: both"></div>
<div style="float: left; margin-bottom: 10px;">
#Html.Label("Telefone")<br />
#Html.TextBox("txtTelefone", "", new { #class = "textfield" })
</div>
<div style="clear: both"></div>
<div style="float: left; margin-bottom: 10px;">
#Html.Label("Comentários")<br />
#Html.TextArea("txtComentarios")
</div>
<div style="clear: both"></div>
<div style="float: left; margin: 2px 20px 0px 255px;">
#*<input type="image" src="/Content/images/button_send2.gif" />*#
<input type="submit" value="Enviar" title="Enviar" />
</div>
}
And this method in controller:
[HttpPost]
public ActionResult EnviarContato(FormCollection values)
{
try
{
string assunto = values["ddlAssunto"];
string nome = values["txtNome"];
string email = values["txtEmail"];
string telefone = values["txtTelefone"];
string comentarios = values["txtComentarios"];
model.Assunto = assunto;
model.Nome = nome;
model.Email = email;
model.Telefone = telefone;
model.Comentarios = comentarios;
EnviarContato();
return RedirectToAction("Index", new { envio = "OK" });
}
catch (ValidationException ex)
{
throw new ValidationException(ex.Message); //return RedirectToAction("Index", new { envio = "NOK" });
}
}
I can't do data annotation client works. The ValidationException occurs in server side, but I'd like to see the validation client messages, but it doesn't work. The jQuery files are still loading in my master page.
Another problem is that my view has a combo, loaded by the assunto variable, and I don't know how to include it in validation, to force user select one.
My model class is not for a data entity. It is just to receive form values, to validate and if everything is ok, send the email.
I cant do data annotation client works. The ValidationException occurs in server side, but I´d like to see the validation client messages, but it doesnt work. The jquery files are still loading in my master page.
The files jquery.validate.js and jquery.validate.unobtrusive.js must be included in the page.
The <add key="UnobtrusiveJavaScriptEnabled" value="true" /> must be in the Web.Config.
Another problem is that my view has a combo, loaded by the assunto variable, and I dont know how to include it in validation, to force user select one.
One of Options with empty value should be in your DropDownList. For example "--Select One--".
Related
I have three class types Search, BaseSearch and TextSearch of the following relation. Search is composed of a List<BaseSearch> and TextSearch inherits from BaseSearch, BaseSearch is abstract.
Now I would like to use Html helper to draw a list of TextSearch, EditorTemplate is below
#model GenericSearch.Models.TextSearch
<table class="form-group container">
<tr class="row">
<td class=" col-sm-2 " style="display: table-cell; vertical-align: middle;height: 50px; ">
#Html.LabelFor(x => x.Label, Model.Label, new { #class = "control-label pull-right" })
</td>
<td class=" col-sm-2 " style="display: table-cell; vertical-align: middle;height: 50px; ">
#Html.DropDownListFor(m => m.Comparators, new SelectList(Model.Comparators, "Value", "Text"), new { #class = "form-control", style = "width:150px" })
</td>
<td class="col-sm-8 form-inline" style="display: table-cell; vertical-align: middle;height: 50px;">
#Html.TextBoxFor(x => x.Value, new { #class = "form-control" })
</td>
</tr>
</table>
I have a razor view for Index as below
#model GenericSearch.Models.Search
<div class="row">
#using (#Html.BeginForm("Index", "Home", FormMethod.Post))
{
{
#Html.EditorFor(m => m.List)
<div class="form-group">
<div class="col-sm-12 text-center">
<button type="submit" class="btn btn-primary">Apply filters</button>
</div>
</div>
}
}
</div>
And two Index action at the controller as below
public ActionResult Index()
{
Search search = new Models.Search();
search.List= new List<BaseSearch>();
TextSearch text = new TextSearch();
text.Label = "Text1";
search.MyProperty.Add(text);
return View(search);
}
[HttpPost]
public ActionResult Index(Search search)
{
return View(search);
}
This setting is rendered fine, however when I fill the rendered text boxes and post it through the submit button, I am expecting to receive the Search class populated with the List<TextSearch> that has properties filled with the values entered by the user at the HttpPost Index. But I get an error saying that this can't be done because BaseClass is abstract, when I remove the abstract keyword from the BaseClass the Search class gets instantiated but with a List<BaseSearch> instead of a List<TextSearch> also it has its properties empty, not filled with the data user entered. What am I missing here?
EDIT
public class Search
{
public List<BaseSearch> List { get; set; }
}
public abstract class BaseSearch
{
string label;
protected List<Comparator> comparators;
public string Label
{
get
{
return label;
}
set
{
label = value;
}
}
public List<Comparator> Comparators
{
get
{
return comparators;
}
set
{
comparators = value;
}
}
public BaseSearch()
{
comparators = new List<Models.Comparator>();
}
}
public class TextSearch : BaseSearch
{
string _value;
public string Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
public TextSearch() : base()
{
comparators.Add(new Comparator() { Value = -1, Text = Resources.Choose });
comparators.Add(new Comparator() { Value = 1, Text = Resources.StartWith });
comparators.Add(new Comparator() { Value = 2, Text = Resources.Contains });
}
}
I have the following I coded directly in HTML:
<label for="RememberMe">
<input type="checkbox" name="RememberMe" id="RememberMe" value="true" />
<span>Remember me?</span>
<input name="RememberMe" type="hidden" value="false">
</label>
When I submit the form I get other values but the checkbox always returns false. I know that in the sample application they use something like this. So how come it does not work for me? Note that I had to use this style as it's the one my CSS is expecting. That's why I did not just use the html.checkbox way of coding.
Here's my viewmodel:
public class LoginViewModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
The viewmodel is the same as used in the MVC samples.
Here's the CSS I am using:
label {
display:block;
}
input[type="radio"],
input[type="checkbox"] {
display:none;
}
input[type="radio"] + span:before,
input[type="checkbox"] + span:before {
font-family: 'FontAwesome';
padding-right: 3px;
}
input[type="radio"] + span:before {
content: "\f10c";
}
input[type="radio"]:checked + span:before {
content: "\f111";
}
input[type="checkbox"] + span:before {
content: "\f096";
}
input[type="checkbox"]:checked + span:before {
content: "\f046";
}
Here's the full code:
<form action="/Account/Login" id="login-form" class="form" method="post">
#Html.AntiForgeryToken()
<div id="input-fields">
<div>
#Html.TextBoxFor(m => m.UserName, new
{
id = "user-name",
placeholder = "Username (or guest)",
required = "required ",
#size = "25"
})
</div>
<div>
#Html.PasswordFor(m => m.Password, new
{
placeholder = "Password (or guest)",
required = "required ",
#size = "25"
})
</div>
<label for="RememberMe">
<input type="checkbox" name="RememberMe" id="RememberMe" value="true" />
<span>Remember me?</span>
<input name="RememberMe" type="hidden" value="false">
</label>
</div>
<button class="medium default" id="login" type="submit">Login</button>
<button class="medium" id="register" type="button" onclick="location.href='/Account/Register'">Register</button>
</form>
There is also this javascript:
<script type="text/javascript">
(function () {
document.getElementsByClassName('form')[0]
.addEventListener("submit", function (ev) {
document.getElementById("login").disabled = true;
document.getElementById("register").disabled = true;
document.getElementById("RememberMe").disabled = true;
document.getElementById('message').innerHTML = ev.target.getAttribute('id') == "register-form" ? "System: Registering " : "System: Authenticating ";
setInterval(function () {
document.getElementById('message').innerHTML += '. ';
}, 3000);
}, false);
})();
</script>
It looks like you are disabling the checkbox when the form submits. This could be stopping the checkbox value from being passed so it will default to the hidden field value.
Try removing this line from the javascript:
document.getElementById("RememberMe").disabled = true;
Guys I have tried to use more than one Models with single view.
but I could not found the solution how to implement it.
I want to use One View data in Single past and the other in another part..
I have used the following code..
this is one view
#Html.Partial("Sidebar")
this is another view
<!-- start content -->
<div id="content">
<div class="post">
<h1 class="title">
Add New Post
</h1>
<p></p>
<div class="entry">
#using (Html.BeginForm())
{
<div>
<div style="display:inline;">
<div style="display: inline; float: left;">
#Html.Label("lblcategory", "Category", new { style = "Width:100px; float: left;" })
<div style="width: 150px; height: 60px; overflow-y: scroll; display: inline; float: left;">
#for (int i = 0; i < (int)TempData["Rows"]; i++)
{
for (int j = 0; j < (int)TempData["Cols"]; j++)
{
<input id="Checkbox + #i" name = "Category" type="checkbox" style="width:50px;" value="#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]"/>
#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]
}
}
#*#Html.LabelFor(model => model.CategoryName)*#
</div>
<div style="float:right;">
<label id="lblcategoryrequired" style="color:Red">#Html.ValidationMessageFor(model => model.CategoryName)</label>
</div>
</div>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblsubjet", "Subject", new { style = "Width:100px; float: left;" })
#*#Html.TextBox("txtsubject", "", new { style = "Width:700px;" })*#
#Html.TextBoxFor(model => model.PostSubject, new { style = "Width:400px; maxlength=400;" })
<label id="lblsubjectrequired" style="color:Red">#Html.ValidationMessageFor(model => model.PostSubject)</label>
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblcontent", "Content", new { style = "Width:100px; float: left; Vertical-align:top;" })
#*#Html.TextArea("txtcontent","", new { style = "Width:700px; height:200px; maxlength=700;" })*#
#Html.TextAreaFor(model => model.PostContent, new { style = "Width:400px; height:200px; maxlength=400;" })
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblblank", "a", new { style = "Width:100px; float: left; Color:#372412" })
<input type="submit" value="Add" id="btnadd" style="width: 100px;" class="button" />
    
<a id="Cancel" href="~/Home/Home"> <input type="button" value="Cancel" id="btncancel" class="button" style="width: 100px;" /></a>
</p>
</div>
</div>
#Html.ValidationSummary(true)
}
</div>
</div>
</div>
</div>
I don't understand your question 100%. But if I were to understand it then I don't think it will work the way that you need it to work (I might be mistaken). I would suggest that you move away from your partial view and just pass in one view model that you can use to populate both sections. View models are there to represent your data on a view.
I'm going to give you a basic sample that you can modify and use in your scenario. Lets say we have a customer and this customer can have 1 or many addresses. So a basic representation of these 2 models could look like this:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Address> Addresses { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
And now on your details view you want to display the customer's details and the addresses of this customer. So we have 2 models (customer and address) that you are displaying on 1 view.
public ActionResult Details(int id)
{
Customer customer = customerRepository.GetById(id);
if (customer != null)
{
customer.Addresses = addressRepository.GetAddressesForCustomer(customer.Id);
}
// The above 2 steps can be done in 1 repository call
// Now populate your view model with the above details
// This can also be 1 or 2 lines when you use something like Auto Mapper
CustomerDetailsViewModel viewModel = new CustomerDetailsViewModel
{
viewModel.CustomerId = customer.Id,
viewModel.CustomerFirstName = customer.FirstName,
viewModel.CustomerLastName = customer.LastName,
viewModel.CustomerAddresses = customer.Addresses
};
return View(viewModel);
}
Your view model:
public class CustomerDetailsViewModel
{
public int CustomerId { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public IEnumerable<Address> CustomerAddresses { get; set; }
}
So now you have 1 view model populated from 2 different models. Now all that you have to do on your view is to use this view model to display data:
#model YourProject.ViewModels.Customers.CustomerDetailsViewModel
#Model.CustomerId<br />
#Model.CustomerFirstName<br />
#Model.CustomerLastName<br /><br />
#foreach (var address in #Model.CustomerAddresses)
{
<div>
#address.Id<br />
#address.AddressLine1<br />
#address.AddressLine2<br />
#address.AddressLine3<br />
</div>
}
I hope this helps.
You should use a view model that represents the data required to render your view. You could either expose the models directly on the view model (violating LoD), or delegate the calls to the view model to the underlying models (violating the DRY principle).
My Controler Content is:
public ActionResult Step2()
{
Step2BusinessLogic step2BusinessLogic = new Step2BusinessLogic();
Step2ViewModel step2ViewModel = step2BusinessLogic.CreateStep2ViewModel();
return View(step2ViewModel);
}
[HttpPost]
public ActionResult Step2()
{
....
}
Step2ViewModel has a property like...
public class Step2ViewModel : MultiStepBaseViewModel
{
public IList<LayoutDetail> LayoutConfig { get; set; }
}
Business Logic Class is Like....
public class Step2BusinessLogic
{
public Step2ViewModel CreateStep2ViewModel(string Id)
{
Step2ViewModel step2ViewModel = new Step2ViewModel();
step2ViewModel.MultiStepId = new Guid(Id);
step2ViewModel.LayoutConfig = GetLayout();
return createEmailStep2ViewModel;
}
public List<LayoutDetail> GetLayout()
{
List<LayoutDetail> layoutList = new List<LayoutDetail>();
LayoutDetail layout1 = new LayoutDetail();
layout1.LayoutID = 1;
layout1.LayoutTitle = "1 Column";
layout1.LayoutImg = "~/img/create/layout/layout-1.png";
layout1.LayoutImgPrev = "img/create/layout/layout-1-preview.png";
layoutList.Add(layout1);
LayoutDetail layout2 = new LayoutDetail();
layout2.LayoutID = 2;
layout2.LayoutTitle = "1:2 Column";
layout2.LayoutImg = "~/img/create/layout/layout-2.png";
layout2.LayoutImgPrev = "img/create/layout/layout-2-preview.png";
layoutList.Add(layout2);
.........(12 Items)
return layoutList;
}
}
public class LayoutDetail
{
public int LayoutID { get; set; }
public string LayoutTitle { get; set; }
public string LayoutImg { get; set; }
public string LayoutImgPrev { get; set; }
}
On My .cshtml view i want something Like this...
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.MultiStepId)
#Html.ValidationSummary(true)
#for (int i = 0; i < 12; i++)
{
<div class="grid_3 tcenter">
<div class="divhighlight">
<div style="width: 165px; margin: 6px auto 4px auto;" class="f16 bold tcenter" id="helptrigger1">#LayoutConfig.Title</div>
<a class="fancybox" rel="layouts" href="#LayoutConfig.LayoutImgPrev" title="1 Column">
<img src="#LayoutConfig.LayoutImg" alt="1 Column" width="189" height="227" vspace="5" /></a>
<div style="width:189px; margin:auto">
<button class="button gobutton" style="margin-right: 40px; width: 165px;" value="#LayoutConfig.LayoutID">Select</button></div>
</div>
</div>
}
I want to bind the values of IList<LayoutDetail> property of Step2ViewModel to the controls of .cshtml page. I tried several other thing but could not Succeed
You are missing this #Model.LayoutConfig[i]
#for (int i = 0; i < Model.LayoutConfig.Count(); i++)
{
<div class="grid_3 tcenter">
<div class="divhighlight">
<div style="width: 165px; margin: 6px auto 4px auto;" class="f16 bold tcenter" id="helptrigger1">#Model.LayoutConfig[i].LayoutTitle </div>
<a class="fancybox" rel="layouts" href="#Model.LayoutConfig[i].LayoutImgPrev" title="1 Column">
<img src="#Model.LayoutConfig[i].LayoutImg" alt="1 Column" width="189" height="227" vspace="5" /></a>
<div style="width:189px; margin:auto">
<button class="button gobutton" style="margin-right: 40px; width: 165px;" value="#Model.LayoutConfig[i].LayoutID">Select</button></div>
</div>
</div>
}
You need use
#Model.LayoutConfig[i].LayoutImg
Instead of
#LayoutConfig.LayoutImg
And of cource for other situations
#LayoutConfig.LayoutID
#LayoutConfig.LayoutImgPrev
I have two groups of Radio Buttons on a page:
Phone 1: [ ] Home | [x] Work | [ ] Cell
Phone 2: [ ] Home | [ ] Work | [x] Cell
When you see the page, I'm setting the defaults for Phone 1, "Work", and for Phone 2, "Cell". What is happening is that when a user submits and does not enter a required FirstName, AND selects Home (for Phone 1) and Home (Phone 2) - when the page refreshes, Phone 1 is "Home" and Phone 2 is "Cell".
How is this so? Phone 2 should be "Home" because that's what I selected before I got the error message. Any feedback is greatly appreciated!
Here's the view:
#using (Html.BeginForm("create", "PetSittingRequest"))
{
<label class="labelleft" style="width: 100px">First Name:</label>
<div class="formfield" style="width: 205px">
#Html.TextBoxFor(model => model.ClientDetails[0].NameFirst, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.ClientDetails[0].NameFirst, null )
</div>
// Phone #1 START
<label class="labelleft" style="width: 100px">Phone 1:</label>
<div class="formfield" style="width: 60px">
#Html.TextBoxFor(model => model.Phones[0].PhoneNumber, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.Phones[0].PhoneNumber, null)
</div>
<div class="formfield" style="width: 60px"></div>
<div class="formfield" style="width: 95px"></div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Home", new { #class="radiobtn" } ) Home
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Work", new { #class="radiobtn", #checked = true } ) Work
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Cell", new { #class="radiobtn" } ) Cell
</div>
// Phone #2 START
<label class="labelleft" style="width: 100px">Phone 2:</label>
<div class="formfield" style="width: 60px">
#Html.TextBoxFor(model => model.Phones[1].PhoneNumber, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.Phones[1].PhoneNumber, null)
</div>
<div class="formfield" style="width: 60px"></div>
<div class="formfield" style="width: 95px"></div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Home", new { #class="radiobtn" } ) Home
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Work", new { #class="radiobtn" } ) Work
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Cell", new { #class="radiobtn", #checked = true } ) Cell
</div>
}
The controller that handles the post is this:
[HttpPost]
public ActionResult Create(ClientUser x)
{
try
{
return View("Index", x);
}
catch
{
return View();
}
}
Here are the models:
public class ClientUser
{
public List<ClientDetail> ClientDetails { get; set; }
public List<Phone> Phones { get; set; }
}
public class ClientDetail
{
[Required(ErrorMessage="This field is required.")]
public string NameFirst { get; set; }
}
public class Phone
{
[Required(ErrorMessage="This field is required.")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage="This field is required.")]
public string Location { get; set; }
}
The problem is that at one side you are checking values of your radios using html attributes and on the other side you want your model value to set the same value. so what you want to do can be done by simply removing the #checked = true from your view for each radio buttons and if you need some specific value to be selected when first time form is rendered you can do something like
public ActionResult Create()
{
ClientUser clientUser = new ClientUser();
clientUser.ClientDetails = new List<ClientDetail> { new ClientDetail()};
clientUser.Phones = new List<Phone> { new Phone{Location = "Work"}, new Phone{Location = "Cell"} };
return View(clientUser);
}
this will set value of first radio group to "Work" and second group to "Cell" and will also change the values accordingly when you make changes on form and it is rendered back in case of an error. Moreover, why are you having list of clientDetails when you are showing just one user on the form. i would suggest changing your viewmodel to
public class ClientUser
{
public ClientDetail ClientDetails { get; set; }
public List<Phone> Phones { get; set; }
}