Foreach ViewBag data gives 'object' does not contain a definition for 'var'

I have a controller that builds a query from Linq to Sql to go to the ViewBag.products object. The problem is that I cannot use the foreach loop, as I expected that I could.

Here is the code in the controller creating the request using the .ToList () function.

var products = from bundles in db.Bundle join bProducts in db.BundleProducts on bundles.bundleId equals bProducts.bundleID join product in db.Products on bProducts.productID equals product.productID join images in db.Images on product.productID equals images.productID where bundles.bundleInactiveDate > DateTime.Now select new { product.productName, product.productExcerpt, images.imageID, images.imageURL }; ViewBag.products = products.ToList(); 

Since I am using a different model for index.cshtml for other necessary elements, I thought that a simple Html.Partial could be used to include a viewbag loop. I tried it with the same result using and without using the partial and simple use of foreach in index.cshtml. Below is a snippet that includes a partial:

 <div id="bundle_products"> <!--build out individual product icons/descriptions here---> @Html.Partial("_homeBundle") </div> 

In my _homeBundle.cshtml file, I have the following:

 @foreach (var item in ViewBag.products) { @item } 

I get ViewBag data, but I get the whole list as output as such:

 { productName = Awesomenes Game, productExcerpt = <b>Awesome game dude!</b>, imageID = 13, imageURL = HotWallpapers.me - 008.jpg }{ productName = RPG Strategy Game, productExcerpt = <i>Test product excerpt</i>, imageID = 14, imageURL = HotWallpapers.me - 014.jpg } 

What I thought I could do is:

 @foreach(var item in ViewBag.Products) { @item.productName } 

As you can see, in the output is productName = Awesomenes Game. However, I get the error "object" does not contain a definition for "productName" when I try to do this.

How can I output each โ€œfieldโ€ so as to say individually in my loop so that I can apply the correct HTML tags and style needed for my page?

I need to make a completely new ViewModel for this, and then create a display template as indicated here: 'object' does not contain a definition for 'X'

Or can I do what I'm trying here?

***** ***** UPDATE

In my controller, I now have the following:

  var bundle = db.Bundle.Where(a => a.bundleInactiveDate > DateTime.Now); var products = from bundles in db.Bundle join bProducts in db.BundleProducts on bundles.bundleId equals bProducts.bundleID join product in db.Products on bProducts.productID equals product.productID join images in db.Images on product.productID equals images.productID where bundles.bundleInactiveDate > DateTime.Now select new { product.productName, product.productExcerpt, images.imageID, images.imageURL }; var bundleContainer = new FullBundleModel(); bundleContainer.bundleItems = bundle; return View(bundleContainer); 

I have a model, FullBundleModel

 using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace JustBundleIt.Models { public class FullBundleModel { public IQueryable<Bundles> bundleItems { get; set; } public IQueryable<Images> imageItems { get; set; } } } 

and now my view has

 @model IEnumerable<JustBundleIt.Models.FullBundleModel> @foreach (var item in Model) { <div class="hp_bundle"> <h3>@Html.Display(item.bundleName)</h3> </div> } 

If I remove the IEnumerable from the model reference, the foreach error excludes that there is no public definition for the counter.

In @ Html.Display (item.bundleName), he makes a mistake that the model does not have a definition for bundleName. If I try to execute

 @foreach(var item in Model.bundleItems) 

I get an error that bundleItems are not defined in the model.

So, what did I not connect correctly to the combined model?

+4
source share
2 answers

Why not create a new model that contains all the data you need?

Example 1:

 public class ContainerModel { public IQueryable<T> modelOne; public IQueryable<T> modelTwo; } 

This will allow you to access any of your queries in Razor:

 @model SomeNamespace.ContainerModel @foreach (var item in Model.modelOne) { //Do stuff } 

I personally avoid using ViewBag and save everything I need in such models, because it is NOT dynamic and forces everything to be strictly typed. I also believe that this gives you a well-defined structure / intention.

And just for the sake of clarity:

 public ViewResult Index() { var queryOne = from p in db.tableOne select p; var queryTwo = from p in db.tableTwo select p; var containerModel = new ContainerModel(); containerModel.modelOne = queryOne; containerModel.modelTwo = queryTwo; return View(containerModel); } 

Example two:

 public class ContainerModel { [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] //Format: MM/dd/yyyy (Date) public Nullable<DateTime> startDate { get; set; } [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")] //Format: MM/dd/yyyy (Date) public Nullable<DateTime> endDate { get; set; } public SelectList dropdown { get; set; } public IQueryable<T> modelOne { get; set; } public IQueryable<T> modelTwo { get; set; } } 

In this case, you saved 3 other elements in the model with two queries. You can use the HTML helpers to create a drop-down list in Razor:

 @Html.DropDownList("dropdown", Model.dropdown) 

And you can use the DisplayFor helper to display dates defined in your model with data annotations:

 @Html.DisplayFor(a => a.startDate) 

This is a profitable IMO because it allows you to define all the data that you want to use in your presentation and how you plan to format this data in one place. Your controller contains all the business logic, your model contains all the data / formatting, and your view refers only to the content of your page.

0
source

I need to make a completely new ViewModel in order to do this, and then create a display template, as indicated here ...

Darin's answer is that you have associated states with an important concept: Anonymous types are not intended to be used across assembly boundaries and are not available to Razor. I would add that it is rarely a good idea to disclose anonymous objects outside their immediate context.

Creating a view model specifically designed for use in view mode is almost always correct. View models can be reused in different views if you present similar data.

You do not need to create a display template, but it can be useful if you want to reuse display logic. HTML helpers can also populate a similar function to provide reusable display logic.

Having said all this, it is impossible to pass an anonymous type to a view or read members of an anonymous type. A RouteValueDictionary can take an anonymous type (even through an assembly) and read its properties. Reflection allows members to be read regardless of visibility. Although this has its uses, passing data to a view is not one of them.

Additional Information:

+2
source

Source: https://habr.com/ru/post/1434739/


All Articles