Sorry if I am not seeing anything wrong, but my View don't bind my ViewModel. I debugged many times, and there's no Data in the model when the breakpoint is on the action line.
Other views of the project works fine.
Action:
[HttpPost]
public ActionResult Index_Funcionario(FuncionariosViewModel viewModel)
{
...
View
#model ZebraStudio.Models.FuncionariosViewModel
#{
ViewBag.Title = "Index_Funcionario";
}
<div class="main-field">
<div class="linha-cabecalho">
<div class="aba">Consulta</div>
<div class="area">Funcionários > Consultar</div>
</div>
<div class="sub-field">
<div class="search-field">
#using (Html.BeginForm())
{
<div class="floatleft">
#Html.RadioButton("TipoFiltro", "1", new { #class = "radioFloat" })
<div >Código: #Html.TextBoxFor(model => model.cod_Usuario, new { #class = "customeditor"})</div>
</div>
<div class="floatleft">
<div class="radioFloat">#Html.RadioButton("TipoFiltro", "2", new { #class = "radioFloat" })</div>
<div>Nome: #Html.TextBoxFor(model => model.nome, new { #class = "customeditor"})</div>
</div>
<div class="floatleft">
#Html.RadioButton("TipoFiltro", "3", true, new { #class = "radioFloat" })
<div class="inline">Listar Todos.</div>
</div>
<br />
<input type="submit" value="Buscar" class="searchbutton"/>
}
</div>
<table class="search-result">
<tr>
<th>Código</th>
<th>Nome</th>
<th>Email</th>
<th>Tipo de Usuário</th>
<th>Ações</th>
</tr>
#foreach (var usuario in Model.usuarios)
{
<td>#usuario.UserId</td>
<td>#usuario.Nome</td>
<td>#User.Identity.Name</td>
<td>#foreach (var role in Roles.GetRolesForUser())
{
#role
}
</td>
<td></td>
}
</table>
</div>
ViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace ZebraStudio.Models
{
public class FuncionariosViewModel
{
public IEnumerable<Usuario> usuarios;
public Usuario usuario;
public string nome;
[DataType(DataType.EmailAddress)]
public string Email;
public string password;
public int opcao_Selecionada;
public int cod_Usuario;
}
}
Anything Wrong? Please Help-me.
ASP.Net MVC model binding does not support fields.
You need to change those to properties.
You can use auto-implemented properties:
public string Email { get; set; }
Related
I face with CRUD operations in ASP Net Core web app when I use Telerik UI Editor, create sample text with some formatting it is stored well in DB.
But if I want to edit this text again telerik editor display it with html tags and without formatting.
Did someone have same issue?
Here is my code:
Controller
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var editorData = await _context.Prescriptions.FindAsync(id);
if (editorData == null)
{
return NotFound();
}
return View(editorData);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("PrescriptionID,PrescriptionText")] Prescription editorData)
{
if (id != editorData.PrescriptionID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(editorData);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EditorDataExists(editorData.PrescriptionID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(editorData);
}
and View
#model WebApplication3.Models.Prescription
<h4>EditorData</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit" id="EditorDataForm">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="PrescriptionID" />
<div class="form-group">
<label asp-for="PrescriptionText"></label>
#Html.Kendo().EditorFor(m => m.PrescriptionText).Encoded(false)
<span asp-validation-for="PrescriptionText" class="text-danger k-invalid-msg" data-for="EditorContent"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="k-button k-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="EditorContent" class="k-button">Back to List</a>
</div>
when I run and create new it work
but If I want to edit it display like this
I have tried your code, it works for me. You can try my sample code, if it not works, it means there are something missed in your project.
First, I suggest you need set breakpoint at
👉 var editorData = await _context.Prescriptions.FindAsync(id);
this line in public async Task<IActionResult> Edit(int? id) method. And you need check the value of editorData.PrescriptionText. It should be like below.
<p>Hello world</p><p>My Sample</p><p><strong><em>Italic <span style="text-decoration:underline;">Underline</span></em></strong></p>
Second, you can try my sample code to check your configuration|static files in your project.
My HomeController code:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TelerikAspNetCoreApp1.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
Prescription a = new Prescription();
string aa = "<p>Hello world</p><p>My Sample</p><p><strong><em>Italic <span style=\"text-decoration:underline;\">Underline</span></em></strong></p>";
int id = 1;
a.PrescriptionText = aa;
return View(a);
}
public string edit = string.Empty;
public IActionResult Edit()
{
Prescription a = new Prescription();
a.PrescriptionText = HttpContext.Session.GetString("key");
return View(a);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("PrescriptionID,PrescriptionText")] Prescription editorData)
{
if (id != editorData.PrescriptionID)
{
return NotFound();
}
if (ModelState.IsValid)
{
string aa = editorData.PrescriptionText;
HttpContext.Session.SetString("key", aa);
return RedirectToAction(nameof(Edit));
}
return View(editorData);
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View();
}
}
}
Edit.cshtml and Index.cshtml is same
#{
ViewData["Title"] = "Home Page";
}
#model TelerikAspNetCoreApp1.Prescription;
<h4>EditorData</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit" id="EditorDataForm">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="PrescriptionID" />
<div class="form-group">
<label asp-for="PrescriptionText"></label>
#Html.Kendo().EditorFor(m => m.PrescriptionText).Encoded(false)
<span asp-validation-for="PrescriptionText" class="text-danger k-invalid-msg" data-for="EditorContent"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="k-button k-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="EditorContent" class="k-button">Back to List</a>
</div>
Prescription.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TelerikAspNetCoreApp1
{
public class Prescription
{
public string PrescriptionText { get; set; }
public int PrescriptionID { get; set; }
}
}
Test Result:
I'm new to MVC. Now I'm trying with a simple demo of MVC that to print Customer's information to screen and update it, send back to database.
I have no idea why the Customer's ID becomes null while the others are fine.
I want to display Customer's ID to the screen but I don't want user to edit it to post to my database. I've been researching this for some hours now..
my code :
Customer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace PeopleManagement.Models
{
public class Customer
{
[Required]
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Customer()
{
}
public Customer(string id, string name, int age)
{
Id = id;
this.Name = name;
this.Age = age;
}
}
}
Index.cshtml
#using System.Web.UI.WebControls
#using PeopleManagement.Models
#model IList<Customer>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>First MVC Application</title>
<link href="#Url.Content("~/Content/css/customized-table.css")" rel="stylesheet" type="text/css" />
</head>
<body style="max-width:100%; max-height:100%">
<div id="pageTitle" style="text-align:center; color:red; font-size:24px; font-weight:bold;">Customer Management</div>
#using (#Html.BeginForm("Index", "Home", FormMethod.Post))
{
<div id="tablePanel" style="padding-top: 15px">
<table class="customized_table" border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
#{
for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(model => model[i].Name);
</td>
<td>
#Html.TextBoxFor(model => model[i].Name, new {#style = "min-width:100%; text-align:center", #disable = "true"})
</td>
<td>
#Html.TextBoxFor(model => model[i].Age)
</td>
</tr>
}
}
</table>
</div>
<div>
<p><input type="submit"/></p>
</div>
}
</body>
</html>
<script>
</script>
HomeController.cs
using System.Collections.Generic;
using System.Web.Mvc;
using PeopleManagement.Models;
namespace PeopleManagement.Controllers
{
public class HomeController : Controller
{
public List<Customer> CustomersList { get; private set; } = new List<Customer>(5);
[HttpGet]
public ActionResult Index()
{
CustomersList.Add(new Customer("ID_1", "Name_1", 1));
CustomersList.Add(new Customer("ID_2", "Name_2", 2));
CustomersList.Add(new Customer("ID_3", "Name_3", 3));
ModelState.Clear();
return View(CustomersList);
}
[HttpPost]
public ActionResult Index(List<Customer> postbackCustomers)
{
if (!ModelState.IsValid)
return View(CustomersList);
CustomersList = postbackCustomers;
return View(CustomersList);
}
}
}
Can anyone help ?
In MVC if you want to get some value back from view you have to have that value in the view first. It seems you have not inputted the Id in the view.
Change your view code like this,
for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.HiddenFor(model => model[i].Id)
</td>
<td>
#Html.TextBoxFor(model => model[i].Name, new { #style = "min-width:100%; text-align:center", #disable = "true" })
</td>
<td>
#Html.TextBoxFor(model => model[i].Age)
</td>
</tr>
}
Hope this helps!!
Actually you are not showing the ID on the index.html view, The customer ID has value in your example. You should try to show it in read only mode in the for each loop.
#Html.DisplayFor(model => model[i].Id)
When I declare a text box in view page the below error will appear
The type arguments for method 'System.Web.Mvc.Html.InputExtensions.TextBoxFor<TModel,TProperty>(System.Web.Mvc.HtmlHelper<TModel>,
System.Linq.Expressions.Expression<System.Func<TModel,TProperty>>)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly
even I included
<compilation debug="true" targetFramework="4.0">
<!-- ... -->
</compilation>
this in webconfig file
but the same error shows .
............
my code
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
//..........
model
public string Entity { set; get; }
//.........
//..............
.cshtml page
#model BOSSNew.Models.NewQuantifierM
#{Layout = "../Shared/_Layout.cshtml";}
<div class="breadCrumbHolder">
#{Html.RenderAction("BreadCrumb", "Base", new { menulist = new string[] { "Quantifier", "New Quantifier" }, CurrentURL = new string[] { "#", "#" } });}
</div>
<div class="divContentPane">
<div class="contentPaneHead">
<span class="contentPaneTitle">Users Details </span>
</div>
<table class="ClsTable ClsPad0">
<tr class="even">
<th>#LabelHelper.GetLabel("THLentity", 3)
</th>
<td>
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
<img title="" id="selectentit" style="margin: 5px" onclick="getentity('txtentity','optentity')"
alt="" src="../../../Name.Controls/Themes/Name-Theme/images/entity.png">
</td>
</tr>
</table>
</div>
//.............
Any idea ?
Any help will be appreciated
You haven't defined model for a view, so you can't use
x => x.Field
expression.
It should look more or less like that:
SomeView.cshtml
#model SomeModel
#{Layout = "../Shared/_Layout.cshtml";}
<div class="breadCrumbHolder">
#{Html.RenderAction("BreadCrumb", "Base", new { menulist = new string[] { "Quantifier", "New Quantifier" }, CurrentURL = new string[] { "#", "#" } });}
</div>
<div class="divContentPane">
<div class="contentPaneHead">
<span class="contentPaneTitle">Users Details </span>
</div>
<table class="ClsTable ClsPad0">
<tr class="even">
<th>#LabelHelper.GetLabel("THLentity", 3)
</th>
<td>
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
<img title="" id="selectentit" style="margin: 5px" onclick="getentity('txtentity','optentity')"
alt="" src="../../../Name.Controls/Themes/Name-Theme/images/entity.png">
</td>
</tr>
</table>
</div>
SomeModel.cs
public class SomeModel
{
public string Entity { set; get; }
}
And finally in your action method...
public ActionResult SomeMethod()
{
var model = new SomeModel();
//here fill the entity field
return View(model);
}
I have the following ViewModel
public class EditPatientViewModel
{
public Domain.Entities.Patient patient;
public IEnumerable<Espece> Especes;
public IEnumerable<Client> Clients;
}
the following controller
public ViewResult Edit(int Id_pat)
{
var ViewModel = new EditPatientViewModel();
ViewModel.patient = patientRepo.GetPatientById(Id_pat);
ViewModel.Especes = especeRepo.Especes;
return View(ViewModel);
}
[HttpPost]
public ActionResult Edit(EditPatientViewModel editPatientViewModel)
{
if (ModelState.IsValid)
{
patientRepo.Save(editPatientViewModel.patient);
TempData["message"] = "Sauvé";
return RedirectToAction("Index");
}
else
{
return View(editPatientViewModel);
}
}
and the following view
#model Veto.Models.ViewModels.EditPatientViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Edit Patient</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
<div class="col-md-10">
#Html.HiddenFor(m => m.patient.Id_pat)
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(m => m.patient.Nom_pat)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Every time I submit the form the ViewModel posted is not null but attributes are.. I would like to retrieve the attributes to make an update.
Why?
Tx,
Two same problem in one hour :)
Change your ViewModel to this:
public class EditPatientViewModel
{
public Domain.Entities.Patient patient { get; set; }
public IEnumerable<Espece> Especes { get; set; }
public IEnumerable<Client> Clients { get; set; }
}
In complex types, mvc model binder search for properties not for member variables.
I'm new to ASP.NET MVC 4 and I'm struggling with a concept that would be easy in webforms. So, if I have a Customer class, and a Customer has an Address, how can I edit both the Customer and Address on the same form in the same submit action? I would like to create an '_Edit' partial view for the Address, but I don't know how to wire the controller up if there is no submit button for the Address. I just want a single button to save all the Models in a single View.
So, I could create a new CompanyView model, view, and controller and do it that way. However, if I have many objects having Addresses it seems like a lot of work to keep creating View Models to allow you to edit both the object and the address in the same form. Is there a way to create an Address partial edit view and somehow update the Address fields in the Company Edit Controller? Or, have it somehow pass the model.Address back to the Company Edit Controller instead of null?
Edit:
Models
public class Address
{
public Int32 Id { get; set; }
[Display(Name = "Address 1")]
public String Address1 { get; set; }
[Display(Name = "Address 2")]
public String Address2 { get; set; }
[Display(Name = "City")]
public String City { get; set; }
[Display(Name = "State")]
public String State { get; set; }
[Display(Name = "Postal Code")]
public String PostalCode { get; set; }
[Display(Name = "Country")]
public String Country { get; set; }
}
public class Company
{
public Int32 Id { get; set; }
[Display(Name = "Company Name")]
public String Name { get; set; }
public Int32 AddressId { get; set; }
public virtual Address Address { get; set; }
}
Address _Edit Partial View
#model Models.Address
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.EditorFor(model => model.Address1)
#Html.EditorFor(model => model.Address2)
#Html.EditorFor(model => model.City)
#Html.EditorFor(model => model.State)
#Html.EditorFor(model => model.PostalCode)
#Html.EditorFor(model => model.Country)
</fieldset>
</div>
Company Edit View
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model.Address)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
Company Edit Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address = NULL here!
Success("Record updated!");
return RedirectToAction("Index");
}
}
For model binding to work properly, you need to post only a Company back to your controller. Just pass your whole model onto your partial :
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
_Edit
#model Models.Company
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address should now be available
Success("Record updated!");
return RedirectToAction("Index");
}
}
You should now see the Address navigation property of your model properly bound on post.
Edit based on question in comment
How you set up your views and partials is up to you really. The important thing to remember is that model binding works based on the names given to the form elements by the HTML helpers.
So Html.HiddenFor(m => m.Id) will result in <input name="Id"> while Html.HiddenFor(m => m.Address.Id) will result in <input name="Address.Id">. First one won't be picked up by the model binder as a navigation property of Company, second one will.
The simple route would be to just duplicate your partial view. But if it gets to the point where your partial becomes quite large and complex with a high amount of fields, you could create a partial base class that both your entities inherit of.
BaseEntityWithAddress.cs
public partial class BaseEntityWithAddress
{
public virtual Address Address { get; set; }
}
Customer.cs
public class Customer : BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
Vendor.cs
public class Vendor: BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
And then your partial view would take BaseEntityWithAddress as a model to which you would still pass the whole model.
_Edit.cshtml
#model Models.BaseEntityWithAddress
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
And that will generate form elements with the correct names for the model binder to pick up.
So you would have 2 classes:
class Address
{
public string street {get;set;}
public string state {get;set;}
}
class Customer
{
public string name {get;set;}
public Address address {get;set;} // links to the above class.
}
your main customer view would be something like:
#model Models.Customer
#using (Html.BeginForm()
{
#Html.TextBoxFor(m => m.name)
#Html.Partial("_Edit", Model.address)
<button type="submit">Submit</button>
}
your partial:
#model Models.Address
#Html.TextBoxFor(m => m.street)
#Html.TextBoxFor(m => m.state)
then in your controller:
public ActionResult customer(Customer model)
{
// do whatever
}