MVC3 WebGrid - Creating Columns Dynamically (foreach?) - asp.net-mvc-3

I want to create a WebGrid with columns based on a collection, such as List. Something like this (which obviously doesn't work):
#grid.GetHtml(
columns: grid.Columns(
#foreach (var column in Model.ListOfColumns) {
grid.Column(column.Name, column.Title);
}
)
)
Any clever ideas?

You could ViewBag it like below.
Controller:
List<WebGridColumn> columns = new List<WebGridColumn>();
columns.Add(new WebGridColumn() { ColumnName = "Id", Header = "Id" });
columns.Add(new WebGridColumn() { ColumnName = "Name", Header = "Name" });
columns.Add(new WebGridColumn() { ColumnName = "Location", Header = "Location" });
columns.Add(new WebGridColumn() { Format = (item) => { return new HtmlString(string.Format("<a href= {0}>View</a>", Url.Action("Edit", "Edit", new { Id = item.Id }))); } });
ViewBag.Columns = columns;
View:
#grid.GetHtml(tableStyle: "ui-widget ui-widget-content",
headerStyle: "ui-widget-header",
columns: ViewBag.Columns
)

Try this:
#{
List<WebGridColumn> cols = new List<WebGridColumn>();
foreach(var column in Model.ListOfColumns)
{
cols.Add(grid.Column(column.Name, column.Title));
}
}
#grid.GetHtml(
columns: cols
)

You could use helper method
public static class GridExtensions
{
public static WebGridColumn[] DynamicColumns(
this HtmlHelper htmlHelper,
WebGrid grid
)
{
var columns = new List<WebGridColumn>();
columns.Add(grid.Column("Property1", "Header", style: "record"));
columns.Add(grid.Column("Property2", "Header", style: "record"));
columns.Add(grid.Column("Actions", format: (item) => { return new HtmlString(string.Format("<a target='_blank' href= {0}>Edit </a>", "/Edit/" + item.Id) + string.Format("<a target='_blank' href= {0}> Delete</a>", "/Delete/" + item.Id)); }));
return columns.ToArray();
}
Usage:
#{
var grid = new WebGrid(Model);
}
#grid.GetHtml(columns: grid.Columns(Html.DynamicColumns(grid)))

Related

Selecting Enum items on AJAX call

