cascade dropdownlist asp.net - asp.net-mvc-3

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();
}

Related

KendoUI grid with draggable only works when I have developer tools open

I've created a nice little KendoUI grid with drag and drop. It works great... as long as I have the developer tools open. Any idea why this would work with the dev tools open, but doesn't work at all with just using the browser?
Edit to add the code:
my cshtml page:
<div id="DisplayOrderGridContainer">
<div class="validation-error-box" id="errorMessages" style="display:none">
<span>Error!</span>
<ul id="message">
<li>The Record you attempted to edit was modified by another user after you got the original value. The edit operation was canceled.</li>
</ul>
</div>
<div style="padding-bottom: 15px;">
#Html.ActionLink("Back", Model.BackActionName, Model.ControllerName, Model.BackRouteValues, new { id = Model.ControllerName + "_Back", #class = "k-button" })
#if (Model.AllowClearingDisplayOrder)
{
#Html.ActionLink("Clear Order", Model.ClearActionName, Model.ControllerName, Model.BackRouteValues, new { #id = "clear-button", #class = "k-button float-right" })
}
</div>
<div id="KendoGridContainer">
<div id="ChangeDisplayOrderGrid"
class="grid"
data-role="grid"
data-bind="source:data, events:{dataBound:onDataBound,columnHide:OnColumnHide,columnShow:OnColumnShow}"
data-filterable="false"
data-sortable="false"
data-column-menu="true"
data-row-template="rowTemplate"
#*data-toolbar='[{ "template": kendo.template($("#toolbarTemplate").html()) }]'*#
data-columns='[{title:"Short Name", field:"NameField", width: 80, headerAttributes:{id: "#Model.ControllerName" + "_ShortName"}},
{title:"Description", field:"DescriptionField", width:300, headerAttributes:{id: "#Model.ControllerName" + "_Description"}},
{title:"Display Order", field:"Display", width:140, headerAttributes:{id: "#Model.ControllerName" + "_Display"}},
{title:"Value", field:"Value", hidden: true, headerAttributes:{id: "#Model.ControllerName" + "_Value"}}]'>
</div>
<script id="rowTemplate" type="text/x-kendo-tmpl">
<tr class="k-master-row" data-uid="#:uid#">
<td class="text-right">#=NameField#</td>
<td class="text-right">#=DescriptionField#</td>
<td class="text-right">#=Display#</td>
<td class="text-right" style="display:none;">#=Value#</td>
</tr>
</script>
<div id="grid" data-grid-url="#(Url.Action(Model.ActionName, Model.ControllerName))" data-grid-viewdataid="#ViewData.ID()"></div>
</div>
<input type="hidden" id="displayOrderId" />
<input type="hidden" id="Id" />
my js page:
$(document).ready(function () {
UnsavedWarningsModule.ClearUnsavedChanges();
var newData = new kendo.data.DataSource({
transport: {
read: {
url: $('#grid').attr('data-grid-url'),
dataType: "json"
}
},
schema: {
model: {
id: "Id"
}
}
})
var viewModel = new kendo.observable({
data: newData,
onDataBound: function (e) {
pfsKendoGridEvents.SetSelectedRow_MVVMGrid("KendoGridContainer", e.sender, $('#grid').attr('data-grid-viewdataId'))
},
OnColumnHide: function (e) {
pfsKendoGridEvents.OnHideShowColumns(e);
},
OnColumnShow: function (e) {
pfsKendoGridEvents.OnHideShowColumns(e);
}
});
kendo.bind($("#DisplayOrderGridContainer"), viewModel);
kendo.addDragAndDropToGrid = function (gridId, rowClass, viewModel) {
if (!gridId) { throw "Parameter [gridId] is not set."; }
if (!rowClass) { throw "Parameter [rowClass] is not set."; }
$(rowClass).kendoDraggable({
hint: function (element) {
var shortName = element[0].cells[0].firstChild.data;
var desc = element[0].cells[1].firstChild.data;
var dispOrder = element[0].cells[2].firstChild.data;
element[0].innerHTML = "<td class=\"text-right dragOver\" style=\"width:95px\">" + shortName + "</td><td class=\"text-right dragOver\" style=\"width:382px\">" + desc + "</td><td class=\"text-right dragOver\" style=\"width:173px\">" + dispOrder + "</td>";
return element;
},
axis: "y",
container: $(gridId)
});
$(gridId).kendoDropTargetArea({
filter: rowClass,
drop: function (e) {
var srcUid = e.draggable.element.data("uid");
var tgtUid = e.dropTarget.data("uid");
var ds = $(gridId).data("kendoGrid").dataSource;
var srcItem = ds.getByUid(srcUid);
var tgtItem = ds.getByUid(tgtUid);
var dstIdx = ds.indexOf(tgtItem);
ds.remove(srcItem);
ds.insert(dstIdx, srcItem);
e.draggable.destroy();
UnsavedWarningsModule.SetUnsavedChanges();
kendo.addDragAndDropToGrid(gridId, rowClass, viewModel);
},
dragenter: function (e) {
e.draggable.hint.css("opacity", 0.3);
},
dragleave: function (e) {
e.draggable.hint.css("opacity", 1);
var srcUid = e.draggable.element.data("uid");
var tgtUid = e.dropTarget.data("uid");
var ds = $(gridId).data("kendoGrid").dataSource;
var srcItem = ds.getByUid(srcUid);
var srcDispOrd = srcItem.Display;
var tgtItem = ds.getByUid(tgtUid);
var tgtDispOrd = tgtItem.Display;
var dstIdx = ds.indexOf(tgtItem);
//--update display orders after dropping
ds._data.forEach(function (data) {
//if dragging it to a spot with higher dispOrder
if (tgtDispOrd > srcDispOrd) {
if (data.Display <= tgtDispOrd && data.Display > srcDispOrd) {
data.Display -= 1;
}
}
//if dragging it to a spot with lower dispOrder
if (srcDispOrd > tgtDispOrd) {
if (data.Display >= tgtDispOrd && data.Display < srcDispOrd) {
data.Display += 1;
}
}
});
srcItem.Display = tgtDispOrd;
//--end
ds.remove(srcItem);
ds.insert(dstIdx, srcItem);
}
});
};
var dataService = (function () {
"use strict";
var self = {};
self.getAddresses = function () {
var data = new kendo.data.ObservableArray([newData]);
// Manual create a promise, so this function mimicks an Ajax call.
var dfd = new $.Deferred();
dfd.resolve(data);
return dfd.promise();
};
return self;
})(kendo);
var controller = (function (dataService, viewModel) {
"use strict";
var _dataService = dataService;
var _vm = viewModel;
var self = {};
self.handleAddressesRefresh = function (data) {
_vm.set("addresses", new kendo.data.DataSource({ data: data }));
kendo.bind($("#KendoGridContainer"), _vm);
kendo.addDragAndDropToGrid("#ChangeDisplayOrderGrid", ".k-master-row", _vm);
};
self.show = function () {
$.when(_dataService.getAddresses())
.then(self.handleAddressesRefresh);
};
return self;
})(dataService, viewModel);
controller.show();});
I think it's something to do with the timing of the loading of the page, possibly with the promise I'm using?
Thanks!

