Why doesn't my autocomplete work MVC3 Razor Engine - asp.net-mvc-3

I using code from this blog Autocompletion Textbox in MVC Using jQuery
but my jQuery isn't firing. I suspect its to do with my selector. I am using MVC as well but I don't see how that would make the javascript any different.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using UserManager.Models;
namespace UserManager.Controllers
{
public class UserManagerController : Controller
{
//
// GET: /UserManager/
public ActionResult Index()
{
try
{
var data = new UserManager.Models.UserManagerTestEntities();
return View(data.vw_UserManager_Model_Add_Users.ToList());
}
catch (Exception ex)
{
return View(ViewBag);
}
}
public ActionResult CreateUser()
{
var data = new UserManager.Models.UserManagerTestEntities();
ViewBag.Message = "Create New User";
return View();
}
public ActionResult LookUpGroupName(string q, int limit)
{
//TODO: Map list to autocomplete textbox control
DAL d = new DAL();
List<string> groups = d.groups();
var GroupValue = groups
.Where(x => x.StartsWith(q))
.OrderBy(x => x)
.Take(limit)
.Select(r => new { group = r });
// Return the result set as JSON
return Json(GroupValue, JsonRequestBehavior.AllowGet);
}
}
}
#model UserManager.Models.vw_UserManager_Model_Add_Users
#{
ViewBag.Title = "Create New User";
}
<h2>
CreateUser</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>New User Details</legend>
<div class="editor-label">
#Html.LabelFor(Model => Model.salutation)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.salutation)
#Html.ValidationMessageFor(model => Model.salutation)
</div>
<div class="editor-label">
#Html.LabelFor(Model => Model.firstname)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.firstname)
#Html.ValidationMessageFor(model => Model.firstname)
</div>
<div class="editor-label">
#Html.LabelFor(Model => Model.lastname)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.lastname)
#Html.ValidationMessageFor(model => Model.lastname)
</div>
<div class="editor-label">
#Html.LabelFor(Model => Model.password)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.password)
#Html.ValidationMessageFor(model => Model.password)
</div>
<div class="editor-label">
#Html.LabelFor(Model => Model.email)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.email)
#Html.ValidationMessageFor(model => Model.email)
</div>
<div class="editor-label">
#Html.LabelFor(Model => Model.isactive)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.isactive)
#Html.ValidationMessageFor(model => Model.isactive)
</div>
<div class="editor-label">
#Html.Label("Group Name")
<!-- GroupName -->
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.group_name)
#Html.ValidationMessageFor(model => Model.group_name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
}
<script type="text/javascript">
$(document).ready(function () {
$("#group_name").autocomplete('#Url.Action("LookUpGroupName")',
{
dataType: 'json',
parse: function (data) {
var rows = new Array();
alert("before loop");
for (var i = 0; i < data.length; i++) {
rows[i] = { data: data[i], value: data[i].group, result: data[i].group }
}
return rows;
},
formatItem: function (row, i, max) {
return row.group
},
width: 300,
highlight: false,
multiple: true,
multipleseparator: ","
});
});
</script>
HTML rendered to browser:
<input name="group_name" class="text-box single-line" id="group_name" type="text" value=""/>
Probably something simple I just cant see it. Any ideas? Thanks!

I don't believe #Html.EditorFor(model => Model.group_name) adds and ID to the element it creates, therefor your selector will not match. You could add an ID like this:
#Html.EditorFor(model => Model.group_name, new { ID = "group_name"})
In addition, if you wan't to select on an ID with jquery it is better to use the ID-selector #group_name instead, unless you actually have a number of elements where the ID actually start with group_name for all of them, and you want to select all of the elements at once.
Update
You use the attribute start with selector input[id^=group_name, and have a typo in it. You are missing the closing ] in your selector. Even so, if you don't intent to select multiple elements that all have ID's that start with group_name, which your markup indicate that you don't. Then you should really use the ID selector instead.

Do a test run with this
$(function() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"Scala",
"Scheme"
];
$( "#group_name" ).autocomplete({
source: availableTags
});
});

