View Database Columns via Checkbox WebFrom and Cookies - asp.net-mvc-3

I am using the telerik MVC template and have a database that has a huge number of columns and the telerik grid does not have a horizontal scroll bar, so I created checkboxes for the user to select exactly what columns they want to view. It works well enough in that when I first go to the page it shows the checkboxes at top with the Apply button and the grid view underneath. Because nothing has been submitted from the WebForm, the grid view shows all the columns. Before adding the cookies, the user only had to press apply once for only those columns to appear. However, if the user then tried to sort or filter one of these columns, it would revert back to showing all of the columns. So, I created a cookie to store the selected information. Unfortunately, this only helped with the selection of the first filter. If a second filter is used, it would, again, show all of the columns instead of just the ones selected. Furthermore, the user now has to press apply twice for their selections to show properly on the grid view. Here is a brief explanation of how I have everything coded:
Index View
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm("Index", "Order"))
{ %>
<p>
<%= Html.CheckBox("osurr", true, "Ad Number")%>Ad Number //I set this and a few other columns to default to true
<%= Html.CheckBox("csurr", false, "Customer Number")%>Customer Number
<%= Html.CheckBox("rhosurr", false, "RHO Number")%>RHO Number
<%= Html.CheckBox("lockid", false, "Lock ID")%>Lock ID
//And several more
</p>
<input type="submit" value="Apply" />
<% } %>
<%
Html.Telerik().Grid(Model)
.Name("Grid")
.Columns(columns =>
{
columns.Template(o =>
{
%>
<%=Html.ActionLink("Detail", "Edit", new { id = o.osurr })%>
<%
}).Width(25);
if (Request.Cookies["DBCols"]["csurr"] != null)
{
if (Request.Cookies["DBCols"].Values["csurr"].Equals("True")) { columns.Bound(o => o.csurr).Title("Cust. No."); }
}
if (Request.Cookies["DBCols"]["rhosurr"] != null)
{
if (Request.Cookies["DBCols"].Values["rhosurr"].Equals("True")) { columns.Bound(o => o.rhosurr).Title("RHO No."); }
}
if (Request.Cookies["DBCols"]["lockid"] != null)
{
if (Request.Cookies["DBCols"].Values["lockid"].Equals("True")) { columns.Bound(o => o.lockid).Title("Lock ID"); }
}
//And again, several more.
})
.Groupable(grouping => grouping.Enabled(true))
.Resizable(resizing => resizing.Columns(true))
.Filterable(filter => filter.Enabled(true))
.Sortable(sorting => sorting.Enabled(true))
.Pageable(paging => paging.Enabled(true).PageSize(25))
.Render();
%>
</asp:Content>
Controller
public ActionResult Index(bool? csurr, bool? rhosurr, bool? lockid /* And Several More */)
{
ViewData["csurr"] = csurr ?? true;
ViewData["rhosurr"] = rhosurr ?? true;
ViewData["lockid"] = lockid ?? true;
if ((bool)ViewData["csurr"]) { DBCols.Values["csurr"] = (ViewData["csurr"].ToString());
}
else { DBCols.Values["csurr"] = "False"; }
if ((bool)ViewData["rhosurr"]) { DBCols.Values["rhosurr"] = (ViewData["rhosurr"].ToString()); }
else { DBCols.Values["rhosurr"] = "False"; }
if ((bool)ViewData["lockid"]) { DBCols.Values["lockid"] = (ViewData["lockid"].ToString()); }
else { DBCols.Values["lockid"] = "False"; }
//And Several more
var db = new MillieOrderDB();
var listView = from m in db.vw_cadords
orderby m.createstamp descending
select m;
return View(listView);
}
I am working just in the Index ActionResult for now to keep things in one place while I figure out how to get this all to work. Anyone have any ideas why I am having to press apply twice, why I can not use more than one filter, and how to avoid this?

It turns out that the reason I had to hit apply twice and why when applying more than one filter caused issues was because I had everything in the Index ActionResult. Once I moved all the form data to its own ActionResult and then did RedirecttoAction("Index"), everything worked fine!

