Add ID from URL in MVC - asp.net-mvc

Im just starting out with MVC and i'm in the learning phase. I'm currently stuck with this problem. In my soulution i got these two tables.
TopicTable
-TopId
-TopName
ContentTable
-ContId
-TopId
-Content
I want while i'm in the Topic Detailes-view to be able to create new content.
In the detailes.cshtml file i've added:
#Html.ActionLink("Create New Content", "Create", "Content", new { ID = Model.TopicId}, null)` which will display in URL: localhost/Content/Create/1
In my ContentController ive got this, and i get this error when submitting "Validation failed for one or more entities. See 'EntityValidationErrors' property for more details."
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(int Id)
{
ContentModel content = new ContentModel();
if (ModelState.IsValid)
{
content.TopId = Id;
db.ContentModel.Add(content);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(content)
}
The View:
#model WebApplication2.Models.ContentModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>JobOfferModel</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Content, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Model:
public class Topic
{
[Display(Name = "Id")]
public virtual int TopicId{ get; set; }
[Display(Name = "Name")]
public virtual string TopicName{ get; set; }
}
public class Content
{
[Display(Name = "Id")]
[Display(Name = "Id")]
public virtual int ContentId{ get; set; }
[Display(Name = "TopicId")]
public virtual string TopicId{ get; set; }
[AllowHtml]
[Display(Name = "Innihald")]
public virtual string Content { get; set; }
}
So when i'm creating new content the topId value will automaticly be added to the content table.
Would love some help,, Gracias

#Html.ActionLink() is a call to a GET method. You need a GET to return a view that renders the form, and a POST method to receive and save the form data
public ActionResult Create(int ID)
{
Content model = new Content();
model.TopicId = ID; // note TopicId should be int, not string
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Content model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// save your model and redirect.
}
View (divs etc omitted)
#model WebApplication2.Models.Content
....
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(m => m.TopicId) // for postback
#Html.LabelFor(model => model.Content, new { #class = "control-label col-md-2" })
#Html.TextBoxFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
<input type="submit" value="Create" class="btn btn-default" />
}
....

Related

why my checkboxes arent generated?

i have the following controller that calls view with template that generates a set of checkboxes
The controller / Action
public class CompoundsController : Controller
{
//
// GET: /Compounds/
testdbDBContext db = new testdbDBContext();
public ActionResult Index()
{
var comps = db.Compounds.Select(e => new CompoundModel { Id=e.Id, Code=e.Code, Name=e.Name, IsSelected = e.IsSelected }).ToList();
return View(new ChemicalsVM { cModel = comps});
}
}
The view
#model mvca1.Models.ChemicalsVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ChemicalsVM</legend>
<div class="editor-label">
#Html.LabelFor(model => model.SName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SName)
#Html.ValidationMessageFor(model => model.SName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DName)
#Html.ValidationMessageFor(model => model.DName)
</div>
<div class="editor-label">
#Html.Label("Chemicals")
</div>
<div class="editor-field">
#Html.EditorFor(x=>x.cModel)
#Html.ValidationMessageFor(model => model.cModel)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
the template is:
#model mvca1.Models.CompoundModel
#{
ViewBag.Title = "rmplCompoundDB";
}
#Html.HiddenFor(x=>x.Id)
#Html.HiddenFor(x=>x.Code)
#Html.CheckBoxFor(x=>x.IsSelected, (Model.IsSelected)? new {#checked="checked"}:null)
#Html.LabelFor(x=>x.Name)
when i ran the code instead of generating checkboxes with labels it displays the id numbers (that should be hidden)
here is the video of what happens https://youtu.be/1Z2fwfBgyn8
why it does not display the checkboxes as expected?
UPDATE:
here is my ChemicalsVM
public class ChemicalsVM
{
public int Id { get; set; }
public string SName { get; set; }
public string DName { get; set; }
public List<CompoundModel> cModel { get; set; }
public ChemicalsVM()
{
cModel = new List<CompoundModel>();
}
}
here is the CompoundModel class
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
The html being rendered means the ViewEngine is not finding the EditorTemplate. The template must be named the same as the class (i.e. CompoundModel.cshtml) and be located in either the /Views/Shared/EditorTemplates or /Views/Compounds/EditorTemplates folders.

Store update, insert, or delete statement affected an unexpected number of rows (0)