When using MVC3 Razor this syntax will not work:
$("#postTags").autocomplete('<%=Url.Action("LookUpGroupName",) %>',
This is because Razor Engine doesn't understand WebForms Engine Syntax. Instead I used:
$("#group_name").autocomplete('#Url.Action("LookUpGroupName")',
I used the overloaded method which accepts ActionResult name only. This worked for me but you if your solution is setup differently you might have to supply both Controller and ActionResult arguements.
Finally I was getting error code 500 when my AJAX request was being made. This is because in my LookUpGroupName method I had to refactor this line of code:
return Json(GroupValue);
To:
return Json(GroupValue, JsonRequestBehavior.AllowGet);
My original post has all the correct code for anybodys future reference.

Related

Can I restrict client-side validation to specific fields?

I have a Form where I successfully use unobtrusive-validation with the [remote] annotation.
I have other fields in the Form with [required] annotation in the model but I don't want client-side validation for these fields.
I only want server-side validation for [required] fields
I haven't found a solution and I wonder if it's easily feasible?
EDIT :
A part of my code
Part of my model :
I would like the first field : "Email" use Unobtrusive-validation and the second one : "PasswordHash" only use server-side validation even if it has [required] annotation.
Finally, i don't want an AJAX error message for all my form 's fields.
[Required(ErrorMessageResourceType = typeof(Project.Resources.Models.Accounts.User), ErrorMessageResourceName = "EMAIL_REQUIRED")]
[Display(Name = "EMAIL_DISPLAY", ResourceType = typeof(Project.Resources.Models.Accounts.User))]
[Remote("EmailExists", "User", "An account with this email address already exists.")]
public string Email { get; set; }
[Required(ErrorMessageResourceType = typeof(Project.Resources.Models.Accounts.User), ErrorMessageResourceName = "PASSWORDHASH_REQUIRED")]
[DataType(DataType.Password)]
[Display(Name = "PASSWORDHASH_DISPLAY", ResourceType = typeof(Project.Resources.Models.Accounts.User))]
public string PasswordHash { get; set; }
Part of the action in Controller
Server-side validation :
[HttpPost]
public ActionResult Register(User user)
{
if (ModelState.IsValid )
{
DataContext.User.Add(user);
DataContext.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
Ajax validation :
public JsonResult EmailExists(string email)
{
User user = DataContext.User.SingleOrDefault(x => x.Email == email);
return user == null ?
Json(true, JsonRequestBehavior.AllowGet) :
Json(
string.Format("an account for address {0} already exists.",
email), JsonRequestBehavior.AllowGet);
}
Part of the view :
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PasswordHash)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PasswordHash)
#Html.ValidationMessageFor(model => model.PasswordHash)
</div>
<p>
<input type="submit" name="op" id="edit-submit" value="#Project.Resources.Views.User.Register.SUBMIT_FORM" class="form-submit art-button" />
</p>
}
When I click on the sumbit button i would like a server-side validation.
And for some specific fields like Email i would like an Ajax Validation.
there might be better ways, but one way to accomplish this is to do the following
#using (Html.BeginForm("Register", "Home", FormMethod.Post, new { id = "registerForm" }))
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PasswordHash)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PasswordHash)
#Html.ValidationMessageFor(model => model.PasswordHash)
</div>
<p>
<input type="submit" name="op" id="edit-submit" value="#Project.Resources.Views.User.Register.SUBMIT_FORM" class="form-submit art-button" />
</p>
}
<script type="text/javascript">
// add the rules for the fields that you want client-side validation on
// leave out the fields that you dont want client-side validation. they will be validated
// on server side.
$("#registerForm").validate({
rules: {
Email: { required: true }
},
messages: {
Email: { required : "Email is required" }
}
});
</script>

Call ActionResult from Ajax.BeginForm

