How to access Dictionary Model Property value from View - ASP.Net MVC - c#

I want to get value of Dictionary from View.
In the view, I have a main/first foreach loop that retrieve data from Model, and inside the main/first loop, I need to retrieve the ListAttribute value according to the first loop by Id.
**//Code in the View - First loop to retrieve data from Model**
#model IEnumerable<ABC.Web.Models.Room.Housing>
foreach (var item in Model.OrderBy(x => x.Id))
{
<div class="col-xs-18 col-sm-4">
<div class="thumbnail">
*...(remainer of the code)*
//Here to insert second loop to retrieve *ListAttribute*
}
//Code in the Model
namespace ABC.Web.Models.Room
{
public class Housing
{
public string[] FloorPlan { get; set; }
public Dictionary<string, ListAttribute> ListAttributes { get; set;}
public string Latitude { get; set; }
}
public partial class ListAttribute
{
public string name { get; set; }
public string icon { get; set; }
public string value { get; set; }
}
}

If item is an object of type Housing, then you can do this:
foreach (KeyValuePair<string, ListAttribute> listItem in item.ListAttributes)
{
// Then you will have...
// listItem.Key -> string
// listItem.Value -> ListAttribute
}
Source

Related

How to add items to existing list of objects?

I have three classes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; set; }
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; set; }
}
And I have two Lists in my code like this:
List<M2ArticleMain> data = new List<M2ArticleMain>();
List<M2ArticleAttributeWeb> attb = new List<M2ArticleAttributeWeb>();
In some part of my code firstly I (from foreach loop) add data to attb list where I add only only some data (because I don't have all data at this point), like this:
...
attb.Add(new M2ArticleAttributeWeb
{
Web_id = item.Id, //(item is from foreach loop)
Variants = null //this is **importat**, I left null for later to add it
});
Next, after I fill attb, I add all this to data list:
...
data.Add(new M2ArticleMain
{
Id = item.Id_Pk, //this is also from foreach loop,
Attribut_Web = attb //now in this part I have only data for Web_id and not Variants
}
Now my question is How to Add items later to data list to object Variants?
Something like this:
data.AddRange( "how to point to Variants" = some data);
The M2ArticleAttributeWeb type holding your Variants property is the member of a collection. That is, there are potentially many of them. You can reference an individual Variants property like this:
data[0].Attribut_Web[0].Variants
But you need to know which items you want to add map to which data and Attribut_Web indexes/objects in order to assign them properly. That probably means another loop, or even a nested loop. That is, you can see all of your Variants properties in a loop like this:
foreach(var main in data)
{
foreach(var attrw in main)
{
var v = attrw.Variants;
// do something with v
Console.WriteLine(v);
// **OR**
attrw.Variants = // assign some object
}
}
It's also much better practice to create your collection properties with the object, and then give them private set attributes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; private set; } = new List<M2ArticleAttributeWeb>();
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; private set; } = new List<string>();
}
Now instead of assigning Attribut_Web = attb, you would need to .Add() to the existing List.

Auto Generate select from list in model

I have the following sample model:
public class FooModel
{
public List<Bar> myList { get; set; }
}
public class Bar
{
public string description { get; set; }
public int pos { get; set; }
public int myField { get; set; }
}
And, in my cshtml file I have this:
#foreach (var bar in Model.myList)
{
<div class="row">
<div class="col-2">PLACEHOLDER</div>
</div>
...
}
So basically, the field myField will be a match (when it has some value set) to a pos of another item. What I want, is to autogenerate a dropdown in PLACEHOLDER containing all the descriptions (and pos as value), of all Bar, with the one that matches selected.
I tried this approach (sample) but this shouldn't work, since I am in a foreach inside my Model
#Html.DropDownListFor(col=> col.myField, new SelectList(Model.myList.description, "Id", "Text"), "Choose... ")
Can I do this automatically or will I have to create the dropdown manually?
Thanks!

Bind multiselect selections to list of objects

