We have a table with 50 rows and want display initially only 10. Just below the table we'd like to add a "Show all" link (not a button) that allow, dynamically (or after reloading the page), to display of all the 50 rows.
What is the most straightforward way to achieve this?
Thanks.
Consider having a model composed of an int and a List<DataRow>:
public class MyDisplayViewModel
{
public int FullCount { get; set; }
public List<DataRow> Data { get; set; }
}
When populating your Data object (in your controller, for example) you can take the full count of your existing data and pass it in the FullCount property.
public ActionResult GetData(int count)
{
MyDisplayViewModel model = new MyDisplayViewModel();
//pseudocode for getting the total number of records
model.FullCount = yourDataProvider(yourDataType).Count();
//pseudocode for getting the the list of records
model.Data = yourDataProvider(yourDataType, count);
return View(model);
}
You can check then in your view if the data passed to it corresponds to all the "available" data. If not, show the link to get all the data from your database.
#{
foreach(var row in Model.Data)
{
//display your data
}
if (Model.Data.Count != Model.FullCount)
{
#Html.ActionLink("Load all", "GetData", "YourControllerName",
new { count = Model.FullCount }, null)
}
}
Of course, this suggestion is at the conceptual level. the view, for example, can implement an Ajax request, in order to get only the remaining DataRows.
Related
// Create the scoresheet
Scoresheet scoresheet = new Scoresheet();
scoresheet.tsakID = task.ID;
// Query Items to retrieve a list of tasks. Then create a scoresheet
// for each item retrieved and bind them together as foreign keys.
var Items = (from c in db.Items
where c.ID == task.ID
select c).ToList();
// Save scoresheet item to db
scoresheet.ScoresheetItems = new List<ScoresheetItem>();
System.Diagnostics.Debug.WriteLine(scoresheet.ScoresheetID);
for (int i = 0; i < Items.Count(); i++)
{
ScoresheetItem scoresheetItem = new ScoresheetItem();
scoresheetItem.ScoresheetID = scoresheet.ScoresheetID;
scoresheet.ScoresheetItems.Add(scoresheetItem);
}
db.Scoresheets.Add(scoresheet);
db.SaveChanges();
The error is on the line where I am doing scoresheetItem.ScoresheetID = scorehseet.ScoresheetID
The problem is that scoresheet.ScoresheetID is null until it is created. when it is created on the database, the value is assigned as an auto-incrementing value.
How do I get around this so that scoresheet.ScoresheetID is not null so that I can assign it to the scoresheetItem?
Here is the scoresheet model:
public class Scoresheet
{
public int ScoresheetID { get; set; }
public virtual ICollection<ScoresheetItem> ScoresheetItems { get; set; }
}
public class ScoresheetItem
{
public int ScoresheetItemID { get; set; }
public int ScoresheetItemScore { get; set; }
public Nullable<int> ScoresheetID { get; set; }
}
If ScoresheetID is an identity column then you should not be setting it in code at all when creating it. On your object you need to let EF know that is an identity column as well. If this is code first, which I'm assuming, you can either use data annotations
https://msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx
or fluent api to configure and map properties
https://msdn.microsoft.com/en-us/library/jj591617(v=vs.113).aspx
When creating child ScoresheetItem(s) you should not set the ScoresheetID either, your models should be configured for the relationship.
Here is one with modeling relationships and navigation properties.
https://msdn.microsoft.com/en-us/library/jj713564(v=vs.113).aspx
Okay, this was actually a pretty simple fault.
There is actually no need at all to set the foreign key such as I was doing right here: scoresheetItem.ScoresheetID = scorehseet.ScoresheetID
When I call scoresheet.ScoresheetItems.Add(scoresheetItem); in the code, it actually handles the foreign key for me.
I am fairly new to using LINQ and are now trying to build a LINQ question I do not quite manage to solve.
I would like to ask a question to a database, where I want to bring back single rows from a few tables, but a list of rows from other tables.
See code below too see what I am trying to do:
public DB.store store { get; set; }
public List<DB.gallery_image> images { get; set; }
public List<DB.product> products { get; set; }
public static List<Store> getStoreInfo()
{
DBDataContext db = new DBDataContext();
var _dataToGet = from _store in db.stores
select new Store
{
store = _store,
images = (from a in db.gallery_images
where a.albumID == _store.storeID
select a).ToList(),
products = (from p in db.products
where p.storeID = _store.storeID).ToList()
};
return _dataToGet.ToList();
}
So I just want one row from "store" table, but a list from "images" and "product" tables.
The code above works fine, but is slow as hell.
I don't have any problems to select data from multiple tables as long as there is only one (or none) row per table, but when it is a list I'm having problem...
If I were you I would use deferred execution rather than materializing the queries with a call to ToList. I would change the data type of images and products to IEnumerable<> instead of List<>. Then I would not call ToList in the sub-queries because this results in a roundtrip to the database, hence, depending on how many stores you have it could turn into an extremely slow query.
You should see a performance gain here...
public DB.store store { get; set; }
public IEnumerable<DB.gallery_image> images { get; set; }
public IEnumerable<DB.product> products { get; set; }
public static List<Store> getStoreInfo()
{
DBDataContext db = new DBDataContext();
var _dataToGet = from _store in db.stores
select new Store
{
store = _store,
images = (from a in db.gallery_images
where a.albumID == _store.storeID
select a),
products = (from p in db.products
where p.storeID = _store.storeID)
};
return _dataToGet.ToList();
}
I am new to ASP.NET MVC and I am stuck on a point. I am working on a classified site. My situation is, I have a lot of categories in which a user can post their ads and each ad category have different View. I have created a Controller Action like
public ActionResult PostAd(string CategoryName, string SubCategoryName)
{
if(categoryName == "Vehicle" && SubCategoryName == "Cars")
{
var model = new CarAdViewModel();
// set CarAdViewModel properties...
return View("CarAdCreateView", model);
}
else if(categoryName == "Vehicle" && SubCategoryName == "Bikes")
{
var model = new BikeAdViewModel();
// set BikeAdViewModel properties...
return View("BikeAdViewModel", model);
}
else if(categoryName == "Property" && SubCategoryName == "RentHouse")
{
var model = new RentHouseAdViewModel();
// set RentHouseAdViewModel properties...
return View("RentHouseAdViewModel", model);
}
else................... so on and so on
}
My problem is I have huge number of Categories and Sub Categories almost 60+. And if I keep on coding like above for 60+ categories and subcategories, my PostAd method is going to blast and become unmanageable.
Please tell me some best practice or pattern which can bring me out of this problem.
Unfortunately, some of what you are doing cannot be avoided. There needs to be some form of model and view selection based on category.
Use a factory pattern. Create a base class:
public abstract class BaseCategory
{
public abstract string GetViewName();
public abstract Object CreateModelFromFormData();
}
For each category, create a sub-class derived from BaseCategory and implement the abstract functions.
In your action, do the following:
public ActionResult PostAd(string categoryName, string subCategoryName)
{
BaseFactory factory;
if (categoryName == "Vehicle")
{
if (subCategoryName == "Cars")
{
factory = new CarsFactory();
}
else ...
}
else ...
return View(factory.GetViewName(), factory.CreateModelFromFormData());
}
I have a couple reasons for this schema:
I am purposefully using if/else for the factory selection. Your controller is going to be created and re-created for every action call. So pre-populating a list will constantly and needlessly create objects for categories that will not be selected. A simple if/else will be more efficient. If you want to prevent the if/else, you can put your factories in a Dictionary and select based on the categories, but that would be a lot of needless constructor actions.
I made the CreateModelFromFormData a function because I assume you'll need to copy data from the posted form data. This may require passing in data, but I left the function parameterless.
I used base/derived classes because the copying of the form data will probably need to be custom from the model being created and the form data being posted. Also, saving to persistent storage (file or database) may be category-specific as well.
It would be one of some possible solutions
public class PostAdData
{
public string CategoryName;
public string SubCategoryName;
public string ViewName;
public Type Model;
}
public class PostController : Controller
{
private readonly List<PostAdData> _theData;
public HomeController()
{
_theData = InitializeData();
}
public ActionResult PostAd(string categoryName, string subCategoryName)
{
var data = _theData.FirstOrDefault(c => c.CategoryName == categoryName && c.SubCategoryName == subCategoryName);
if (data != null)
{
var model = Activator.CreateInstance(data.Model);
return View(data.ViewName, model);
}
return View("Error");
}
[NonAction]
public List<PostAdData> InitializeData()
{
var result = new List<PostAdData>
{
new PostAdData
{
CategoryName = "Vehicle",
SubCategoryName = "Cars",
ViewName = "CarAdCreateView",
Model = typeof (CarAdViewModel)
}
};
return result;
}
}
You should make this data driven. You create a lookup table that has a compound primary key of category and subcategory. Then it has a table with View in it. Then you simply ad rows for each category/subcategory/view combination.
If you absolutely don't want a database, then you can use a simple hashset or dictionary.
var views = new Dictionary<Tuple<string,string>,string>();
views.Add(new Tuple<string,string>("Vehicle", "Cars"), "CarAdCreateView");
Then in your PostAd you just lookup the correct view.
What a beautiful solution on www.asp.net to my question, here is the link : http://forums.asp.net/t/1923868.aspx/1?ASP+NET+MVC+Conditional+ViewModel+Abstraction
Edit:
My code is :
public class AdsController : Controller
{
private readonly IAdService _adService;
public AdsController(IAdService adService)
{
_adService = adService;
}
public ActionResult PostAd(string Category, string SubCategory)
{
//Here I will call
var strategy = GetStrategy(CategoryName, SubCategoryName);
strategy.FillModel(_adService );
return View(strategy.ViewName, strategy.Model);
}
}
I'm very new to ASP.NET, but I know a little programming in Java. I want to use a ZIP code to query a database which will return a string, then use that string to query another database. I wanted to do this on the same control model. I thought it would be easy, and it sounds pretty easy.
When I created the controller, I put the model class of the first database, and, so far, I've gotten as far as querying the first database, but now that I have the string I want to query a second database through the DBEntities.
This displays an error saying:
> The model item passed into the dictionary is of type
> 'System.Collections.Generic.List`1[FinalBallot.Models.AgainCandidate]',
> but this dictionary requires a model item of type
> 'System.Collections.Generic.IEnumerable`1[FinalBallot.Models.ZipTable]'.
Is there a way to solve this in an easy way?
public class Default1Controller : Controller
{
private CandidatesDBEntities db = new CandidatesDBEntities();
public string districString = "";
//
// GET: /Default1/
public ViewResult Index(string searchString)
{
var queryZip = from s in db.ZipTables select s;
var queryCandidates = from s1 in db.AgainCandidates select s1;
double sT = 0;
//method so it doesnt display the whole db
if (String.IsNullOrEmpty(searchString))
{
queryZip = queryZip.Where(s => s.ZipL.Equals(0));
}
if (!String.IsNullOrEmpty(searchString))
{
sT = double.Parse(searchString);
queryZip = queryZip.Where(s => s.ZipL.Equals(sT));
try
{
districString = queryZip.ToList().ElementAt(0).District;
}
catch
{
}
if (!String.IsNullOrEmpty(districString))
{
queryCandidates = queryCandidates.Where(s1 => s1.District.Equals(districString));
}
}
return View(queryCandidates.ToList());
}
In your view, did you specify the model to be IEnumerable<ZipTable>? The model that you're passing to your view is IEnumerable<AgainCandidate>, so you would get an error if you specified your model as something else. You'd need to change the model in your view to be IEnumerable<AgainCandidate>.
UPDATE:
Based on your revised explanation, you can do a couple things:
1) create a "ViewModel" that has two properties for each of your collections you want to display on the page like so:
public class MyViewModel
{
IEnumerable<ZipTable> Zips { get; set; }
IEnumerable<AgainCandidate> Candidates { get; set; }
}
Instantiate that in your action method and return that as your model. This would be my preferred approach.
2) Stash your two collections in the ViewData bag in your action method:
ViewData["Zips"] = queryZip.ToList();
ViewData["Candidates"] = queryCandidates.ToList();
return View(ViewData);
You can pull this data in your view like this:
#foreach (var zip in ViewData["Zips"] as IEnumerable<ZipTable>)
{
...
}
I have an Asp.Net GridView. One of the Columns is a List, but I only want to show the Last Item in the list. How can I do this?
List<string> Column1
I am binding the Gridview to a business object:
public Class GridObject
{
List<string> Column1 { get; set; }
}
EDIT
This worked, but is it the best solution:
<%# ((List<string>)Eval("Column1"))[((List<string>)Eval("Column1")).Count - 1] %>
I would add a property to the object you are binding to, and use that property instead of the list property in your binding.
public Class GridObject
{
List<string> Column1 { get; set; }
public string Column1LastValue
{
get
{ // return Column1.Last(); if linq is available
return Column1[Column1.Count-1];
}
}
}
Edit: Adding a presentation wrapper allows you to unit test what will be displayed. You are doing a translation in the view, which is OK, but since you technically have some logic happening to translate your business object to something proper for display, you would likely want to unit test that translation. Then, any formatting you want to apply to any of your business object fields is wrapped in a testable class, rather than hidden on the untestable view. Here is a sample of how this could be done:
public class GridObjectView
{
private GridObject _gridObject;
public GridObjectView(GridObject gridObject)
{
_gridObject = gridObject;
}
public string Column1
{
get
{
return _gridObject.Column1.Last();
}
}
}
Then to do the databinding, you could do this:
List<GridObject> data = GetGridData();
grid.DataSource = data.Select(g => new GridObjectView(g));
grid.DataBind();
Your best bet is to create a template column and use an inline script to retrieve the value from the list:
<%= ((List<string>)DataBinder.Eval("Column1"))[((List<string>)DataBinder.Eval("Column1")).Count] %>
Or you could store the result in the text of a label or a literal.
Hope that helps