Related

Kendo Grid: Toolbar template issue

I have a grid that lists Road information and want a Toolbar Template that will allow me to filter the roads by choosing a Concession from a DropDownList. Something like this
My code:
CSHTML
<div id="datagrid">
#(Html.Kendo().Grid<SustIMS.Models.RoadModel>()
.Name("datagrid_Roads")
.Columns(columns =>
{
columns.Bound(r => r.RoadCode).Title(ViewBag.lblCode).Width(140);
columns.Bound(r => r.RoadType).Title(ViewBag.RoadType).Width(140);
columns.Bound(r => r.RoadMediumDescription).Title(ViewBag.lblDescription);
columns.Bound(r => r.ConcessionCode).Title("CCode").Hidden();
columns.Bound(r => r.ConcessionMediumDescription).Hidden().Title(ViewBag.Concession);
})
.ToolBar(toolbar =>
{
toolbar.Template(#<text>
<div class="toolbar">
<label class="category-label" for="category">Concessão:</label>
#(Html.Kendo().DropDownList()
.Name("concessions")
.OptionLabel("All")
.DataTextField("ConcessionMediumDescription")
.DataValueField("CCode")
.AutoBind(false)
.Events(e => e.Change("concessionChange"))
.DataSource(ds =>
{
ds.Read("ConcessionFiltering", "MasterData");
})
)
</div>
</text>);
})
.HtmlAttributes(new { style = "height: 534px;" })
...
)
)
</div>
<script type="text/javascript">
function concessionChange() {
var value = this.value(),
grid = $("#datagrid_Roads").data("kendoGrid");
if (value) {
grid.dataSource.filter({ field: "ConcessionMediumDescription", operator: "eq", value: value });
} else {
grid.dataSource.filter({});
}
}
Controller
public ActionResult ConcessionFiltering()
{
ConcessionModel cm = new ConcessionModel();
var aux = cm.getConcessions();
return Json(aux.concessions.Select(c => c.concession.mediumDescription).Distinct(), JsonRequestBehavior.AllowGet);
}
This is the current result:
The list is filled with the word "undefined" 16 times, which is the number of concessions I currently have. When I select one of the undefined options, it shows the actual name of the concession, refreshes the grid but doesn't filter it.
I want the list to show the concession names and to filter the grid by concession as I select one of them. What am I missing?
change this
return Json(aux.concessions.Select(c => c.concession.mediumDescription).Distinct(), hJsonRequestBehavior.AllowGet);
to
return Json(aux.concessions.Select(c => new ConcessionModel { Description = c.concession.mediumDescription }).Distinct(), JsonRequestBehavior.AllowGet);
First, double check what Json you are returning from the controller method. It looks like your ConcessionMediumDescriptions may have no data in them.
Second, it looks like, in your controller, that you are returning a list of "ConcessionMediumDescription" data objects.
I am guessing it looks like this...
{ConcessionMediumDescription: {
CCode: 'mycode',
...
}
}
You may consider returning a title field as a part of this Json and to use that for the text field of your dropdown. This is just me guessing from what you are returning in that controller.
Ideal Json would be somting like this...
[{
{{id: 'id1'},{text: 'text1'}},
{{id: 'id2'},{text: 'text2'}}
}]
And you defind your dropdown as such.
.DataTextField("text")
.DataValueField("id")
You have to do json return line like this.
return Json(aux.concessions.Select(c => new { Value = c.concession.DATAVALUE, Text = c.concession.DATATEXT }), JsonRequestBehavior.AllowGet);
Just change DATAVALUE and DATATEXT

How to pass an object from a View to a Partial View within a popup window?