I'm working on an application for insurance requests. When I log in as CommitteeMember and try to Edit a request(editing only its status to "approved" for ex) I get this error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
The line posing a problem is a like in the context class in the Data Project.
public virtual void Commit()
{
base.SaveChanges();
}
Here's my model:
public class Request
{
[Key]
public int RequestId { get; set; }
public DateTime Date { get; set; }
public string nomBeneficiary { get; set; }
[DataType(DataType.Upload)]
public byte[] file { get; set; }
public Member beneficiary { get; set; }
public string status { get; set; }
public string eMailBeneficiairy { get; set; }
}
And here's the controller:
public ActionResult EditRequest (int id)
{
RequestService requestService = new RequestService();
Request request =requestService.GetRequestById(id);
return View(request);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditRequest([Bind(Exclude = "RequestId,Date,nomBeneficiairy,file,beneficiare,eMailBeneficiairy")]Request request)
{
if (ModelState.IsValid) {
RequestService requestService = new Requestervice();
requestService.UpdateRequest(request);
return View("requests");
}
return View(request);
}
And here's the view:
#model Mutuelle.Domain.Entities.Request
#{
ViewBag.Title = "EditRequest";
}
<h2>EditRequest</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Request</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.RequestId)
<div class="form-group">
#Html.LabelFor(model => model.status, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.status)
#Html.ValidationMessageFor(model => model.status)
</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>
Since you are editing, the object should already exist. But it's not attached to the context; try using Attach to attach it first, or query the object from the context and copy the properties over. See this for more info.
EDIT: Per your date comment, you need to either change this to nullable:
public DateTime? Date { get; set; }
And also make null in the DB, or in your controller, before attaching, default it to a date greater than 1/1/1753 (a minimum value allowed in SQL for datetime).

MVC Master Detail Update