I using Ajax begin form and when I click submit button, post method doesn't call, here is code:
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "personListDivforReturnPerson"}))
{
<div class="ReturnPersonGeneralPageBody">
<div class="returnPersonHeader">
საზღვრის კვეთისას დაფიქსირებული მონაცემები
</div>
<div class="fieldNameForMIA">
<span>#Html.LabelFor(model => model.LastName, "გვარი")
<br />
#Html.EditorFor(model => model.LastName)
</span>
<div class="fieldNameInnerForMIA">
<span>#Html.LabelFor(model => model.FirstName, "სახელი")
<br />
#Html.EditorFor(model => model.FirstName)
</span>
</div>
</div>
<div class="fieldNameForMIA">
<span>#Html.LabelFor(model => model.PersonalNo, "პირადი ნომერი")
<br />
#Html.EditorFor(model => model.PersonalNo)
</span>
<div class="fieldNameInnerForMIA">
<span>#Html.LabelFor(model => model.DateOfBirth, "დაბადების თარიღი")
<br />
#Html.EditorFor(model => model.DateOfBirth)
</span>
</div>
</div>
<div class="fieldNameForReturnCheckBox">
#Html.LabelFor(model => model.IsIdentified, "სხვა სახელით დაბრუნდა")
#Html.CheckBoxFor(model => model.IsIdentified)
</div>
<div class="saveReturnPerson">
<input type="image" name="submit" id="submit" src="/Content/Resources/SaveGeo.gif" />
</div>
</div>
}
and here is post method which is never called:
[HttpPost]
public ActionResult EditReturnPerson(int id, FormCollection collection)
{ ....
but this method is called when first is loaded:
public ActionResult EditReturnPerson(long parentObjectId, int parentObjectTypeId, bool readOnly = false)
{
....
Mention the method as POST in AjaxOptions
new AjaxOptions { UpdateTargetId = "personListDivforReturnPerson",
HttpMethod ="POST"}
If you do not mention, It will take the Default which is GET.
EDIT : Also If you want to handle it with your own code, You can do it with handwritten JavaScript. Pretty clean and full control.
Get rid of the AjaxBeginForm and use a normal form in your view.
#using(Html.BeginForm())
{
#Html.EditorFor(model => model.FirstName)
#Html.EditorFor(model => model.PersonalNo)
<input type="submit" class="ajaxSubmit" />
}
Now have some javascript to handle the form submit
<script type="text/javascript">
$(function(){
$(".ajaxSubmit").click(function(e){
e.preventDefault();
var item=$(this);
$.post("#Url.Action("EditReturnPerson","YourControllerName")",
item.closest("form").serialize(), function(response){
$("#personListDivforReturnPerson").html(response);
});
});
});
</script>
ბიჭო აქ ვერ გეტყვიან ვერაფერს :D გეუბნები სერვერს მიმართავს და იქ უშლის რაღაცა ხელს. კლიენტის მხარეს ყველაფერი კარგადაა. ეს კიდე მაგარი კაცია, ფორმას უკეთებ სუბმით-ს და default მეთოდი არის პოსტი მაგ დროს.
I found my problem, the problem was [HttpPost] public ActionResult EditReturnPerson(int id, FormCollection collection) { .... in this part, id was int and my id in DB was bigint, so I changed int to long in controller and everything worked, thanks for advice.

inconvenient when editing models

I have a problem trying to edit. I work with Areas for better management the application.The problem is in the areas called "Administrator".
Next is the controller code (OfficeControlle), I use a session variable has been previously created and functions to edit the model data I get.
public ActionResult Edit()
{
decimal id;
id = (decimal)Session["consul"];
CAMPUS_UNIVERSITY campus_university = db. CAMPUS_UNIVERSITY.Single(s => s.Idoffice == id);
ViewData.Model = db.OFFICE.Single(c => c.Idoffice == id);
ViewBag.University = db.UNIVERSITY.Single(u => u.IdUniversity == campus_university.IdUniversity);
ViewBag.campus = db.CITY_CAMPUS.Single(u => u.IdCity == campus_university.Idcitycampus);
return View(sede_universidad);
}
[HttpPost]
public ActionResult Edit(CAMPUS_UNIVERSITY campus_university, OFFICE office)
{
if (ModelState.IsValid)
{
db.CAMPUS_UNIVERSITY.Attach(campus_university);
db.ObjectStateManager.ChangeObjectState(campus_university, EntityState.Modified);
db.SaveChanges();
db. OFFICE.Attach(office);
db.ObjectStateManager.ChangeObjectState(office, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.IdCitycampus = new SelectList(db.CITY_CAMPUS, "IdCity", "Name", campus_university.IdCitycampus);
ViewBag.IdConsultorio = new SelectList(db.OFFICE, "Idoffice", "addressoffice", campus_university.Idoffice);
ViewBag.IdUniversidad = new SelectList(db.UNIVERSITY, "IdUniversity", "Name", campus_university.IdUniversity);
return View(campus_university);
}
Next is the view code
#model RolMVC3.Models.CAMPUS_UNIVERSITY
#{
ViewBag.Title = "Edit";
}
<h2>edit</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<h2> #ViewBag.University.Name - #ViewBag.Campus.Name </h2>
<fieldset>
<legend>OFFICE</legend>
#Html.HiddenFor(model => model.IdUniversity)
#Html.HiddenFor(model => model.IdCitycampus)
#Html.HiddenFor(model => model.Idoffice)
<div class="editor-label">
#Html.LabelFor(model => model.addresscampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.addresscampus)
#Html.ValidationMessageFor(model => model.addresscampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.phonecampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.phonecampus)
#Html.ValidationMessageFor(model => model.phonecampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.emailcampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.emailcampus)
#Html.ValidationMessageFor(model => model.emailcampus)
</div>
<fieldset>
<legend>OTHER DATE</legend>
#Html.Partial("_office", Model.OFFICE)
</fieldset>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("back", "Index")
</div>
The problem appears when I press the "Save" button, get the following error:
The parameters dictionary contains a null entry for parameter 'Id' of non-nullable type ''System.Decimal' ' for method ''System.Web.Mvc.ActionResult Index(System.Decimal)' in ''RolMVC3.Areas.Administrator.Controllers.OfficeController''
When you are redirecting here:
return RedirectToAction("Index");
make sure that you pass the id in the query string as it looks like your Index action requires it as parameter:
return RedirectToAction("Index", new { id = campus_university.IdUniversity });
I'm assuming that your Index action method looks something like this (please correct me if I am wrong):
public ActionResult Index(decimal id)
{
// Your method's code
}
So where you do return RedirectToAction("Index"); you are trying to redirect to an action method that takes no parameters. But in this case there is an action method that requires a parameter, namely id. So when redirecting you need to change your code and supply this id parameter.
This is what you could do:
return RedirectToAction("Index", new { id = /* put your id here */ });

Using #Html.HiddenFor in MVC3

I'm having lots of troubles.
I think that MVC just hates me.
1st. I'm using Linq and the model is automagically generated. I just completed the properties I need with the [Required] tag/directives.
2nd. I have a "Big Model" that joins two of the models.
Like is explained here -> Multiple models in a view
When I try to postback a view with a model that has those properties like nulls, is has the ModelState.isvalid == false. I think that is obvious because I set the [Required] to some of the properties that the model needs.
And here comes the thing that brought me here.
3rd. When I'm trying to use #Html.HiddenFor(...) my page won't postback.
If I use, let's say, 3 HiddenFor, the page does PostBack, but if I use 10 HiddenFor, the page just stand still. It does not go anywhere.
I've tried to do everything that is within my range of knowledge (very limited, I'm really new at MVC).
I've tried to bring to the view those properties and showing them up as if it were a "Detail View". Didn't succeed.
I've tried to set the #HiddenFor(model => model.Client). In the Action is passed as null.
I've tried to use these tons of HiddenFor.
I've tried to pass just an ID in the hidden (ClientID) and retrieve the object from the database, but the ModelState will not "update" its status once inside the action.
Why am I doing this?
I'm doing this because I need the pages to display the "Required Field Message" when a box isn't filled, hence, forbiding the page to postback without the data.
My database is fine, and those fields are "Not null", so, I can just remove the [Required] from the properties, but I would lose the "Required Field Message" (in addition to the PostBack that is the thing that I'm trying to avoid).
If anyone has the answer or an answer or whatever, please, post it... I'm about to shoot my head out xD
Thanks in advance...
PS: Sorry about my english... I know that it's not good (or even regular).
View
#model PruebaMVC.Models.OperacionModel
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Operación de Venta</legend>
#Html.HiddenFor(model => model.INMUEBLE)
#*#Html.HiddenFor(model => model.INMUEBLE.Direccion)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Localidad)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Ciudad)*#
#*#Html.HiddenFor(model => model.INMUEBLE.Caracteristicas)*#
#*#Html.HiddenFor(model => model.INMUEBLE.PrecioVenta)*#
#*#Html.HiddenFor(model => model.INMUEBLE.CLIENTE.IDCliente)*#
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.Nombre, "Nombre del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.Nombre)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.Nombre)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.Apellido, "Apellido del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.Apellido)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.Apellido)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.FechaNacimiento, "Fecha de Nacimiento del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.FechaNacimiento)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.FechaNacimiento)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.CLIENTE1.DNI, "DNI del Comprador")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.CLIENTE1.DNI)
#Html.ValidationMessageFor(model => model.OPERACION.CLIENTE1.DNI)
</div>
<div class="editor-label">
#*#Html.LabelFor(model=>model.OPERACION.IDFormaPago, "Forma de Pago")*#
<label for="ComboFP">Forma de Pago</label>
</div>
<div class="editor-field">
<select id="ComboFP" name="SelectFP">
#{
foreach (PruebaMVC.Models.DatosLINQ.FORMA_PAGO item in PruebaMVC.Models.DatosLINQ.OperacionDatos.ListarFormaPago())
{
<option value="#(item.IDFormaDePago)">#(item.TipoPago)</option>
}
}
</select>
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.Comision, "Comisión de la Venta")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.Comision)
#Html.ValidationMessageFor(model => model.OPERACION.Comision)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.OPERACION.Legajo, "Número de Legajo")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OPERACION.Legajo)
#Html.ValidationMessageFor(model => model.OPERACION.Legajo)
</div>
<p>
<input type="submit" class="formbutton" value="Cargar Venta" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Volver al listado de Inmuebles", "Index")
</div>
Controller
//
// GET: /Inmueble/Sale/5
public ActionResult VentaP(int id)
{
OperacionModel unModeloOperacionCompuesto = new OperacionModel();
unModeloOperacionCompuesto.INMUEBLE = InmuebleDatos.DetallesInmueble(id);
return View(unModeloOperacionCompuesto);
}
//
// POST: /Inmueble/Sale/5
[HttpPost]
public ActionResult VentaP(OperacionModel model, FormCollection collection)
{
try
{
// TODO: Add insert logic here
model.INMUEBLE = InmuebleDatos.DetallesInmueble(model.INMUEBLE.IDInmueble);
CLIENTE clienteComprador = new CLIENTE();
clienteComprador.Nombre = model.OPERACION.CLIENTE1.Nombre;
clienteComprador.Apellido = model.OPERACION.CLIENTE1.Apellido;
clienteComprador.DNI = model.OPERACION.CLIENTE1.DNI;
clienteComprador.FechaNacimiento = model.OPERACION.CLIENTE1.FechaNacimiento;
OPERACION nuevaOperacion = new OPERACION();
int unIDUsuario = UsuarioDatos.IDUsuario(User.Identity.Name);
int unIDFormaPago = Convert.ToInt32(collection["SelectFP"]);
decimal unaComision = model.OPERACION.Comision;
int unLegajo = model.OPERACION.Legajo;
if (ModelState.IsValid)
{
nuevaOperacion.INMUEBLE = model.INMUEBLE;
nuevaOperacion.FechaOperacion = DateTime.Now;
nuevaOperacion.IDUsuario = unIDUsuario;
nuevaOperacion.IDFormaPago = unIDFormaPago;
nuevaOperacion.INMUEBLE.IDEstado = 2;
nuevaOperacion.Monto = model.INMUEBLE.PrecioVenta;
nuevaOperacion.Comision = unaComision;
nuevaOperacion.Legajo = unLegajo;
nuevaOperacion.CLIENTE1 = clienteComprador;
nuevaOperacion.CLIENTE = model.INMUEBLE.CLIENTE;
OperacionDatos.CrearVenta(nuevaOperacion);
return RedirectToAction("Index");
}
else
{
//return View(nuevaOperacion);
return View(model);
}
}
catch
{
return View(model);
}
}
Edit 2:
I'm still touching the code, and when I comment the line of
#Html.HiddenFor(model => model.INMUEBLE.PrecioVenta)
Where "PrecioVenta" is a decimal(18,2), the page does post back... it is obviously still getting a ModelState.isValid == false because I'm having left that value.
What can I do?
Which are the primitive types for the "HiddenFor" will work?
Or is some stuff of the .Net Framework that can't "map" that datatype properly?
I think that the problem is the client side validations and decimals.
When you have a decimal value, it render it as "35,0" in your culture... but the javascript validator doesn't recognice the "," as a decimal coma.
This is a problem I'm having but I've found a post here in stackoverflow about modifying the javascript validator.
Here you can learn how to fix the javascript validator for decimals