I am working on action result which returns JSON data to view and then loads on textFields by AJAX call
Action:
public ActionResult loadInf(string custm)
{
int smclientbranchid = Convert.ToInt32(Session["smclientbranchid"]);
var query = (from parent in db.Customer
join child in db.CustomerAddress on parent.CustomerId equals child.CustomerId
where parent.SMClientBranchId == smclientbranchid && parent.NIC == custm
select new SalesVM
{
Indicator = parent.Indicator,
//code removed
}).ToList();
return Json(query);
}
In View:
#Html.DropDownListFor(model => model.Indicator,
new SelectList(Enum.GetValues(typeof(ColorTypes))),
"<Select>",
new { #class = "form-control", id ="Indicator" })
<script type="text/javascript">
$(document).ready(function () {
$("#btnSearchCus").click(function () {
var custm = $('#custm').val();
$.ajax({
cashe: 'false',
type: "POST",
data: { "custm": custm },
url: '#Url.Action("LoadCustomerInfo", "Sales")',
dataType: 'json', // add this line
"success": function (data) {
if (data != null) {
var vdata = data;
$("#Indicator").val(vdata[0].Indicator);
//code removed
}
}
});
});
});
</script>
I am getting data right and also loading right except the "Indicator" field, which is of type enum.
How can I select an enum list item from the data I get.
For example:
0,1,2,3 index order
You need to be setting the Value attributes against all of the option values for the select list.
Use the following for your dropdown box to select by the text representation of the value:
#Html.DropDownListFor(model => model.Indicator, Enum.GetValues(typeof(ColorTypes)).Cast<ColorTypes>().Select(x => new SelectListItem { Text = x.ToString(), Value = x.ToString() }), new { #class = "form-control", id = "Indicator" })
Or use the following for it to select by the integer value:
#Html.DropDownListFor(model => model.Indicator, Enum.GetValues(typeof(ColorTypes)).Cast<ColorTypes>().Select(x => new SelectListItem { Text = x.ToString(), Value = ((int)x).ToString() }), new { #class = "form-control", id = "Indicator" })
This will allow your .Val() jQuery code to select the correct one.
If you retrieving string variable nm (0,1,2,3...) - would be better to change the type to int and try cast your integer variable to Enum type that you have.
public ActionResult loadInf(int nm)
{
ColorTypes enumValue = (ColorTypes) nm;
.......
You can take a look about details to this article: http://www.jarloo.com/convert-an-int-or-string-to-an-enum/

cascade dropdownlist asp.net

i've two table in DB.
i want to create dropdownlist for city and corresponding area after that.this is my first cascade drodown menu in my entire life.i've tried to follow some examples.in the get action i've :
ViewBag.cities = db.cities.ToList();
ViewBag.areas = db.areas.ToList();
in the view i've:
<div class="editor-field">
#Html.DropDownListFor(model => model.city,new SelectList(ViewBag.cities as
System.Collections.IEnumerable, "city_id", "name"),
"Select City", new { id = "ddlCars" })
#Html.ValidationMessageFor(model => model.city)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.area)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.area, new
SelectList(Enumerable.Empty<SelectListItem>(), "area_id", "name"),
"Select Area", new { id = "ddlModels" })
#Html.ValidationMessageFor(model => model.area)
</div>
i've just copied a js file from a site that is
$(document).ready(function () {
$("#ddlCars").change(function () {
var idModel = $(this).val();
$.getJSON("/Post/LoadAreasByCity", { id: idModel },
function (carData) {
var select = $("#ddlModels");
select.empty();
select.append($('<option/>', {
value: 0,
text: "Select Area"
}));
$.each(carData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
});
});
$("#ddlModels").change(function () {
var idColour = $(this).val();
$.getJSON("/Home/LoadColoursByModel", { id: idColour },
function (modelData) {
var select = $("#ddlColours");
select.empty();
select.append($('<option/>', {
value: 0,
text: "Select a Colour"
}));
$.each(modelData, function (index, itemData) {
select.append($('<option/>', {
value: itemData.Value,
text: itemData.Text
}));
});
});
});
});
in my Post/LoadAreasByCity my method is:
public JsonResult LoadAreasByCity(string id)
{
PostManager pm = new PostManager();
if ( id=="") { id = "1"; }
int c_id =(int) Convert.ToInt32(id);
var areaList = pm.GetModels(c_id);
var modelData = areaList.Select(m => new SelectListItem()
{
Text = m.name,
Value = m.area_id.ToString(),
});
return Json(modelData, JsonRequestBehavior.AllowGet);
}
it propagate cities and area is correctly in the view page.but after submitting the data it gives errorin this line
#Html.DropDownListFor(model => model.city,new SelectList(ViewBag.cities as
System.Collections.IEnumerable, "city_id", "name"),"Select City", new { id =
"ddlCars" })
it says Value cannot be null.
Parameter name: items
Finally in my post action
int c_id = Convert.ToInt32(p.city);
int a_id = Convert.ToInt32(p.area);
area a = db.areas.Single(x=>x.area_id == a_id);
city c = db.cities.Single(s => s.city_id == c_id);
post.city = c.name;
post.area = a.name;
....Save to DB
what is the problem in this ..... thanks in advance
I suspect that in your POST action you have redisplayed the same view but forgot to populate the ViewBag.cities and ViewBag.areas items as you did in your GET action:
[HttpPost]
Public ActionResult Process()
{
... Save to DB
ViewBag.cities = db.cities.ToList();
ViewBag.areas = db.areas.ToList();
return View();
}

Paging/Sorting not working on web grid used in Partial View

