Trying to access List<> properties from Html.DropDownListFor() - c#

Probably I'm doing this the wrong way, but this is a sample of the code I'm dealing with:
ViewModel
public class TasDataView
{
public int nTas { get; set; }
public string codTas { get; set; }
public decimal nValue { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
public IEnumerable<Segments> ListSegments { get; set; }
public IEnumerable<Tas> ListTas { get; set; }
}
Segments class
public class Segments
{
public int segmentValue { get; set; }
public string segmentCode { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
}
So, when I call the View with my controller, I send an TasDataView object as parameter:
public ActionResult AddTas()
{
TasDataView TDV = new TasDataView();
SegmentsManager SM = new SegmentsManager();
TDV.ListSegments = SM.DataSegments();
return View(TDV);
}
And here is the problem I'm facing. I need all the values of ViewModel for this View to work. So, for example, I have:
#model Project.Models.ViewModel.TasDataView
#Html.EditorFor(model => model.nValue, new { htmlAttributes = new { #class = "form-control" } })
And that will create the box for inserting whatever I want into nValue. But what if I want to access the ListSegments properties (from Segments class) that I sent to the View, so I can make a DropDown List ?
I can't do something like:
#Html.DropDownListFor(x => x.ListSegments.segmentValue, new SelectList(Model.ListSegments));
because all the ListSegments (like segmentValue) properties "are not in" TasDataView, but in Segments class.
How can I reorganize my DataView to be manageable for what I want? Instead of a List<> I should have plain variables?

I guess you're doing it wrong. The first argument of DropDownListFor is an expression that represents the property of the model that receives the value of the item selected in the drop down list. It must be some dedicate=d property somewhere on your model. e.g. selectedSegment.
EDIT:
So, if your goal is to present a list of values via model to the user in a drop down list and let the user pick a value, you'll need to:
have a property on the model to store the selected item (segment), e.g. selectedSegment,
properly render your segments as strings to present them.
The simplest solution is given below.
public class TasDataView
{
public int nTas { get; set; }
public string codTas { get; set; }
public decimal nValue { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
public IEnumerable<Segments> ListSegments { get; set; }
public IEnumerable<Tas> ListTas { get; set; }
public Int32 selectedSegment;
}
#Html.DropDownListFor(x => x.selectedSegment, new SelectList(Model.ListSegments.Select(s => s.segmentCode)));
So there are no properties of the list you need to access.

Related

Automapper executes without error, but no data being copied from source to destination

I have a class like this
public class ListOfBMTTeamMapping
{
public class TeamMapping
{
public List<TeamMappings> results { get; set; }
}
public class TeamMappings
{
public int id { get; set; }
public string areaPath { get; set; }
public string agileReleaseTrainName { get; set; }
public string deliveryTeamName { get; set; }
public string keyedInTeamCode { get; set; }
public string deliveryTeamId { get; set; }
public bool isDeleted { get; set; }
public string modified { get; set; }
public string modifiedBy { get; set; }
}
}
And here is my model class to which I need the above API class to get copied
public class JsonBmtAdoMapping
{
public int? Id { get; set; }
public string AreaPath { get; set; }
public string AgileReleaseTrainName { get; set; }
public string DeliveryTeamName { get; set; }
public string KeyedInTeamCode { get; set; }
public string DeliveryTeamId { get; set; }
public string IsDeleted { get; set; }
public DateTime? Modified { get; set; }
public string ModifiedBy { get; set; }
}
So here is my code I tried
var format = "dd/MM/yyyy";
var dateTimeConverter = new IsoDateTimeConverter { DateTimeFormat = format };
ListOfBMTTeamMapping.TeamMapping Results = new ListOfBMTTeamMapping.TeamMapping();
Results = JsonConvert.DeserializeObject<ListOfBMTTeamMapping.TeamMapping>(responseBody);
List<JsonBmtAdoMapping> jM = new List<JsonBmtAdoMapping>();
jM = _mapper.Map<ListOfBMTTeamMapping.TeamMapping,List<JsonBmtAdoMapping>>(Results);
int n = 10;
And here is my automapper profile
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>();
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
But when the code executes, Ofcourse I am getting the data in results variable without any trouble
But when the mapper code fires, it execute the line without any error, but no data being copied from source to my model class which is the destination
jM.count is always 0 when Results hold 124 rows of data
What I did wrong
Your mapping from TeamMapping to List<JsonBmtAdoMapping> can't be done out of the box by AutoMapper, because your source is an object with a property that contains the list and the destination is a list on itself.
So you have to tell him, how this conversion from a single object to a list can be done. Due to the fact, that you already have a mapping for each individual item, we can use that recursively within our mapping method.
By using this mapping, it should work:
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => src.results.Select(context.Mapper.Map<JsonBmtAdoMapping>).ToList());
Update
Cause a mapper is already defined for the individual items and lists are handled automatically by AutoMapper we can even make it shorter (thanks for Lucian for the hint in the comments):
CreateMap<ListOfBMTTeamMapping.TeamMappings, JsonBmtAdoMapping>();
CreateMap<ListOfBMTTeamMapping.TeamMapping, List<JsonBmtAdoMapping>>()
.ConvertUsing((src, _, context) => context.Mapper.Map<List<JsonBmtAdoMapping>>(src.results));

Posting Radiobuttonfor to different boolean fields whilst grouping then using name property returns null?

I have radiobuttons nested within two for loops, they are for a quiz and only one radiobutton should be selected for each question, here is the second for loop where the radiobutton is:
for (int k = 0; k < Model[i].QuizAnswers.Count(); k++)
{
<li>
#Html.HiddenFor(model => Model[i].QuizAnswers[k].Correct)
#Html.RadioButtonFor(model => Model[i].QuizAnswers[k].Chosen, true, new { id = "radioanswer", #Name = "N-" + #Model[i].Order, data_questionid = #Model[i].Order })
#Html.DisplayFor(model => Model[i].QuizAnswers[k].Answer)
</li>
}
In order to stop the user selecting multiple radiobuttons I have grouped the name attribute for each set of radiobuttons as above. Each Radiobutton is posting true to an individual boolean field. Without the grouped name attribute the radiobuttons post correctly, however with the grouped name attribute they do not post. I'm guessing this is because by grouping the buttons using the name attribute MVC assumes they all should be returning to a single field. How can I fix this so that the Radiobuttons return true to their individual fields whilst at the same time being grouped so that only one can be selected?
Edit - As requested my models are as follows, the view model the radio buttons are posted too:
public class QuizViewModel
{
public int QuizQuestionID { get; set; }
public int QuizID { get; set; }
public int EnrollmentID { get; set; }
public int OldCoursePageID { get; set; }
public string Question { get; set; }
public int Order { get; set; }
public int Type { get; set; }
public IList<QuizAnswers> QuizAnswers { get; set; }
}
The QuizAnswers model within the viewmodel above:
public class QuizAnswers
{
[Key]
public int QuizAnsID { get; set; }
public int QuizQuestionID { get; set; }
public string Answer { get; set; }
public int Order { get; set; }
public bool Correct { get; set; }
public bool Chosen { get; set; }
public virtual QuizQuestions QuizQuestions { get; set; }
}

with list of objects updating wrongly

Here is the class
public class CartManage
{
public int prodId { get; set; }
// public string prodId { get; set; }
public int qty { get; set; }
public string color { get; set; }
public string size { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string Specification { get; set; }
public double Price { get; set; }
public string skew { get; set; }
public string weight { get; set; }
public string maxqty { get; set; }
public string productimage { get; set; }
public string prd_vendor_id { get; set; }
public string prdDeliveryDays { get; set; }
public bool GiftingEnabled { get; set; }
public int GiftingId { get; set; }
}
I use this to manage cart in my website i.e List < CartManage > prodList_temp. Now when a person increase the quantity of an item in cart. I add another object in the list(I used to just increase the quantity of the object but due to some functionality i have to implement i need separate objects). I did this by doing a linq query on the list and just adding the result to cart.
var session_updating_data = prodList_temp.Where(p => p.skew == reqired_skew);
prodList_temp.Add(session_updating_data.FirstOrDefault());
The problem im having is that after inserting when ever change anyting in one of the copies the changes are reflected in all the copies. for example i have two quantity of item A, i.e the cart contains two objects containing details of item a created as shown above. Now if I change the giftingEnabled property of any one of the objects it gets reflected in both. Now i found a work around for this by creating a new object. but i would like to know why this weird phenomenon is happening for future reference.
var session_updating_data = prodList_temp.Where(p => p.skew == reqired_skew);
prodList_temp.Add(session_updating_data.FirstOrDefault());
You are passing a reference to that object to your list, so any change in the object will be reflected everywhere. Where as when you create a new object, it's a separate instance.

DropDownListFor Properties of Collection in ViewModel

I am new to ASP.NET MVC and was/am not sure exactly how to word my problem. I have to create a page where the user can add a list of multiple collateral items to a loan application. Each "row" for each collateral items needs several Dropdownlist to select the type of collateral, its class etc. The page is based on a ViewModel:
public class CollateralViewModel
{
public Guid LoanApplicationId { get; set; }
public IEnumerable<CollateralRowViewModel> Collateral { get; set; }
}
The IEnumerable Collateral gets the following:
public class CollateralRowViewModel
{
public Guid Id { get; set; }
public Guid LoanApplicationId { get; set; }
public IEnumerable<SelectListItem> CollateralClass { get; set; }
public IEnumerable<SelectListItem> CollateralType { get; set; }
public Guid SelectedCollateralType { get; set; }
public Guid SelectedCollateralClass { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public decimal? MarketValue { get; set; }
public decimal? PriorLiens { get; set; }
public decimal? AdvanceRate { get; set; }
public string GrantorFirstName { get; set; }
public string GrantorMiddleName { get; set; }
public string GrantorLastName { get; set; }
}
My Controller looks like this:
public async Task<ActionResult> Create(CollateralViewModel collateralViewModel)
{
var collateralServiceProxy = base.ServiceProvider.CollateralServiceProxy;
var collateralTypes = await GetCollateralTypesByClass(Guid.NewGuid());
var selectedCollateral = collateralViewModel.Collateral.Select(collateral => new Collateral()
{
Id = collateral.Id,
LoanApplicationId = collateral.LoanApplicationId,
CollateralTypeId = collateral.SelectedCollateralType,
Description = collateral.Description,
GrantorFirstName = collateral.GrantorFirstName,
GrantorMiddleName = collateral.GrantorMiddleName,
GrantorLastName = collateral.GrantorLastName,
PriorLiens = collateral.PriorLiens,
MarketValue = collateral.MarketValue
});
foreach (var collateral in selectedCollateral)
{
await collateralServiceProxy.PutCollateralAsync(collateral);
}
return View(collateralViewModel);
}
private async Task<IEnumerable<SelectListItem>> GetCollateralClasses()
{
var collateralServiceProxy = base.ServiceProvider.CollateralServiceProxy;
var collateralClasses = await collateralServiceProxy.GetAllCollateralClassesAsync();
if (collateralClasses == null)
{
return new List<SelectListItem>();
}
return collateralClasses.ToSelectList();
}
private async Task<IEnumerable<SelectListItem>> GetCollateralTypesByClass(Guid collateralClassId)
{
var allCollateralTypes = await GetAllCollateralTypes();
var selectedCollateralTypes = allCollateralTypes.Where(collateralType => Guid.Parse(collateralType.Value).Equals(collateralClassId));
return selectedCollateralTypes;
}
When I try to use #Html.DropDownListFor(model=>model.Collateral.CollateralClasses) I cannot because CollateralClasses is unavailable. I type "(model.Collateral." and the properties aren't there. What am I doing wrong here?
Any help is greatly appreciated!!
Please check you dropdownlistfor syntex. I think that may be the issue (because you have not specified the error).Please check the syntex
#Html.DropDownListFor(m => m.ContribType,
new SelectList(Model.ContribTypeOptions,
"ContribId", "Value",
Model.ContribTypeOptions.First().ContribId))
so you may try it like this. In your first place "valueItRepresent", it should be the property for which the dropdown is for
#Html.DropDownListFor(model => model.valueItRepresent, model.Collateral.FirstOrDefault().CollateralClasses‌ as SelectList, "Select")
The issue is your dropdownlist not populated when rendering the UI. You have to properly populate dropdownlist before render data.This can be done in several ways, but I would recommend reading below article.
This article provide solution for your question
http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx
Hope this helps.

Displaying average rating

I have following two model classes
public partial class Items
{
public Items()
{
this.Items_RATINGS = new HashSet<Items_RATINGS>();
}
public int ITEMID { get; set; }
public string ITEMNAME { get; set; }
public virtual ICollection<Items_RATINGS> Items_RATINGS { get; set; }
}
public partial class Items_RATINGS
{
public int ItemsID { get; set; }
public byte ItemsRATING { get; set; }
public string COMMENTS { get; set; }
public virtual Items Items { get; set; }
}
In the controller calls, I have added
return View(db.Items.Include(c => c.Items_RATINGS).ToList());
In view, I'm calling
Html.DisplayFor(modelItem => item.Items_RATINGS.Average(dr => dr.ItemsRATING))
However, I'm getting following error
Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
How do I retireve Average Value
it's better to calculate the average and then pass to the view, so in you model you could have this:
private ICollection<Items_RATINGS> _Items_RATINGS ;
public double Items_RATINGS
{
get { return _Items_RATINGS.Average(c => c.ItemsRATING); }
set;
}
and then bind the Items_RATINGS in view:
Html.DisplayFor(modelItem => item.Items_RATINGS)

Categories

Resources