I have a view containing a Telerik grid:
Index.cshtml
#(Html.Telerik().Grid(Model)
.Name("Grid")
.DataKeys(keys => keys.Add(c => c.CustomerID))
.ToolBar(toolBar => toolBar.Template(
#<text>
<button id="feedback-open-button" title="Add Customer" class="t-button t-state-default">Add</button>
</text>))
.Columns(columns =>
{
columns.AutoGenerate(column =>
{
//customize autogenereted column's settings
column.Width = "150px";
if (column.Member == "CustomerID")
column.Visible = false;
});
columns.Command(commands => commands
.Custom("editCustomer")
.Text("Edit")
.DataRouteValues(route => route.Add(o => o.CustomerID).RouteKey("CustomerID"))
.Ajax(true)
.Action("EditCustomer", "Grid"))
.HtmlAttributes(new { style = "text-align: center" })
.Width(150);
})
)
I want to add/edit records to this grid using a popup. I have used a Telerik Window, in which I have opened another view as Partial View to add/edit records. This is the code for the window and how I am opening it as a popup for "ADD functionality".
Index.cshtml
#{ Html.Telerik().Window()
.Name("Window")
.Title("Add / Edit Customer")
.Content(#<text>
#Html.Partial("AddEditCustomer", new Customer());
</text>)
.Width(400)
.Draggable(true)
.Modal(true)
.Visible(false)
.Render();
}
#{ Html.Telerik().ScriptRegistrar()
.OnDocumentReady(#<text>
// open the initially hidden window when the button is clicked
$('#feedback-open-button')
.click(function(e) {
e.preventDefault();
$('#Window').data('tWindow').center().open();
});
</text>);
}
I have tried to use the same window for edit. But I am having problem in passing the customer object to the partial view within the window.
CustomerController.cs
public JsonResult EditCustomer(int CustomerID)
{
var model = CustomerModel._CustomerCollection.FirstOrDefault(o => o.CustomerID == CustomerID);
return Json(new { customer = model });
}
Index.cshtml
<script type="text/javascript">
function onComplete(e) {
if (e.name == "editCustomer") {
var detailWindow = $("#Window").data("tWindow");
var customer = e.response.customer;
detailWindow.center().open();
}
}
</script>
How can I pass this "customer" object to the partial view inside the popup window?
The way we deal with this where I work is by creating an empty div in the Telerik window. The "edit" link is an AJAX link which uses the window's div as its target. The link calls the controller method of your choice, and from there rather than returning Json, just return the PartialView you want displayed. The benefit of this approach is you use the customer object just like you would for any normal view/partial.
After the AJAX completes, open the Telerik window and the content should be there.

Linq MVC 2 TryUpdateModel nullable bool

I have been having an issue with updating a nullable bool value using TryUpdateModel. I have a template created to handle the values as so:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.Boolean?>" %>
<% if (ViewData.ModelMetadata.IsNullableValueType) { %>
<%= Html.DropDownListFor(model => model, new SelectListItem[] { new SelectListItem() { Text = "", Value = "null"},new SelectListItem() { Text = "Yes", Value = "true"}, new SelectListItem() { Text = "No", Value = "false" }})%>
<% } else { %>
<%= Html.CheckBoxFor(model => model.Value)%>
<% } %>
My View looks like this:
<%=Html.EditorFor(model => model.TestField) %> //which looks/acts correctly
The SQL Server Database types are also defined correctly as a nullable bit.
My Code is straight forward:
var so = new SomeObject();
if (ModelState.IsValid)
{
//gets to here
if (TryUpdateModel(so))
{
//never gets here
}
}
The Error reported for ModelState on that field is: "The value 'null' is not valid for TestField."
This seems pretty straight forward, but I wasn't able to find anything on this. Any help would be greatly appreciated.
Cheers,
Brian
Since nobody has answered my question, I will put my workaround up. It's not super elegant, but it works. If I wanted it to be pretty, it'd be in a pink font. ;)
Basically I had to load "so" (someObject) manually using the form Collection like so...
var so = new SomeObject();
if (ModelState.IsValid)
{
so.WasItFound = StringToNullBool(form["WasItFound"]);
so.WhereWasItFound = form["WhereWasItFound"];
//fill in the rest of the properties using the form Collection...
}
private bool? StringToNullBool(string s)
{
if (s != "null")
return Convert.ToBoolean(s);
else
return null;
}

Bound column to a list and loop...Is it possible at all?