Ajax Login from MVC

I have an MVC project that uses the inbuilt forms authentication (which talks to the MDF database stored in App_data). I want to change the login form to be the Ajax login form so that I can take advantage of the "onSuccess" and "onFailure" options.
Does anyone have a working example of how I would achive this as I've tried previuosly but I can't get the form to authenticate it just does nothing. I think I may have missed a step so any help is appreciated.
Example code would also be benificial. Please find my current code below.
The login view
#model MyProject.Models.LoginViewModel
#using (Ajax.BeginForm("Login", "Account", null, new AjaxOptions
{
OnSuccess = "OnSuccess",
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnComplete = "OnComplete",
HttpMethod = "POST",
UpdateTargetId = "target"
}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Login Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</li>
<li>
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe, new { #class = "checkbox" })
</li>
</ol>
<input type="submit" value="Login" />
</fieldset>
}
Here is the login controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public JsonResult ValidateUser(string userid, string password,
bool rememberme)
{
LoginStatus status = new LoginStatus();
if (Membership.ValidateUser(userid, password))
{
FormsAuthentication.SetAuthCookie(userid, rememberme);
status.Success = true;
status.TargetURL = FormsAuthentication.
GetRedirectUrl(userid, rememberme);
if (string.IsNullOrEmpty(status.TargetURL))
{
status.TargetURL = FormsAuthentication.DefaultUrl;
}
status.Message = "Login attempt successful!";
}
else
{
status.Success = false;
status.Message = "Invalid UserID or Password!";
status.TargetURL = FormsAuthentication.LoginUrl;
}
return Json(status);
}
Here is the login view model
public class LoginStatus
{
public bool Success { get; set; }
public string Message { get; set; }
public string TargetURL { get; set; }
}
Script on the page for handling the form
$(document).ready(function () {
$("#login").click(function () {
$("#message").html("Logging in...");
var data = {
"UserName": $("#userid").val(),
"Password": $("#password").val(),
"RememberMe": $("#rememberme").prop("checked")
};
$.ajax({
url: "/Home/Index",
type: "POST",
data: JSON.stringify(data),
dataType: "json",
contentType: "application/json",
success: function (status) {
$("#message").html(status.Message);
if (status.Success)
{
window.location.href = status.TargetURL;
}
},
error: function () {
$("#message").html("Error while authenticating user credentials!");
}
});
});
});
I've an extensions (MvcNotification) that put into ViewData or TempData messages to display.
To complement this, my post actions return "ERROR" or "OK" and i use those messages inside the ajax form OnSuccess.
MessageType
public enum MessageType
{
Success,
Warning,
Error,
Info
}
AjaxMessagesFilter
/// <summary>
/// If we're dealing with ajax requests, any message that is in the view data goes to the http header.
/// </summary>
public class AjaxMessagesFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var viewData = filterContext.Controller.ViewData;
var response = filterContext.HttpContext.Response;
foreach (var messageType in Enum.GetNames(typeof(MessageType)))
{
var message = viewData.ContainsKey(messageType)
? viewData[messageType]
: null;
if (message != null) // We store only one message in the http header. First message that comes wins.
{
response.AddHeader("X-Message-Type", messageType.ToLower());
response.AddHeader("X-Message", HttpUtility.HtmlEncode(message.ToString()));
return;
}
}
}
}
}
ControllerExtensions
public static class ControllerExtensions
{
public static ActionResult ShowMessage(this Controller controller, MessageType messageType, string message, bool showAfterRedirect = false, bool UseJson = false)
{
var messageTypeKey = messageType.ToString();
if (showAfterRedirect)
{
controller.TempData[messageTypeKey] = message;
}
else
{
controller.ViewData[messageTypeKey] = message;
}
if (UseJson)
return new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
else
return new ContentResult() { Content = "ERROR" };
}
public static ActionResult ShowMessage(this ControllerBase controller, MessageType messageType, string message, bool showAfterRedirect = false, bool UseJson = false)
{
var messageTypeKey = messageType.ToString();
if (showAfterRedirect)
{
controller.TempData[messageTypeKey] = message;
}
else
{
controller.ViewData[messageTypeKey] = message;
}
if (UseJson)
return new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
else
return new ContentResult() { Content = "ERROR" };
}
public static ActionResult EmptyField(this Controller controller, string FieldName, bool IsJson = false)
{
controller.ShowMessage(MessageType.Info, String.Format("O campo \"{0}\" é de carácter obrigatório.", FieldName));
return IsJson == false ? (ActionResult)new ContentResult() { Content = "ERROR" } : (ActionResult)new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
}
To call the extension inside the controller:
this.ShowMessage(MessageType.Error, "An error has occurred");
if you want to redirect after the message is thrown, you need to add true in the last parameter.
this.ShowMessage(MessageType.Error, "An error has occurred", true);
Note: I created the EmptyField method to give a standart message when some field is empty.
Action Example (LoginPost)
[HttpPost]
[AllowAnonymous]
public ActionResult LoginPost(LoginViewModel model, string returnUrl, bool Relogin = false)
{
returnUrl = string.IsNullOrEmpty(returnUrl) || string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl;
if (string.IsNullOrEmpty(model.UserName))
return this.EmptyField(Resource_General.UserName);
if (string.IsNullOrEmpty(model.Password))
return this.EmptyField(Resource_General.Password);
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = SignInManager.PasswordSignIn(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
var user = db.Users.FirstOrDefault(x => x.UserName == model.UserName);
if (!user.IsActive)
{
AuthenticationManager.SignOut();
this.ShowMessage(MessageType.Error, Messages.LockedOutUser);
return Content("ERROR");
}
if (Url.IsLocalUrl(returnUrl))
return Content(returnUrl);
else
return Content("/Home");
case SignInStatus.LockedOut:
this.ShowMessage(MessageType.Error, Messages.LockedOutUser);
return Content("ERROR");
case SignInStatus.RequiresVerification:
case SignInStatus.Failure:
default:
this.ShowMessage(MessageType.Error, Messages.WrongPassword);
return Content("ERROR");
}
}
Ajax Form
#using (Ajax.BeginForm("LoginPost", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, new AjaxOptions { OnSuccess = "OnSuccess" }, new { #id = "login-form" }))
{
#Html.AntiForgeryToken()
<div class="network-login-fields">
<div class="form-group">
<div class="input-group col-xs-12">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", placeholder = Resource_General.UserNamePlaceHolder, name = "loginname", autofocus = "true" })
</div>
</div>
<div class="form-group">
<div class="input-group col-xs-12">
#Html.PasswordFor(m => m.Password, new { #class = "form-control", placeholder = Resource_General.PasswordPlaceHolder, name = "password" })
</div>
</div>
<div class="network-login-links">
<button class="btn btn-default"><i class="fa fa-sign-in"></i> #Resource_General.Login</button>
</div>
</div>
}
Javascript
function OnSuccess(data) {
if (data != "ERROR") {
window.location.href = data;
}
}
Here in the javascript, you need to handle the ajax form OnSuccess and do something if the response is "OK" or "ERROR".
In your main javascript file you need to include this:
Handle Messages
// START Messages and Notifications
function handleAjaxMessages() {
$(document).ajaxStart(function () {
Openloading();
}).ajaxComplete(function (e, xhr, settings) {
CloseLoading();
}).ajaxSuccess(function (event, request) {
checkAndHandleMessageFromHeader(request);
}).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
if (thrownError !== "abort") {
CloseLoading();
NotifyError();
}
OnInit();
});
}
function checkAndHandleMessageFromHeader(request) {
var msg = request.getResponseHeader('X-Message');
if (msg) {
var title = NotifyHeader(request.getResponseHeader('X-Message-Type'));
Notify(msg, title, request.getResponseHeader('X-Message-Type'));
}
}
function NotifyHeader(type) {
console.log(type);
var title = "";
if (type == "error")
title = CustomScriptsLocales.ErrorTitle;
if (type == "success")
title = CustomScriptsLocales.SuccessTitle;
if (type == "warning")
title = CustomScriptsLocales.WarningTitle;
if (type == "info")
title = CustomScriptsLocales.InfoTitle;
console.log(title);
return title;
}
function Notify(message, title, type) {
if (title == null || title == "" || title == undefined) {
title = NotifyHeader(type);
}
PNotify.desktop.permission();
var notice = new PNotify({
title: title,
text: decodeHtml(message),
nonblock: {
nonblock: true,
nonblock_opacity: .55
},
buttons: {
closer: true,
},
desktop: {
desktop: false,
},
hide: true,
type: type,
delay: 2000,
insert_brs: true,
remove: true,
});
}
function NotifyError() {
Notify(CustomScriptsLocales.ErrorMessage, CustomScriptsLocales.ErrorTitle, "error");
}
// END Messages and Notifications
And call it inside a ready function:
$(document).ready(function () {
handleAjaxMessages();
}
Note: I use the PNotify plugin to show notifications. If you don't want notifications just exclude all this javascript "Handle Messages".

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/

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.

MVC3 WebGrid - Creating Columns Dynamically (foreach?)

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)))

Resources