I have a partial view where I am showing a web grid depending upon a value selected from a page.
For drop down I have used
#Html.DropDownListFor(
x => x.ItemId,
new SelectList(Model.Items, "Value", "Text"),
new {
id = "myddl",
data_url = Url.Action("Foo", "SomeController")
}
)
For drop down item select I have used
$(function() {
$('#myddl').change(function() {
var url = $(this).data('url');
var value = $(this).val();
$('#result').load(url, { value: value })
});
});
and below is my action
public ActionResult Foo(string value)
{
SomeModel model = ...
return PartialView(model);
}
everything works good, but when I try doing a paging or sorting on my webgrid which is on my partial view I am showing a new window with the web grid.
I wanted to be able to sort and page on the same page without postback
Please help
The following example works fine for me.
Model:
public class MyViewModel
{
public string Bar { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Foo(string value)
{
var model = Enumerable.Range(1, 45).Select(x => new MyViewModel
{
Bar = "bar " + value + " " + x
});
return PartialView(model);
}
}
Index.cshtml view:
<script type="text/javascript">
$(function () {
$('#myddl').change(function () {
var url = $(this).data('url');
var value = $(this).val();
$.ajax({
url: url,
type: 'GET',
cache: false,
data: { value: value },
success: function (result) {
$('#result').html(result);
}
});
});
});
</script>
#Html.DropDownList(
"id",
new[] {
new SelectListItem { Value = "val1", Text = "value 1" },
new SelectListItem { Value = "val2", Text = "value 2" },
new SelectListItem { Value = "val3", Text = "value 3" },
},
new {
id = "myddl",
data_url = Url.Action("Foo", "Home")
}
)
<div id="result">
#Html.Action("Foo")
</div>
Foo.cshtml partial:
#model IEnumerable<MyViewModel>
#{
var grid = new WebGrid(
canPage: true,
rowsPerPage: 10,
canSort: true,
ajaxUpdateContainerId: "grid"
);
grid.Bind(Model, rowCount: Model.Count());
grid.Pager(WebGridPagerModes.All);
}
#grid.GetHtml(
htmlAttributes: new { id = "grid" },
columns: grid.Columns(
grid.Column("Bar")
)
)
Notice that I have used a GET request to refresh the grid instead of POST because this way the value query string parameter selected in the dropdown is preserved for future sorting and paging.

ASP.NET MVC 3 WebGrid Sort Order Image