I have a view model like so:
public class ListingPlanEditorViewModel
{
public ListingPlan Plan { get; set; }
public IEnumerable<Directory> SiteDirectories { get; set; }
}
One property is an object of type ListingPlan here:
public class ListingPlan
{
public int? ListingPlanID { get; set; }
public int DescriptionLinesCount { get; set; }
public List<Directory> Directories { get; set; }
}
The object Directory looks like this:
public class Directory
{
public int DirectoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I have a controller that returns a ListingPlanEditorViewModel to the view:
public ActionResult ConfigurePlan(int? listingIdentifier)
{
ListingPlan plan = new ListingPlan()
{
DescriptionLinesCount = 10,
Directories = new List<Directory>()
{
new Directory()
{
DirectoryID = 3
},
new Directory()
{
DirectoryID = 4
}
}
};
ListingPlanEditorViewModel model = new ListingPlanEditorViewModel()
{
Plan = plan,//_listingRepository.GetListingPlan(listingIdentifier, null),
SiteDirectories = _database.GetDirectories()
};
return View(model);
}
I would like to create a multiselect box that will bind the selected values back to the Plan property in the ListingPlanEditorViewModel, setting the DirectoryID property for each selection. So after binding I should have a List of Directory objects. All with their DirectoryID's set.
I'm having some trouble doing this. I can create the multiselectbox with the correct select options in it, but I am unable to retrieve them in my post action which looks like this:
#using (Html.BeginForm("ConfigurePlan", "ListingPlan"))
{
<div class="form-body">
#Html.ListBoxFor(model => model.Plan.Directories, new MultiSelectList(Model.SiteDirectories, "DirectoryID", "Name"))
</div>
<button type="submit">submit</button>
}
You have to create an [] or List of IDs in the ViewModel that will store selected values.
public class ListingPlanEditorViewModel
{
public ListingPlan Plan { get; set; }
public IEnumerable<Directory> SiteDirectories { get; set; }
public int[] DirectoryIDs {get;set;}
}
The View will change according. The Directories selected will be stored in DirectoryIDs.
#using (Html.BeginForm("ConfigurePlan", "ListingPlan"))
{
<div class="form-body">
#Html.ListBoxFor(model => model.DirectoryIDs, new MultiSelectList(Model.SiteDirectories, "DirectoryID", "Name"))
</div>
<button type="submit">submit</button>
}
Now on POST Action you can query the database and get the Directories that was selected by user.
Note: You can't just get the full objects because the ListBoxFor will generate a <select multiple ... > ... </select> tag won't know how to bind to your object.

substring one field on model and send to view

i have a model and i send substring one field on this model and return to a view for show in gridview
my model is:
public class News
{
public int ID { get; set; }
[MaxLength(300)]
public string Title { get; set; }
[DataType(DataType.MultilineText)]
[MaxLength]
public string Content { get; set; }
[ReadOnly(true)]
public DateTime Date { get; set; }
[Column("PictureID")]
public virtual Picture Picture { get; set; }
//public IList<Picture> PicID { get; set; }
[Column("NewsTypeID",Order=1)]
public virtual NewsType NewsType { get; set; }
public ICollection<Tag> Tags { get; set; }
public News()
{
Tags = new List<Tag>();
}
}
when i send this model by myController:
public ActionResult ShowNews()
{
var data = new DatabaseContext();
var news = data.newsInfo.ToList();
return View(news);
}
it is ok and show properly in gridview
but if send this model by this cod in controller:
public ActionResult ShowNews()
{
var data = new DatabaseContext();
var news = data.newsInfo.Select(x => new { Content = x.Content.Substring(0,200), x }).ToList();
return View(news);
}
show this Error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType02[System.String,NewsAgency.Models.News]]', but this dictionary requires a model item of type 'System.Collections.Generic.List`1[NewsAgency.Models.News]'.
i have send substring one of the field
what is problem?
You have created list of anonymous objects in this statement:
data.newsInfo.Select(x => new { Content = x.Content.Substring(0,200), x }).ToList();
And you have send it as model to your view:
View(news);
But, in your view you have set model type as List<News>. So, the exception is throwned. Try to change your code as:
var news = data.newsInfo.AsEnumerable().Select(x => { x.Content = x.Content.Substring(0,200); return x; }).ToList();
If you want to send whole Content values along with substrings, then I recommend to use first way and get the substring of all item's Content with razor inside view.

Child foreach not looping as intended in Partial using ViewModel

I have a List of Recipes and each Recipe has a number of RecipeLines, I want to loop Each Recipe with it's corresponding Recipe Lines foreach Looping inside of the parent Recipe foreach.
Recipe Class
namespace XXX.Models
{
public class Recipe
{
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public string RecipeInstructions { get; set; }
public virtual List<RecipeLine> RecipeLines { get; set; }
}
}
RecipeLine Class
namespace XXX.Models
{
public class RecipeLine
{
public int RecipeLineID { get; set; }
public float Quantity { get; set; }
public int MeasurementID { get; set; }
public int RecipeID { get; set; }
public int IngredientID { get; set; }
public virtual Measurement Measurement { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual Ingredient Ingredient { get; set; }
}
}
No need to list the Ingredient and Measurement Class, but they are structured fine.
Now let's look at the ViewModel
namespace XXX.ViewModels
{
public class RecipeLineViewModel
{
public IEnumerable<Recipe> Recipes { get; set; }
public IEnumerable<RecipeLine> RecipeLines { get; set; }
}
}
And the PartialsController
namespace XXX.Controllers
{
public class PartialsController : Controller
{
private XXXDb db = new XXXDb();
public ActionResult RecipeList()
{
RecipeLineViewModel viewModel;
viewModel = new RecipeLineViewModel();
viewModel.Recipes = db.Recipes.ToList();
viewModel.RecipeLines = db.RecipeLines.Include(r =>
r.Measurement).Include(r => r.Ingredient);
return PartialView("_RecipeList", viewModel);
}
}
}
Now the partial view is Views > Partials > __RecipeList.cshtml
RecipeList Partial View
#model XXX.ViewModels.RecipeLineViewModel
#foreach (Recipe recipe in Model.Recipes)
{
<div>#recipe.RecipeName</div>
<div>#recipe.RecipeInstructions</div>
foreach (RecipeLine recipeLines in Model.RecipeLines)
{
<div class="row">
<div class="large-12 columns">
#recipeLines.Quantity #recipeLines.Measurement.MeasurementEn
#recipeLines.Ingredient.IngredientNameEn
</div>
</div>
}
}
}
(I printed the RecipeID at the end of each recipeLine to show that each recipe is repeating out Recipe Lines for RecipeID = 1 and not their Lines related to their own RecipeID. I'm a newbie to this stuff, I'm assuming that somewhere I should be telling the Recipe Lines about the RecipeID they should be looping for????
Here is the result I'm getting:
In your Recipie model you have have a List<RecipieLine> property which one would assume is to maintain one or more RecipieLine model objects. In your RecipieLineViewModel you have two separate IEnumerable collections exposing your Recipie and RecipieLine objects.
In your actual view, you are iterating over your Recipie collection:
#foreach (Recipe recipe in Model.Recipes)
Looks good, however, the following line is your issue:
foreach (RecipeLine recipeLines in Model.RecipeLines)
This enumerates over the RecipieLine model objects stored in your RecipieLineViewModel RecipieLine collection, however, it currently has no way of knowing which Recipie you are currently enumerating in your outer foreach.
You either want to provide a where LINQ clause of some sort using the data available to you from the current Recipie object enumeration, or alter the inner foreach to use the current Recipie enumeration rather than the Model.
Update
For completeness, here is an example of how to use the current Recipe object enumeration to access its associated RecipieLines:
#forech (var recipie in Model.Recipies)
{
<div>#recipe.RecipeName</div>
<div>#recipe.RecipeInstructions</div>
foreach (var recipieLine in recipie.RecipieLines)
{
<div class="row">
<div class="large-12 columns">
// Do something with recipieLine here
</div>
</div>
}
}
The above would be my preferred method as it is more efficient that performing a LINQ query each enumeration, and removes the IEnumerable<RecipieLine> from your ViewModel which is effectively duplicate code.
Add a where Linq clause to foreach.
#foreach (Recipe recipe in Model.Recipes)
{
<div>#recipe.RecipeName</div>
<div>#recipe.RecipeInstructions</div>
foreach (RecipeLine recipeLines in Model.RecipeLines.Where(rl => rl.RecipeID == recipe.RecipeID))
{
Upd:
Also you can definently include RecipeLine stuff in Recipes and you won't need RecipeLine Collection at all! Just loop through recipe.RecipeLines
Something like this:
viewModel.Recipes = db.Recipes.Include("RecipeLine").Include("RecipeLine.Measurement").
.Include("RecipeLine.Ingredient");

Categories