ado.net mvc3 tuple using in model and single views

I have the following ADO Model
Student
Id,Name
and
Course
Id,Name,Student_ID
I have made the following view for it
#model Tuple<MvcApplication4.Models.Course, MvcApplication4.Models.Student >
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item1.Name)
#Html.ValidationMessageFor(model => model.Item1.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.S_ID, "Student")
</div>
<fieldset>
<legend>Student</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item2.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item2.Name)
#Html.ValidationMessageFor(model => model.Item2.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item2.Class)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item2.Class)
#Html.ValidationMessageFor(model => model.Item2.Class)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</fieldset>
}
And the controller for it is as
public ActionResult Create()
{
return View();
}
//
// POST: /Default3/Create
[HttpPost]
public ActionResult Create(Tuple<Student ,Course > t)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(t.Item1);
db.SaveChanges();
t.Item2.S_ID = t.Item1.Id;
db.Courses.AddObject(t.Item2);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View();
}
}
But When i click the Creat button it gives the following Error
Server Error in '/' Application.
No parameterless constructor defined for this object.
The Tuple<X, Y> class doesn't have a default constructor so you will need to write a custom model binder if you want this to work. Another possibility is to use a custom view model which is what I would recommend you:
public class MyViewModel
{
public Course Course { get; set; }
public Student Student { get; set; }
}
and then:
public ActionResult Create()
{
return View(new MyViewModel());
}
//
// POST: /Default3/Create
[HttpPost]
public ActionResult Create(MyViewModel model)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(t.Student);
db.SaveChanges();
t.Course.S_ID = t.Student.Id;
db.Courses.AddObject(t.Course);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View(model);
}
}
and finally:
#model MvcApplication4.Models.MyViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Course</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Student.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Student.Name)
#Html.ValidationMessageFor(model => model.Student.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Student.S_ID, "Student")
</div>
<fieldset>
<legend>Student</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Course.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Course.Name)
#Html.ValidationMessageFor(model => model.Course.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Course.Class)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Course.Class)
#Html.ValidationMessageFor(model => model.Course.Class)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
MVC is pretty smart, but it can't really figure out how to create a new instance of Tuple and create new instances of the items, then assign the proper items to it. That's just too complex of a task.
The error you get is because a Tuple doesn't have a default parameterless constructor, and requires new items to be passed to it in the constructor, something that MVC can't do.
You will have to break this down, and create your tuple in your controller action from a viewmodel that contains your items as members.
You need to pass the model to your view.
Example:
return View(model);
This seems to have resolved the issue for me as an alternative and it is working now:
[HttpGet]
public ActionResult Create()
{
Course course = new Course();
Student student = new Student();
var tuple = new Tuple<Course,Student>(course,student);
return View(tuple);
}
[HttpPost]
public ActionResult Create(Tuple<Course,Student> tuple){ do something ...}
I tried several other approaches include some that have been suggested here but, didn't resolve the problem. I just posted this to help someone else who might want to use Tuple though, use it only if you don't have another alternative.
I got it to work after a few minutes of digging and some thinking. Here's a quick example of what I did:
GET action:
[HttpGet]
public ActionResult Update(int id = 0)
{
ProductDto product = _productService.FindByID(id);
SupplierDto supplier = _supplierService.FindByProductID(productId: product.ProductID);
return View(model: new Tuple<ProductDto, SupplierDto>(product, supplier));
}
POST action:
[HttpPost]
public JsonResult Update(int id = 0, ProductDto Item1, SupplierDto Item2)
{
// Get the product name
string productName = Item1.ProductName;
// Get the supplier name
string supplierName = Item2.SupplierName;
...
return Json(new { success = true });
}
View:
#model Tuple<ProductDto, SupplierDto>
#{
ViewBag.Title = "add title later ... ";
AjaxOptions options = new AjaxOptions { ... };
}
#using (Ajax.BeginForm("Update", "Product", options, htmlAttributes: new { #id = "update-form" }))
{
<fieldset>
<legend>Update Product</legend>
<div class="display-label">
#Html.LabelFor(model => model.Item1.ProductName)
</div>
<div class="display-field">
#Html.EditorFor(model => model.Item1.ProductName)
</div>
...
<div class="display-label">
#Html.LabelFor(model => model.Item2.SupplierName)
</div>
<div class="display-field">
#Html.EditorFor(model => model.Item2.SupplierName)
</div>
</fieldset>
<div class="submit-button">
<button type="submit" class="button">Update details</button>
<div>
}
You should bind prefix in parameters
Controller:
public ActionResult ThisMethod([Bind(Prefix = "Item1")] AccountViewModel model)
{
// toDo
}
View:
#model Tuple<AccountViewModel>
#Html.EditorFor(model => model.Item1.Firstname)
#DarinDimitri's solution is right but there is a way with Tuple as well. If you just change these code below you will get tuple models.
[HttpPost]
public ActionResult Create(Course Item1, Student Item2)
{
try
{
// TODO: Add insert logic here
db.Students.AddObject(Item2);
db.SaveChanges();
Item1.S_ID = Item2.Id;
db.Courses.AddObject(Item1);
db.SaveChanges();
return RedirectToAction("Copy");
}
catch
{
return View();
}

Resources