I am working with a WebGrid, and I would like to have an image or character like "^" "v" in the header showing the column with the sort order.
How can I do this?
This is the code of one of my Webgrids:
<div id="contenedor-gridACTIVIDAD">
#{
WebGrid gridACTIVIDAD = new WebGrid(Model.actividadDiaria, ajaxUpdateContainerId: "contenedor-gridACTIVIDAD", rowsPerPage: 20);
}
#gridACTIVIDAD.GetHtml(
fillEmptyRows: true,
alternatingRowStyle: "fila-alternativa",
headerStyle: "encabezado-grid",
footerStyle: "pie-grid",
mode: WebGridPagerModes.All,
firstText: "<<",
previousText: "<",
nextText: ">",
lastText: ">>",
columns: new[] {
gridACTIVIDAD.Column("contrato", header: "Contrato"),
gridACTIVIDAD.Column("Observacion", header: "Observación"),
gridACTIVIDAD.Column("DESCR", header: "Tarea"),
gridACTIVIDAD.Column("FECHA", header: "Fecha",
format: (item) =>
{
return item.fecha.ToString("dd/MM/yyyy");
}
),
gridACTIVIDAD.Column("",
header: "ESTADO",
format: (item) =>
{
if (item.estado == "VC")
{
return Html.Image("/Imagenes/vc.gif","Validado correcto", new { #border = "0"});
}
else if (item.estado == "VI")
{
return Html.Image("/Imagenes/vi.gif", "Validado incorrecto", new { #border = "0" });
}
else if (item.estado == "NV")
{
return Html.Image("/Imagenes/vp.gif", "No validado", new { #border = "0" });
}
else
{
return Html.Image("/Imagenes/nv.png", "Pendiente validar", new { #border = "0" });
}
}
),
gridACTIVIDAD.Column("JDP", header: "JDP")
}
)
</div>
I've solved this issue on server side using HTMLAgilityPack.
This is the code for the view:
WebGrid webGrid = new WebGrid(Model.myModel, defaultSort: "title", rowsPerPage: 20);
IHtmlString webGridHtml = webGrid.GetHtml(
columns: webGrid.Columns(
webGrid.Column("id", "ID"),
webGrid.Column("title", "Title")
)
);
#Helper.GetExtendedWebGrid(webGrid, webGridHtml);
And this is the code for the Helper class:
public static IHtmlString GetExtendedWebGrid(WebGrid webGrid, IHtmlString webGridHtml)
{
HtmlString result;
string webGridHtmlString = webGridHtml.ToString();
HtmlDocument htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(webGridHtmlString);
HtmlNode htmlNodeAnchor = htmlDocument.DocumentNode.SelectSingleNode("//a[contains(#href,'" + webGrid.SortColumn + "')]");
if (htmlNodeAnchor != null)
{
string imgSortDirection;
if (webGrid.SortDirection == SortDirection.Ascending)
imgSortDirection = "asc";
else
imgSortDirection = "desc";
HtmlNode htmlNodeIcon = HtmlNode.CreateNode("<img src=\"/images/" + imgSortDirection + ".png\" width=\"10\" height=\"10\" />");
htmlNodeAnchor.ParentNode.AppendChild(htmlNodeIcon);
webGridHtmlString = htmlDocument.DocumentNode.OuterHtml;
}
result = new HtmlString(webGridHtmlString);
return result;
}
I just did a google search on "webgrid sort indicator" and came back with a result from http://prokofyev.blogspot.com/2011/01/sort-indicator-in-systemwebhelperswebgr.html
Basically, the person uses jQuery to add in the sort direction image.
<script type="text/javascript">
$('thead > tr > th > a[href*="sort=#grid.SortColumn"]').parent()
.append('#(grid.SortDirection == SortDirection.Ascending ? "U" : "D")');
</script>
(As an added bonus, I just tested it myself, so you can copy and paste this code (the link one is a picture instead of a code sample :( ...) just replace the U and D with whatever you want to display instead.
Hope that helps.
This page has a very simple example of how to implement the sorting arrow or images, when using the WebGrid with AJAX.
http://www.mikesdotnetting.com/Article/203/Enhancing-The-WebGrid-With-Sort-Arrows

Hiding columns values for few records in the grid depending on their role type: MVC3

**I am trying to create a view which has a grid
View layout, I am using is:**
#model IEnumerable<VC.MC.ReportalWeb.UI.Users>
#using myspace
#{
ViewBag.Title = "Users";
var grid = new WebGrid(source: Model, canSort: true);
}
<h2>Users</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#grid.GetHtml(columns: grid.Columns(
grid.Column("UserName"),
grid.Column("Email"),
grid.Column(
header: "",
style: "text-align-center",
format: (item) => new HtmlString(Html.ActionLink("Edit", "Edit", new { id = item.id ).ToString() + " | " +
Html.ActionLink("Details", "Details", new { id = item.id }).ToString() + " | " +
Html.ActionLink("Delete", "Delete", new { id = item.id }).ToString()))
)
)
#grid.GetHtml(columns: grid.Columns(Html.RoleBasedColumns(grid)))
#{
if (!string.IsNullOrWhiteSpace(grid.SortColumn))
{
<script type="text/javascript">
$('thead > tr > th > a[href*="sort=#grid.SortColumn"]').parent().append('#(grid.SortDirection == SortDirection.Ascending ? "^" : "v")');
</script>
}
}
The RoleBasedColumns(grid) is a helper method in my razor which is
public static WebGridColumn[] RoleBasedColumns(
this HtmlHelper htmlHelper,
WebGrid grid
)
{
var user = htmlHelper.ViewContext.HttpContext.User;
var columns = new List<WebGridColumn>();
var query = from p in _adminModelContainer.Users
select p;
IList<Users> userList = query.ToList();
for (int i = 0; i < userList.Count; i++)
{
// The Prop1 column would be visible to all users
columns.Add(grid.Column("UserName"));
if (userList[i].RolesId == 1)
{
// The Prop2 column would be visible only to users
// in the foo role
columns.Add(grid.Column("Email"));
}
}
return columns.ToArray();
}
I want to show Edit and delete link buttons only for those users whose RolesId is 1.
Using the above functionality the grid is just replicating itself .Columns headers are shown whose rolesid is 1.
I am in a fix.
Any help would be of great use.
Thanks
Do it the easy way and use Telerik's free open source mvc controls (the grid) and when you define your grid.. just use a dynamic column along the lines of:
#(Html.Telerik().Grid(Model)
.Name("Grid").TableHtmlAttributes(new { width="800"})
.Columns(columns =>
{
if (userIsInWhateverRole){
columns.Template(o => Html.Action(GenerateYourLinkStuffHere));
}
columns.Bound(o => o.Address).Width(150);
columns.Bound(o => o.City).Width(120);
columns.Bound(o => o.State).Width(100);
})
.Sortable()
.Scrollable()
.Groupable()
.Filterable()
.Pageable(paging =>
paging.PageSize(5)
.Style(GridPagerStyles.NextPreviousAndNumeric)
.Position(GridPagerPosition.Bottom)))
No other grid is as nice in my opinion - and its free. Why give yourself the headache : )

Resources