Hide column in telerik Grid but need to get it - asp.net-mvc

let's say i have an order and order details.
the view will contains the order fields, and a Telerik Grid for the details
i always maintain a reference of the Order in the session.
Session["Order"] = order;
and when the user add an order detail to the grid, I'm saving it in the Order reference.
public ActionResult Grid_AddDetail(OrderDetail orderDetail) {
(Session["order"] as Order).Details.Add(orderDetail);
}
the problem is when i need to update the row, how can i determine which detail in
Order Details has been updated?
public ActionResult Grid_UpdateDetail(OrderDetail orderDetail) {
///how will i compare the element in the details, with the orderDetail?
(Session["order"] as Order).Details.IndexOf(orderDetail) = orderDetail;
}
the problem can be solved by adding a serial number column, and compare the incoming detail with the existed on in my reference, by overriding the Equal:
public overrid Equal(object obj){
return (obj as OrderDetail).Serial == this.Serial;
}
but i want the serial number column to be invisible, but if i do so, it will not be presented in the incomming detail.

If you just want to make the column invisible, I think this should help:
AutoGenerateColumns="false"
That will force you to generate the columns displaying the information, rather than the gridview automatically creating them for you. So now you will need to do something like this to get the order to display
<asp:TemplateField>
<ItemTemplate>
<b><%# DataBinder.Eval(Container.DataItem, "Order") %>:</b>
</ItemTemplate>
</asp:TemplateField>
EDIT:
To access the Serial Number when it is not visible, you will need to use DataKeys:
orderDetail.DataKeyNames = new string[] { "Serial" };

what I did is:
added a column called Serial
made the column width set to 0.
columns.Bound(m => m.Serial).Title("").Sortable(false).Width(0);
and it will be presented in (insert, update)
but the problem in delete is to make him (as Brett said) as a Datakey.
public ActionResult Grid_AddDetail(OrderDetail orderDetail) {
if ((Session["order"] as Order).Details.Count != 0)
item.Serial= (Session["order"] as Order).Details.Max(d => d.Serial) + 1;
(Session["order"] as Order).Details.Add(orderDetail);
}
public ActionResult Grid_UpdateDetail(OrderDetail orderDetail) {
///order detail now contains the serial number.
(Session["order"] as Order).Details.IndexOf(orderDetail) = orderDetail;
}

Related

Select from a list passed to view in .NET MVC