I'm a novice Telerik Grid user and was wondering if it is a possibility to use Telerik Grid such that I bound one column to a string array and then somehow loop through it to show the array items as list.
StoreViewModel:(One store can have multiple displays)
public string Name { get; set; }
public string[] StoreDisplays { get; set; }
Controller:
private IQueryable<StoreViewModel> GetRetailers()
{
var stores = from sg in db.Store
select new RetailerViewModel
{
Name = sg.sg_Name,
Name = sg.sg_Name,
StoreDisplays = ( from ca in db.Categories.Where(item => item.c_ParentId == null)
join sd in db.StoreDisplays.Where(item => item.sd_StoreGroupId == sg.sg_Id)
on ca.c_Id equals sd.sd_CategoryId into gj
from subpet in gj.DefaultIfEmpty()
select (ca.c_Name)).ToArray<string>()
};
return stores;
}
Index.aspx
<%= Html.Telerik().Grid<StoreLocatorBackOffice.Models.RetailerViewModel>(Model) <br/>
.Name("Grid")
.Columns(columns =>
{
columns.Bound(sg => sg.Name)
columns.Bound(sg => sg.StoreDisplays);
})
.DataBinding(dataBinding => dataBinding
.Ajax()
.Select("_Index", "Retailer", true)
)
.Scrollable(scrolling => scrolling.Enabled(false))
.Sortable(sorting => sorting
.OrderBy(sortOrder => sortOrder.Add(p => p.Name).Ascending()))
.Pageable(settings => settings.PageSize((int)ViewData["pageSize"]))
.Filterable(filtering => filtering.Enabled(true))
.Footer(true)
%>
Currently it Displays like this.
Name Store Display
Store#1 Display#1Display#2Display#6
Store#2 Display#3Display#9
And want to some how show it as follows.
Name Store Display
Store#1 Display#1
Display#2
Display#6
Store#2 Display#3
Display#9
Instead of:
columns.Bound(sg => sg.StoreDisplays);
You should bind using a template. That template can be whatever you want, (even another grid).
Here's a template that will put an image in:
columns.Template(c => {
%>
<img
alt="<%= c.CustomerID %>"
src="<%= Url.Content("~/Content/Grid/Customers/" + c.CustomerID + ".jpg") %>"
/>
<%
});
Changing that template to display a list should be simple.
Look here for more info.
I would use HTML tags in to make data to spread vertically
For example
StoreDisplays = "
<ul>
<li>Display#1</li>
<li>Display#2</li>
<li>Display#3</li>
</ul>";
.Columns(columns =>
{
columns.Bound(o => o.StoreDisplays).ClientTemplate("<#= StoreDisplays #>");
}

Telerik MVC Grid. How to bind to a nullable column

I have a grid with a column which contains a nullable data
Html.Telerik().Grid(Model)
.Columns(columns =>
{
columns.Add(o => o.Foo);
}
That works, but shows something like [object Object] on the client. Supposedly it should show Foo.Name, I tried to override Foo's ToString() - didn't work, I tried to change that into columns.Add(o => o.Foo.Name);, but then it doesn't want to render the entire grid.
I tried to use columns.Bound(o => o.Foo.Name); - no results. BTW, what's the difference between Add() and Bound() ?
I would use the Template of the column to do this. Here is some code
Html.Telerik().Grid(Model)
.Columns(columns =>
{
columns.Add(o => o.Foo).Template(o =>
{
%>
<%= o.Foo != null ? o.Foo.Name : "" %>
<%
})
.ClientTemplate("<#= Foo != null ? Foo.Name : '' #>");
}
Assuming that Model is a collection of RowData instances, you could add a getter FooName to the RowData class:
public class RowData
{
public string FooName
{
get { return Foo == null ? null :: Foo.Name; }
}
}
Then you can bind to FooName:
Html.Telerik().Grid(Model)
.Columns(columns =>
{
columns.Bound(o => o.FooName);
}
I can't test it at the moment. Possibly you need a setter as well. It doesn't need to do anything.
And I have no idea what Add() does. I've never used it.

Resources