ICollection object edit cshtml - c#

I want create or edit in collection object. But collection object in return null controller .
ViewModel:
public class ViewModelEditManuscript
{
public int Id { get; set; }
public string ArchiveNumber { get; set; }
public ICollection<ViewModelEditManuscriptAuthor> Authors { get; set;
}
public class ViewModelEditManuscriptAuthor
{
public ViewModelEditPerson Author { get; set; }
}
public class ViewModelEditPerson
{
public int Id { get; set; }
public string TRName { get; set; }
}
Controller:
public ActionResult Edit(ViewModelEdit viewModelEdit)
{
problem this.viewModel.Authors = null;
}
Cshtml:
foreach (var item in #Model.Entity.Authors)
{
#Html.TextBoxFor(m => item.Author.Id)
}

When you use #Html.TextBoxFor(m => item.Author.Id) inside your loop, For all textboxes inside the loop, It is going to generate textbox markup with name property as
name="item.Author.Id"
When the form is submitted the Modelbinder cannot map this form data to an object of the ViewModelEditManuscript class.
For the model binding to work, you need to make sure that you are generating the proper field names which matches with your view model property hierarchy.
Since our ViewModelEditManuscript class has a collection property called Authors and each item of that again has an Author property which again has an Id property, We should tell razor to generate name value for our inputs like
name="Authors[0].Author.Id"
name="Authors[1].Author.Id"
We can do Html.TextBox helper method to do that. The first parameter is the value for the name property of the input.
#model ViewModelEditManuscript
#using (Html.BeginForm())
{
var i = 0;
foreach (var item in #Model.Authors)
{
#Html.TextBox("Authors[" + i+ "].Author.Id",item.Author.Id)
i++;
}
<input type="submit"/>
}
This will work assuming your HttpPost action method's argument is of type ViewModelEditManuscript
[HttpPost]
public ActionResult WhateverYourActionMethodNameIs(ViewModelEditManuscript model)
{
// do something with model and redirect/return something
}

I wantto Authors save.
//this Domain
public class Manuscript
{
public int Id { get; set; }
public string ArchiveNumber { get; set; }
[XmlIgnore]
public virtual ICollection<ManuscriptAuthor> Authors { get; set; }
}
public class ManuscriptAuthor
{
public int ManuscriptId { get; set; }
public int AuthorId { get; set; }
}
//this controller
public ActionResult Edit(ViewModelEdit viewModelEdit)
{
Manuscript manuscript = null;
manuscript.Authors = viewModelEdit.Entity.Authors; // this error
}

Related

How to transfer model to editpage from Data Base?

My input model consists of NewForm in which many fields
public class NewForm
{
[Key]
public int Id { get; set; }
public string HeadForm { get; set; }
public List<Field> Fields { get; set; }
}
public class Field
{
public int Id { get; set; }
public bool Check { get; set; }
public string HeadField { get; set; }
}
I want to take values from the base and edit them, but Model.Fields.Count throw exception. Although the string "HeadForm" is displayed. Lists are not displayed.
EditPage:
#model EditFormApplication.Models.NewForm
#using (Html.BeginForm("Edit", "Home", FormMethod.Post))
{
#Html.TextBoxFor(model => model.HeadForm)
<h5>Fields:</h5><br>
#for ( var i = 0; i< Model.Fields.Count; i++) {
#Html.TextBoxFor(model => model.Fields[i].HeadField)
#Html.CheckBoxFor(model => model.Fields[i].Check)
}
<input type="button" value="Add Field" onclick="addField(this);">
<input type="submit"value="Save">
}
For example, I am typing data by ID = 3.
Controller:
public ActionResult CreateForm(NewForm model)
{
using (NewFormContext db = new NewFormContext())
{
db.NewForms.Add(model);
db.SaveChanges();
return RedirectToAction("Edit");
}
}
public ActionResult Edit()
{
using (NewFormContext db = new NewFormContext()) {
var model = db.NewForms.Find(3);
return this.View(model);
}
}
used Code First and one to many
Sounds like Model.Fields property still contain null when db.NewForms.Find() is executed to assign the model you want to return into view, indicating that EF doesn't create dependent collection yet. As far as I know you should add collection instance definition inside parameterless constructor of entity class:
public class NewForm
{
public NewForm()
{
// instantiate list here
Fields = new List<Field>();
}
[Key]
public int Id { get; set; }
public string HeadForm { get; set; }
public List<Field> Fields { get; set; }
}
Or if you're using lazy loading, mark the property as virtual to let EF instantiate the collection while necessary:
public virtual List<Field> Fields { get; set; }
Related issue:
EF codefirst : Should I initialize navigation properties?

ASP.NET nested list of models is not binding

I'm trying to post a list of models to the server, using ASP.NET's model binding and manipulating a bunch of values with JavaScript. When I send the values to the server, this is what I get:
model.inventory.processed_items[0].id: GA-6570
model.inventory.processed_items[0].event:
model.inventory.processed_items[0].subevent:
model.inventory.processed_items[0].restrict_marking:
model.inventory.processed_items[0].cecp_string:
model.inventory.processed_items[0].discrepancies:
model.inventory.processed_items.Index: 0
model.inventory.processed_items[1].id: GD-1000
model.inventory.processed_items[1].event:
model.inventory.processed_items[1].subevent:
model.inventory.processed_items[1].restrict_marking:
model.inventory.processed_items[1].cecp_string:
model.inventory.processed_items[1].discrepancies:
model.inventory.processed_items.Index: 1
These are my model classes that I'm binding to (I've omitted any fields that don't really matter to the question):
public class PackageViewModel
{
public InventoryViewModel inventory { get; set; }
}
public class InventoryViewModel
{
public List<ProcessedItemViewModel> processed_items { get; set; }
}
public class ProcessedItemViewModel
{
public string id { get; set; }
public int #event { get; set; }
public string subevent { get; set; }
public string cecp_string { get; set; }
public string restrict_marking { get; set; }
public string discrepancies { get; set; }
public string highest_classification { get; set; }
public int occurences_count { get; set; }
public IEnumerable<ProcessedOccurenceViewModel> occurences { get; set; }
}
public class ProcessedOccurenceViewModel
{
public string text { get; set; }
public string security_num { get; set; }
public Nullable<int> media_count { get; set; }
public string classification { get; set; }
}
This is my controller:
[HttpGet]
public ActionResult Create()
{
var inventoryVM = new InventoryViewModel
{
processed_items = new List<ProcessedItemViewModel>()
};
var packageVM = new PackageViewModel {
inventory = inventoryVM
};
return View(packageVM);
}
[HttpPost]
public ActionResult Create(PackageViewModel packageVM)
{
if (ModelState.IsValid)
{
...
}
}
When I check packageVM in debugger, the values are not bound to the view model. However, other values excluding this nested list of models are included in the packageVM model during the POST request. I don't understand why this portion is not binding because I have supplied indices and also passed in an empty list to the view.
The property names for the values you are sending do not match the model you are binding to. PackageViewModel does not contain a property named model (it contains one named inventory), so instead of
model.inventory.processed_items[0].id: GA-6570
it needs to be
inventory.processed_items[0].id: GA-6570
An easy way to think about this is to consider how you would access the value of a property of the model in the POST method
public ActionResult Create(PackageViewModel packageVM)
{
// get the id of the first item in processed_items
string id = packageVM.inventory.processed_items[0].id
Because the parameter in the method is named packageVM, just drop that prefix, (i.e. becomes inventory.processed_items[0].id), and that is what the name of the data needs to be in order to bind.
As a side note, it you are using the strong typed ***For() methods inside a for loop to generate your form controls based on your model, they will generate the correct name attributes, and you can just use $('form').serialize() to correctly generate the data to be sent via your ajax call.

Sending Model issue ASP.net MVC 4

Controller httpGet Action :
[HttpGet]
public ActionResult CalculCom(int id)
{
CalcCom calc = new CalcCom();
ComModel com = calc.CalculCom(id, 10, 2011);
return View(com);
}
This is my View :
// Some code to show my model attribute
#using (Html.BeginForm()) {
#Html.HiddenFor(m=>m.ben)
#Html.HiddenFor(m=>m.centre)
#Html.HiddenFor(m=>m.mtn_brut)
#Html.HiddenFor(m=>m.mtn_net)
#Html.HiddenFor(m=>m.mtn_rs)
#Html.HiddenFor(m=>m.quitaList) // this is a list
#Html.HiddenFor(m=>m.val_rs)
#Html.HiddenFor(m=>m.versNum)
<input type="submit" value="Valider"/>
}
This is my controller HttpPost Action :
[HttpPost]
public ActionResult CalculCom(ComModel model)
{
//some code
foreach (ComModel.quita qi in model.quitaList)
{
var quita = db.QUITA.Find(qi.n_quita);
quita.VERSNUM = vers.VERSNUM;
db.Entry(quita).State = EntityState.Modified;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ComModel :
public class ComModel
{
public int versNum { get; set; }
public decimal mtn_brut { get; set; }
public decimal mtn_net { get; set; }
public decimal mtn_rs { get; set; }
public decimal val_rs { get; set; }
public string ben { get; set; }
public int centre { get; set; }
public List<quita> quitaList = new List<quita>();
public struct quita
{
public decimal mtn_com { get; set; }
public decimal mtn_net { get; set; }
public decimal mtn_ttc { get; set; }
public decimal comp_prime { get; set; }
public decimal mtn_fq { get; set; }
public decimal mtn_tot { get; set; }
public int n_quita { get; set; }
}
}
So What I'm trying to do Is:
getting the Model (HttpGet Action)
show my model the then user will decide it to validate the model or not.
If Model is valide then I will save it to database.
The problem when user Click on submit button the model is sent but the items in quitaList was missing , After sending , in my HttpPost Controler, quitaList was empty
So how to fix it ? Also is there any other ways to do that, showing modal before saving it to database, instead using From to send model?
For get list back in model during form post you need to loop through the list like this
#using (Html.BeginForm()) {
#Html.HiddenFor(m=>m.ben)
#Html.HiddenFor(m=>m.centre)
#Html.HiddenFor(m=>m.mtn_brut)
#Html.HiddenFor(m=>m.mtn_net)
#Html.HiddenFor(m=>m.mtn_rs)
#for(int i=0;i<Model.quitaList.Count;i++)
{
#Html.HiddenFor(m=>m.quitaList[i].mtn_com)
}
#Html.HiddenFor(m=>m.val_rs)
#Html.HiddenFor(m=>m.versNum)
<input type="submit" value="Valider"/>
}
This will give list back in model, but note that it will only contain value of "mnt_com" property. if you want all property value then you need to define all same as in above code in the loop.

Accessing Navigation Properties in a View

I have a Controller action the receives 2 URL parameters, which are foreign keys for the data model:
public ActionResult Create(SurveyResponseModel surveyresponsemodel, int MemberId, int ProgramId)
{
surveyresponsemodel.MemberId = MemberId;
surveyresponsemodel.ProgramId = ProgramId;
return View(surveyresponsemodel);
}
Here is the data model:
public class SurveyResponseModel
{
[Key]
public int ResponseId { get; set; }
public int MemberId { get; set; }
public int ProgramId { get; set; }
// "If yes, what changes did you make? Mark all that apply."
[DisplayName("Did you make any changes in your practice, research, or administration activities as a result of participating in this CME activity?")]
public string CmeChanges { get; set; }
[DisplayName("Better patient follow-up")]
public bool PatientFollowUp { get; set; }
public virtual SurveyProgramModel SurveyProgramModel { get; set; }
public virtual PersonModel PersonModel { get; set; }
And the Data Model for "SurveyProgramType"
public class SurveyProgramModel
{
[Key]
public int ProgramId { get; set; }
public int ProgramYear { get; set; }
public int ProgramStatusId { get; set; }
public string ProgramTitle { get; set; }
public int ProgramTypeId { get; set; }
public virtual SurveyProgramTypeModel ProgramType { get; set; }
public virtual ProgramStatusModel ProgramStatusModel { get; set; }
}
What I want to be able to do in my view, is retrieve the ProgramTitle by the URL parameter that is passed for ProgramId. So the view looks something like:
<div class="editor-label">
#Model.SurveyProgramModel.ProgramTitle
</div>
However, #Model.SurveyProgramModel.ProgramTitle is throwing an exception because it is null. I'm thinking I have my navigation property set up incorrectly. Any idea what that is?
Shouldn't you return your view model to the view?
public ActionResult Create(
SurveyResponseModel surveyresponsemodel) //, int MemberId, int ProgramId)
{
// MemberId and ProgramId arguments do not need to be defined
// They will be picked up my MVC model binder, since there are properties
// with the same name in SurveyResponseModel class
//surveyresponsemodel.MemberId = MemberId;
//surveyresponsemodel.ProgramId = ProgramId;
surveyresponsemodel.SurveyProgramModel = new SurveyProgramModel(); // new line
return View(surveyresponsemodel); // <- return your view model here
}
without passing the model to the view, you cant access the properties of the model in your view. thats the possible cause of the error.
public ~ActionResult PassModel(DemoModel _model, int id)
{
// your code goes here....
return View(_model); // pass the model to view ..so you can work on your model
}

DefaultModelBinder behaviour when property absent from request

I have a model like the following:
public class TestViewModel
{
string UpdateProperty { get; set; }
string IgnoreProperty { get; set; }
ComplexType ComplexProperty { get; set; }
}
where
public class ComplexType
{
long? Code { get; set; }
string Name { get; set; }
}
My controller action:
public Edit(int id, FormColleciton formCollection)
{
var model = service.GetModel(id);
TryUpdateModel(model);
//...
}
When calling the Edit action I have a formCollection parameter containing only a key/value for UpdateProperty.
After the call to TryUpdateModel UpdateProperty is set correctly, IgnoreProperty is left un-touched but ComplexProperty is set to null, even if it previously had a value.
Should TryUpdateModel() only modify properties that are a part of the request? If this is not the case what is the best way to work around this so ComplexProperty is only modified if it is included in the request?
After it was pointed out by Darin that the test case above didn't demonstrate the problem I have added a scenario where this problem really occurs:
public class TestViewModel
{
public List<SubModel> List { get; set; }
}
public class SubModel
{
public ComplexType ComplexTypeOne { get; set; }
public string StringOne { get; set; }
}
public class ComplexType
{
public long? Code { get; set; }
public string Name { get; set; }
}
Controller Action:
public ActionResult Index()
{
var model = new TestViewModel
{
List = new List<SubModel> {
new SubModel{
ComplexTypeOne = new ComplexType{Code = 1, Name = "5"},
StringOne = "String One"
}
}
};
if (TryUpdateModel(model)) { }
return View(model);
}
Sending this request:
/Home/Index?List[0].StringOne=test
updates SubModel.StringOne property but sets ComplexTypeOne to null, even though it is not included in the request.
Is this expected behaviour (given this does not happen unless an enumerable of complex types is used)? How best to work around this?
There must be something wrong with your test case as I was unable to reproduce it. Here's what I tried:
Model (notice that I use public properties):
public class TestViewModel
{
public string UpdateProperty { get; set; }
public string IgnoreProperty { get; set; }
public ComplexType ComplexProperty { get; set; }
}
public class ComplexType
{
public long? Code { get; set; }
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new TestViewModel
{
IgnoreProperty = "to be ignored",
UpdateProperty = "to be updated",
ComplexProperty = new ComplexType
{
Code = 1,
Name = "5"
}
};
if (TryUpdateModel(model))
{
}
return View();
}
}
Now I send the following request: /home/index?UpdateProperty=abc and inside the condition only the UpdateProperty is modified with the new value from the query string. All other properties, including the complex property, are left untouched.
Also notice that the FormCollection action parameter is useless.

Categories

Resources