Before I had this:
public ActionResult ShowSong(int id)
{
return view(db.PublishedSongs.Where(x => x.Id == id).FirstOrDefault());
}
and in my view:
#model MusicSite.Models.PublishedSong
<h2>#Model.SongName</h2>
#Html.ImageFor(x => x.CoverImageBytes, #Model.SongName + " Image", new { #class = "big-cover-image" })
This worked fine for just retrieving one item from DB and showing on view.
However now, I need to also pass a list to my view, because I want to show all of the items in model and just the select item that was passed through action method, how do I do this?
If I pass return View(db.PublishedSongs); to view then I no longer know which id to get to show just that one item.
As I am not that much good in .NET MVC but I will try to answer according to spring MVC knowledge.
The rough idea is to pass list to view as you are mentioned and along with it pass the id that you want to select using ViewBag. Now in view iterate over the list, while iteration check whether id come from iteration is equal to id that you passed in ViewBag.
So in controller :
public ActionResult ShowSong(int id)
{
ViewBag.SelectId = id;
return view(db.PublishedSongs);
}
In View :
(Loop over the db.PublishedSongs)
{
if(PublishedSong.id=#ViewBag.SelectId)
{
//select current PublishedSong
}
else
{
//otherwise
}
}

Nested bean : a collection inside an object

I got a simple POJO class that i wish to display / update in a form
Using the BeanItem class and the binding of component data, i was able to quickly display the first attributes of may data class. However i've hit a wall for tow related attributes :
my class posses a set of available status, as a list of object 'AppStatus'. it also possess a current status, that is one of the status in the 'available' list.
I would like to display the list in the form as a combobox, with the current status selected.
I'we managed to associate the 'available' attribute with a combobox, but i can't seem to be able to fill this combobox when setting the data source (method setItemDataSource). How do i get the avalaible status list and the current status from my Item ?
I could always use a workaround and add a parameter to the method to get the source objet in addition to the BeanItem, but i would prefer to avoid this if the Item properties can give me my attribute.
Regards
Edit : shortened exemple, with code from Eric R.
class Status {
String id;
Sting label
+ setter /getter
}
class App {
String AppId;
String AppLabel
ArrayList<Status> availablestatus;
Status currentStatus
+setter/getter
}
in the form extension, in the createField of the fieldfactory i added the following lines
if ("status".equals(propertyId)) {
// create the combobox
ComboBox status = new ComboBox(
texts.getString("application.label.status"));
status.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
status.setItemCaptionPropertyId("label");
status.setImmediate(true);
status.setNullSelectionAllowed(false);
IndexedContainer container = new IndexedContainer(
(Collection<ApplicationStatus>) item.getItemProperty(
"availableStatus").getValue());
status.setContainerDataSource(container);
status.setPropertyDataSource(item.getItemProperty("currentStatus"));
return status;
} else...
this didn't work, i do get a combobox, with the correct number of lines, but all empties.
i tried to use a beanContainer instead of a IndexedContainer
BeanContainer<String, ApplicationStatus> container =
new BeanContainer<String, ApplicationStatus>(ApplicationStatus.class);
container.addAll((Collection<ApplicationStatus>) item
.getItemProperty("availableStatus").
container.setBeanIdProperty("id");
the result is slightly better, since i do have the available values in the combobox.
only the currentValue is not selected...
I also tried to use a nestedbean property to get the id of the currentstatus, but the result is still not valid... i get a combobox, with the correct value selected, but i can not see others values anymore, since the combobox is readonly ?(even with setReadOnly(false);)
I suggest my way to resolve this. I don't think this is the nicest way, but it's works.
The beanItem class contains all you need.
I did the following in a simple project and it's work verry well :
ComboBox status = new ComboBox("ComboBox");
status.setImmediate(true);
status.setNullSelectionAllowed(false);
for(Status st : (Collection<Status>)item.getItemProperty("availableStatus").getValue()) {
status.addItem(st);
status.setItemCaption(st, st.getLabel());
}
status.setPropertyDataSource(item.getItemProperty("currentStatus"));
Hope it's works.
Regards Éric
From the vaadin demo site you can get this sample that show how to fill a combobox with countries. You could do the same i would guess (not sure I understand your problem 100%):
myForm.setFormFieldFactory(new MyFormFieldFactory ());
private class MyFormFieldFactory extends DefaultFieldFactory {
final ComboBox countries = new ComboBox("Country");
public MyFormFieldFactory () {
countries.setWidth(COMMON_FIELD_WIDTH);
countries.setContainerDataSource(ExampleUtil.getISO3166Container());
countries
.setItemCaptionPropertyId(ExampleUtil.iso3166_PROPERTY_NAME);
countries.setItemIconPropertyId(ExampleUtil.iso3166_PROPERTY_FLAG);
countries.setFilteringMode(ComboBox.FILTERINGMODE_STARTSWITH);
}
#Override
public Field createField(Item item, Object propertyId,
Component uiContext) {
Field f = (Field)item;
if ("countryCode".equals(propertyId)) {
// filtering ComboBox w/ country names
return countries;
}
return f;
}
}

ASP.NET MVC: Keeping last page state

Here's the situation: i have a SearchPage where an user can make a complex search. Nothing really unusual. After the results are displayed, the user can select one of them and move to another Page (Like a Master/Detail).
I have a breacrumb which holds the places where the user has been and it can have more than 4 levels (Like Main -> 2Page -> 3Page -> 4Page -> NPage). What i want is to maintain the state of each control on my complex search page, if the user uses the breacrumb to navigate backwards, since i don't want them to manually set all those search filters again.
So far, i've been using javascript:history.back(), but since i can have multiple levels on my breadcrumb, this hasn't been very useful. I was thinking about using OutputCache to do it, but i don't know how i would proceed.
UPDATE
I've just talked to a co-worker and he told me that some of our combobox (dropdownlist) are dynamically generated. So if the user select one item on the first combobox, the second will be filled with data related to the first selection.
OutputCache would cache the results for every user. Why don't you try to store the information in a cookie with page url and filter information. Each time an action is executed, read the cookie and populate the model (custom model for search) with those values found (if they match the page url, action in this situation). Pass the model to the view and let it repopulate the search criteria text boxes and check boxes.
UPDATE:
When a user fills in the search filter text boxes, you are passing that information back to a controller somehow. Probably as some kind of a strongly typed object.
Let's say your users get to enter the following information:
- Criteria
- StartDate
- EndDate
There is a model called SearchCriteria defined as:
public class SearchCriteria
{
public string Criteria { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
Your action could look something like this:
[HttpGet]
public ViewResult Search()
{
SearchCriteria criteria = new SearchCriteria();
if (Request.Cookies["SearchCriteria"] != null)
{
HttpCookie cookie = Request.Cookies["SearchCriteria"];
criteria.Criteria = cookie.Values["Criteria"];
criteria.StartDate = cookie.Values["StartDate"] ?? null;
criteria.EndDate = cookie.Values["EndDate"] ?? null;
}
return View(criteria);
}
[HttpPost]
public ActionResult Search(SearchCriteria criteria)
{
// At this point save the data into cookie
HttpCookie cookie;
if (Request.Cookies["SearchCriteria"] != null)
{
cookie = Request.Cookies["SearchCriteria"];
cookie.Values.Clear();
}
else
{
cookie = new HttpCookie("SearchCriteria");
}
cookie.Values.Add("Criteria", criteria.Criteria);
if (criteria.StartDate.HasValue)
{
cookie.Values.Add("StartDate", criteria.StartDate.Value.ToString("yyyy-mm-dd"));
}
if (criteria.EndDate.HasValue)
{
cookie.Values.Add("EndDate", criteria.EndDate.Value.ToString("yyyy-mm-dd"));
}
// Do something with the criteria that user posted
return View();
}
This is some kind of a solution. Please understand that I did not test this and I wrote it from top of my head. It is meant to give you an idea just how you might solve this problem. You should probably also add Action to SearchCriteria so that you can check whether this is an appropriate action where you would read the cookie. Also, reading and writing a cookie should be moved into a separate method so that you can read it from other actions.
Hope this helps,
Huske

ASP.NET MVC: Caching combobox

Is it possible to cash drop down list?
I'm using a Telerik MVC Window, ComboBox, and the contents of the window (including ComboBox) is being returned with a partial view. Contents of the partial view depends on the list of parameters, but on the every div in this window there is a combo box contents of which is usually unchanged and it contains ~2000 records.
i'm thinking about returning ViewData["ComboContent"] using separate controller with cashing before returning the window itself, but may be there is a better way...
TIA
updated (my controller code):
[AcceptVerbs("GET")]
[OutputCache(Duration = int.MaxValue, VaryByParam = "id")] //Some custom param??
public ActionResult LoadTimeOffset(int id)
{
String error;
IEnumerable<MyModel> model = repo.GetSomeVariableStuff(id, 10, out error); //always varies
ViewData["ComboList"] = new SelectList(repo.GetComboitems(id), "Key", "Value", -1); //changes only on id
if (model.Count() > 0)
{
return PartialView("Partial", model);
}
return Content(error);
}
Cache the data instead of caching the drop-down.
So, instead of putting the SelectList into the ViewData, put the contents for it:
if (HttpContext.Current.Cache["ComboList"] == null)
{
HttpContext.Current.Cache["ComboList"] = repo.GetComboitems(id); //use Add instead so that you can specify the cache duration.
}
ViewData["ComboList"] = HttpContext.Current.Cache["ComboList"]; //take from cache.
Note, code is not accurate, but it is an example only.
Then, in your view, render the combo.
I hope this helps.

Update a row in ASP.NET and MVC LINQ to SQL

I have a simple row that has 4 columns:
{ [Primary Key Int]RowID, [text]Title, [text]Text, [datetime]Date }
I would like to allow the user to edit this row on a simple page that has a form with the fields "Title" and "Text".
There is a hidden field to store the RowID.
When the user posts this form to my controller action, I want it to update the row's Title and Text, and keep the Date the same. I don't want to have to explicitly include a hidden field for the Date in the form page.
Here is my action:
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(Row myRow)
{
RowRepository.SaveRow(myRow)
return View("Success");
}
RowRepository:
public void SaveRow(Row myRow)
{
db.MyRows.Attach(myRow);
db.Refresh(RefreshMode.KeepCurrentValues, myRow);
db.SubmitChanges();
}
This dosen't keep the "Date" value already in the row and tries to insert a value that throws an timespan exception.
How can I just tell it to keep the old values?
I tried doing RefreshMode.KeepChanges and nothing.
I'm not in a position to test this at the moment but try making the datetime column nullable and then ensure that the datetime passed into SaveRow has a null value.
Try
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow([Bind(Exclude="Date")] Row myRow) {
RowRepository.SaveRow(myRow)
return View("Success");
}
Update
Try this approach, where there is no 'Date' field on your page
[AcceptVerbs(HttpVerb.Post)]
public ActionResult EditRow(int RowID) {
Row myRow = RowRepository.GetRow(RowID);
UpdateModel(myRow);
RowRepository.Save();
return View("Success");
}
In your repository
public void Save() {
db.SubmitChanges();
}
This will only save the changes made to 'myRow'
You will have add a method in the partial class / override the code it build.
The class Table does implement "INotifyPropertyChanging|ed" which is used to track which column has been changed.
You can hack it and reset the value "this.PropertyChanged".
But what I do at work is a stupid READ-APPLY-WRITE approach (and I am using WebForm).
public void SaveRow(Row myRow)
{
var obj=db.MyRows.Where(c=>c.id==myRow.id).First();
obj.a=myRow.a;
obj.b=myRow.b;
db.SubmitChanges();
}
You can do a bit simpler.
public void SaveRow(Row myRow)
{
db.MyRows.Attach(new Row(){
Id=myRow.Id,
Title=myRow.Title,
Text=myRow.Text,
});
db.SubmitChanges();
}
PS. I am new to LINQ to SQL. Please let me know if there is a smarter way to do it.
Ok, I set it to nullable and it keeps overwriting the database as a null value. I guess its impossible to do this since technically null is a valid value for the column and if I pass an object to the function, the empty values must contain something or be null.
So I would have to explicitly state to take the database value for that column
Thanks

Resources