I have created master detail form with editorfor templates, I am able to add new records but do not know how to update the child records while editing. I am able to see the phonenumbers in the controller.
Master Table : Person
Detail Table : PersonPhoneNumber
I need to update PersonPhoneNumbers before db.SaveChanges()
Model
public class Person
{
public Person()
{
this.PersonPhoneNumbers = new HashSet<PersonPhoneNumber>();
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<PersonPhoneNumber> PersonPhoneNumbers { get; set; }
public void BuildPhoneNumbers(int count = 1)
{
for (int i = 0; i < count; i++)
{
PersonPhoneNumbers.Add(new PersonPhoneNumber());
}
}
}
public class PersonPhoneNumber
{
public int PersonPhoneNumberId { get; set; }
public string PhoneNumber { get; set; }
public int PersonId { get; set; }
public bool DeletePhone { get; set; }
}
Controller
// GET: /Person/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Person person = db.Persons.Find(id);
if (person == null)
{
return HttpNotFound();
}
return View(person);
}
// POST: /Person/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
db.Entry(person).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}
Edit.cshtml
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.PersonId)
<div class="form-group">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.LastName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
<div>
<label>City</label>
#Html.EditorFor(model => model.PersonPhoneNumbers)
</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>
}
EditorTemplates
PersonPhoneNumber.cshtml
<div>
#Html.HiddenFor(model => model.PersonPhoneNumberId)
#Html.HiddenFor(model => model.PersonId)
</div>
<div class="form-group">
#Html.LabelFor(model => model.PhoneNumber, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
</div>
Also please let me know is there any better way of doing the same.
Thanks
Try this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Person person)
{
if (ModelState.IsValid)
{
db.Entry(person).State = EntityState.Modified;
foreach (var phoneNumber in person.PersonPhoneNumbers)
db.Entry(phoneNumber).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(person);
}

Using one html.editorfor to fill in two model fields

Im trying to use only 1 html.editorfor to fill in two model field in each of my model.
I want the value of this editorfor to be also inserted to my Clientes0013.Client0013
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Client00130012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Client00130012)
</div>
and this one to be also inserted to Clientes0013.F1Pais00200013
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.F1Pais00200012)
#Html.ValidationMessageFor(model => model.CanaClie0012.F1Pais00200012)
</div>
Kindly show me what should be the right way of doing this.
My Table Model:
public partial class CanaClie0012
{
public string Client00130012 { get; set; }
public string F1Pais00200012 { get; set; }
public string F1Cana02530012 { get; set; }
public string Direcc0012 { get; set; }
public Nullable<System.DateTime> TmStmp0012 { get; set; }
}
public partial class Clientes0013
{
public string Client0013 { get; set; }
public string Nombre0013 { get; set; }
public string F1Pais00200013 { get; set; }
}
My Custom Model to combine the two table is:
public class ClientModel
{
public CanaClie0012 CanaClie0012 { get; set; }
public Clientes0013 Clientes0013 { get; set; }
}
My Controller:
[HttpPost]
public ActionResult ClientCreate(CanaClie0012 canaclie0012, Clientes0013 clientes0013)
{
ClientModel vm = new ClientModel();
if (ModelState.IsValid)
{
db.CanaClie0012.Add(canaclie0012);
db.Clientes0013.Add(clientes0013);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
My View:
#model MvcApplication1.Models.ClientModel
#{
ViewBag.Title = "ClientCreate";
}
<h2>ClientCreate</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)
<fieldset>
<legend>ClientModel</legend>
<div class="editor-label">
Client Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Client00130012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Client00130012)
</div>
<div class="editor-label">
Pais
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.F1Pais00200012)
#Html.ValidationMessageFor(model => model.CanaClie0012.F1Pais00200012)
</div>
<div class="editor-label">
Address
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Direcc0012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Direcc0012)
</div>
<div class="editor-label">
Contact Number
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Clientes0013.Nombre0013)
#Html.ValidationMessageFor(model => model.Clientes0013.Nombre0013)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Got it.. modified my controller action to this one.
[HttpPost]
public ActionResult ClientCreate(CanaClie0012 canaclie0012, Clientes0013 clientes0013)
{
ClientModel vm = new ClientModel();
if (ModelState.IsValid)
{
clientes0013.Client0013 = canaclie0012.Client00130012;
clientes0013.F1Pais00200013 = canaclie0012.F1Pais00200012;
db.CanaClie0012.Add(canaclie0012);
db.Clientes0013.Add(clientes0013);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}

ASP.NET MVC 3 Binding to a Collection inside an Object

I have a model with an object that contains a collection like this:
namespace API.Example.Models
{
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public POCO.Order Order { get; set; }
}
}
namespace Supertext.API.POCO
{
public class Order
{
public List<TranslationGroup> Groups = new List<TranslationGroup>();
}
public class TranslationGroup
{
public string GroupId { get; set; }
}
}
The Order object contains a collection called Groups.
In the view I display the collection like this (with the index like explained in several examples)
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
}
And this is the Controller method that gets called:
[HttpPost]
public ActionResult Index(Models.OrderTest model)
The HTML of the UserName element:
<input id="UserName" name="UserName" style="width:300px;" type="text" value="">
and the GroupId element:
<input id="Order_Groups_0__GroupId" name="Order.Groups[0].GroupId" type="text" value="1">
I can access the UserName, but there is nothing in the collection.
What am I missing?
And whats the difference between using m.UserName and Model.Order.Groups (I mean m and Model). Is that my issue?
Each property of POCO entity use like a property managed by the CLR. Let the CLR manage the create of instance and etc.. or you can generate conflicts that can throw issues like you have.
Change your Order code to this:
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
--EDIT
I create a new project and add the following class:
public class TranslationGroup
{
public string GroupId { get; set; }
}
public class Order
{
public List<TranslationGroup> Groups { get; set; }
}
public class OrderTest
{
public string UserName { get; set; }
public string Token { get; set; }
public Order Order { get; set; }
}
Here my code behind of the OrderTestController:
public ActionResult Index()
{
var orderTest = new Models.OrderTest()
{
UserName = "Vinicius",
Token = "12as1da58sd558",
Order = new Models.Order()
{
Groups = new List<Models.TranslationGroup>()
{
new Models.TranslationGroup() { GroupId = "a54s"},
new Models.TranslationGroup() { GroupId = "a87d"},
new Models.TranslationGroup() { GroupId = "2gf4"}
}
}
};
return View(orderTest);
}
[HttpPost]
public ActionResult Index(Models.OrderTest model)
{
return View();
}
And Index View:
#model TestCollection.Models.OrderTest
#{
ViewBag.Title = "Index";
}
<h2>
Index</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)
<fieldset>
<legend>OrderTest</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Token)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Token)
#Html.ValidationMessageFor(model => model.Token)
</div>
#for (int i = 0; i < Model.Order.Groups.Count; i++)
{
<div class="editor-label">
#Html.LabelFor(m => Model.Order.Groups[i].GroupId)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => Model.Order.Groups[i].GroupId)
</div>
}
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So, if you run, and go to OrderTest view, you 'll see all attributes filled, and when you click in create, all things will be binded (the collection as well).

Resources