I'm trying to take information from a DropDownList and post the SelectListItem "Value" to another ActionResult method in the controller. The controller it will be passed to will take an integer value and use it in another query.
My controller method for populating the DropDownList is as follows:
public ActionResult SelectCategory()
{
var model = new TestTypesViewModel();
var query = (from ab in db.Tbl_Admin_Batch
from ub in db.Tbl_Admin_User_Batch
where ub.User_Id == 45875 && ab.Batch_Id == ub.Batch_Id
select ab).ToList();
model.Test_Types = query.Select(c => new SelectListItem
{
Text = c.Batch_Name,
Value = c.Batch_Id.ToString()
}).ToList();
return View(model);
My ViewModel for TestTypesViewModel is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace HFI_Assessment_Administration.ViewModels
{
public class TestTypesViewModel
{
public int Batch_ID { get; set; }
public string Test_Type { get; set; }
public IEnumerable<SelectListItem> Test_Types { get; set; }
}
}
I'm new to MVC and trying to keep things simple, I know Batch_ID and Test_Type haven't been specified, but I'm not sure if they are even necessary at this point.
Any advice or help would be greatly appreciated, many thanks!
EDIT:
I now have a View for SelectCategory as follows:
#model HFI_Assessment_Administration.ViewModels.TestTypesViewModel
#{
ViewBag.Title = "SelectCategory";
}
#using (Html.BeginForm("Practice", "WebFormUserList"))
{
#Html.DropDownListFor(x => x.Batch_ID, Model.Test_Types)
<input type="submit" />
}
The controller it is being passed to is as follows:
[HttpPost]
public ActionResult Practice(TestTypesViewModel model, int Parent_ID = 45875)
{
var query = (from u in db.Users
join ur in db.User_Relationship on u.User_ID equals ur.Child_ID
join ub in db.Tbl_Admin_User_Batch on u.User_ID equals ub.User_Id
join ut in db.User_Tests on u.User_ID equals ut.User_ID into ps
from ut in ps.DefaultIfEmpty()
join lu in db.Lookups on u.First_LanguageID equals lu.LookupID
where ur.Parent_ID == Parent_ID && ub.Batch_Id == model.Batch_ID
group new { u, lu, ut } by new
{
u.User_ID,
u.Forename,
u.Surname,
u.Client_Code,
u.User_Name,
u.Password,
u.Email,
u.Gender,
u.Report_date,
u.EmailDate,
u.Job_Function,
lu.LookupValue
} into g
select new UserViewModel
{
User_ID = g.Key.User_ID,
Forename = g.Key.Forename,
Surname = g.Key.Surname,
Client_Code = g.Key.Client_Code,
User_Name = g.Key.User_Name,
Password = g.Key.Password,
Email = g.Key.Email,
Gender = g.Key.Gender,
Report_Date = g.Key.Report_date,
Email_Date = g.Key.EmailDate,
Test_Count = g.Count(p => p.ut.Test_ID != null),
Test_Completed = g.Count(p => p.ut.Completed != null),
Job_Function = g.Key.Job_Function,
Lookup_Value = g.Key.LookupValue
}).ToList();
return View(query);
}
The View for Practice is as follows:
#model IEnumerable<HFI_Assessment_Administration.ViewModels.UserViewModel>
#{
ViewBag.Title = "ChildUsers";
}
<h2>Practice</h2>
<div>
#{
var grid = new WebGrid(Model);
}
#grid.GetHtml(
tableStyle: "webgrid",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webgrid-selected-row",
rowStyle: "webgrid-row-style",
columns: grid.Columns
(
grid.Column(columnName:"User_ID", header: "User ID", style: "text-align-center"),
grid.Column(columnName:"Forename", header: "Forename", style: "text-align-center"),
grid.Column(columnName:"Surname", header: "Surname", style: "text-align-center"),
grid.Column(columnName:"Client_Code", header: "Client Code", style: "text-align-center"),
grid.Column(columnName:"User_Name", header: "User Name", style: "text-align-center"),
grid.Column(columnName:"Password", header: "Password", style: "text-align-center"),
grid.Column(columnName:"Email", header: "Email", style: "text-align-center"),
grid.Column(columnName:"Gender", header: "Gender", style: "text-align-center"),
grid.Column(columnName:"Report_Date", header: "Report Date", style: "text-align-center"),
grid.Column(columnName:"Email_Date", header: "Email Date", style: "text-align-center"),
grid.Column(columnName:"Test_Count", header: "Count", style: "text-align-center"),
grid.Column(columnName:"Test_Completed", header: "Completed", style: "text-align-center"),
grid.Column(columnName:"Job_Function", header: "Job Function", style: "text-align-center"),
grid.Column(columnName:"Lookup_Value", header: "Language", style: "text-align-center")
)
)
</div>
Everything is fine until I try to go to the next page of the grid or try to sort the grid. Upon where I get the error, Server Error in "/" Application. The resource cannot be found.
There are many ways to achieve that. You could either use a standard <form> tag or use AJAX to send the value.
Let's see the first case:
#model TestTypesViewModel
#using (Html.BeginForm("SomeAction", "SomeController"))
{
#Html.DropDownListFor(x => x.Test_Type, Model.Test_Types)
<button type="submit">OK</button>
}
and now in your target action:
[HttpPost]
public ActionResult SomeAction(TestTypesViewModel model)
{
// model.Test_Type will contain the selected value here
// Notice that if you intend to return the same view as the GET action
// (SelectCategory.cshtml) you should assign the Test_Types property on
// your model by querying your database the same way you did in the GET action
// before passing this model to the view. If on the other hand you intend to
// redirect here you don't need to assign it.
}
A second possibility is to use AJAX. So you could for example give your dropdownlist an id and have some link that when clicked it will invoke the target controller action sending it the selected value using AJAX:
#Html.DropDownListFor(x => x.Test_Type, Model.Test_Types, new { id = "testTypeDdl" })
#Html.ActionLink("click me", "SomeAction", null, new { id = "myLink" })
and then when some button or link is clicked use the $.ajax request:
$(function() {
$('#myLink').click(function() {
$.ajax({
url: this.href,
type: 'GET',
cache: false,
data: { selectedValue: $('#testTypeDdl').val() },
success: function(result) {
alert('The value was submitted to the server');
}
});
return false;
});
});
and now your controller action could have the following signature:
public ActionResult SomeAction(string selectedValue)
{
// Process the selected value here and return some result.
// This result could either be a PartialView or a JsonResult
// depending on your requirements.
}
Related
I started using web grid from last couple of days. Everything was so handy with webgrid like displaying columns with different datatype like textbox, label, drop down etc. But how do I save data or update data.
I tried using action link and submit buttons but none of them worked for me. They weren't fetching the modified drop down data in my controller. The action link was able to fetch the user id but it couldn't get the changed drop down value.
Below is the code:
View
WebGridColumn colLocation = null;
foreach (var col in Model)
{
colLocation = new WebGridColumn()
{
Header = "Locations",
Format = (item) => #Html.DropDownList("LocationId", #col.LocationItems.Select(l => new SelectListItem
{
Text = l.Text,
Value = l.Value,
Selected = ((WebGridRow)item)["LocationId"].ToString() == l.Value
}
)
)
};
colSave = new WebGridColumn()
{
Header = "Save User",
Format = (item) => Html.ActionLink("Save", "Save", "UsersList", new { userId = item.UserId, locationId = item.LocationId }, new { #class = "btn btn-default" }),
CanSort = true
};
}
columns.Add(colLocation);
columns.Add(colSave);
#grid.GetHtml(tableStyle: "webgrid",
headerStyle: "header",
selectedRowStyle: "select",
alternatingRowStyle: "alt",
columns: columns
)
Controller
public ActionResult Save(int userId, int locationId)
{
var user = Utility.SetUserDetails(userId, locationId);
return RedirectToAction("UsersList");
}
After some rigorous trials, I've achieved this functionality. This can be done using ajax.
I've to extend my column properties to include class & id attribute
colUser = new WebGridColumn()
{
Header = "User Id",
ColumnName = "UserId",
CanSort = true,
Format = #<text>
<span class="display"><label id="lblUserId">#item.UserId</label></span>
<input type="text" id="inUserId" value="#item.UserId" class="edit" style="visibility:hidden" />
</text>
};
colLocation = new WebGridColumn()
{
Header = "Locations",
Format = #<text>
#Html.DropDownList("Location", #col.LocationItems.Select(l => new SelectListItem
{
Text = l.Text,
Value = l.Value,
Selected = ((WebGridRow)item)["LocationId"].ToString() == l.Value
}
), new { #class = "edit", #id = "inLocation" })
</text>
};
colSave = new WebGridColumn()
{
Header = "Save User",
Format = #<text>
Save
</text>
};
After adding the jquery script, we can post the selected values into controller,
<script type="text/javascript">
$(function () {
$('.save-btn').on("click", function () {
var tr = $(this).parents('tr:first');
var id = tr.find("#inUserId").val();
var location = tr.find("#inLocation").val();
var User =
{
"UserId": id,
"LocationId": location
};
$.ajax({
url: '/UsersList/SaveData/',
data: JSON.stringify(User),
type: 'POST',
contentType: 'application/json; charset=utf-8',
success: function (result) {
isSuccess = result;
},
error: function (result) {
isSuccess = result;
}
})
});
});
</script>
In the controller, add new method,
public ActionResult SaveData(UserAccountViewModel User)
{
int userId = User.UserId;
int locationId = Convert.ToInt32(User.LocationId);
var user = Utility.SetUserDetails(userId, locationId);
return RedirectToAction("UsersList");
}
in web-grid i can not use navigation properties between my classes(products and productimages classes). for example i have used below code in web grid:
grid.Column("", "test",item=> (item.ProductImages.First().Id)+(item.Price))
but i got error:
'System.Collections.Generic.HashSet<WebStore.Models.ProductImage>' does not contain a definition for 'First'
my total code is like below:
#model IEnumerable<WebStore.Models.Product>
#using System.Linq;
#{
var grid = new WebGrid(source: Model, rowsPerPage: 5,ajaxUpdateContainerId:"divGrid");
}
#grid.GetHtml(tableStyle: "gridStyle", headerStyle: "gridHeader", rowStyle: "gridRow", alternatingRowStyle: null,htmlAttributes:new{Id="divGrid"},
columns: new WebGridColumn[] {
grid.Column("ProductName", "Product Name"),
grid.Column("Price", "Price"),
grid.Column("Description", "Description"),
grid.Column("CategoryName","Category Name",x=>x.Category.CategoryName),
grid.Column("", "test",item=> (item.ProductImages.First().Id)+(item.Price)),
grid.Column("","",x=>Html.ActionLink("Edit", "Edit", new{id=x.Id})),
grid.Column("","",x=>Html.ActionLink("Details", "Details", new{id=x.Id})),
grid.Column("","",x=>Html.ActionLink("Delete", "Delete", new{id=x.Id}))
}
)
this is my index view:
#model IEnumerable<WebStore.Models.Product>
#using System.Linq
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_LayoutCategory.cshtml";
}
<br/>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div id="divGrid">
#{ Html.RenderPartial("_ProductTitle", Model); }
</div>
this is my RenderPartial that use web grid before i posted:
#model IEnumerable<WebStore.Models.Product>
#using System.Linq
#ViewBag.test
#{
var grid = new WebGrid(source: Model, rowsPerPage: 5,ajaxUpdateContainerId:"divGrid");
}
#grid.GetHtml(tableStyle: "gridStyle", headerStyle: "gridHeader", rowStyle: "gridRow", alternatingRowStyle: null,htmlAttributes:new{Id="divGrid"},
columns: new WebGridColumn[] {
grid.Column("ProductName", "Product Name"),
grid.Column("Price", "Price"),
grid.Column("Description", "Description"),
grid.Column("CategoryName","Category Name",x=>x.Category.CategoryName),
grid.Column("", "test",item=>(int) (item.ProductImages.FirstOrDefault().Id)+(int)(item.Price)),
grid.Column("","",x=>Html.ActionLink("Edit", "Edit", new{id=x.Id})),
grid.Column("","",x=>Html.ActionLink("Details", "Details", new{id=x.Id})),
grid.Column("","",x=>Html.ActionLink("Delete", "Delete", new{id=x.Id}))
}
)
It's because definition of First is available in System.Linq. So, you should have System.Linq in your razor page :
#using System.Linq;
if you are using Linq in multiple page, you can add System.Linq namespace in web.config so that you do not need to write above using in each page. You can add namespace in web.config in following configuration :
<system.web.webPages.razor>
<pages>
<namespaces>
<add namespace="System.Linq" />
</namespaces>
</pages>
</system.web.webPages.razor>
i got the answer of my question with below code from the net:
I followed your steps and test your code and the same error display. So I think the format in your code can not be used in webgrid. So I think about another way to meet your requirement: we need a ViewModel to display what you want to show in the View and search the first item in Controller then save as ViewModel and pass the ViewModel to View, then we do not need search in the View. Here I will show you the steps with my demo.
Now, we have two model Product and Quantity that one product has many quantities. We should create a ViewModel.
ViewModel.cs:
public class ViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public long quan { get; set; }
}
We can initialize some data and search the first value of Quantity depend on Product in Controller and assign to the ViewModel.
InventoryController .cs:
public class InventoryController : Controller
public ActionResult WebgridSample()
{
ObservableCollection<Product> inventoryList =
new ObservableCollection<Product>();
inventoryList.Add(new Product
{
Id = "P101",
Name = "Computer",
Description = "All type of computers",
quantity = new List<Quantity>
{
new Quantity {QUAN = 100 },
new Quantity {QUAN = 200 },
new Quantity {QUAN = 300 }
}
});
inventoryList.Add(new Product
{
Id = "P102",
Name = "Laptop",
Description = "All models of Laptops",
quantity = new List<Quantity>
{
new Quantity {QUAN = 400 },
new Quantity {QUAN = 500 },
new Quantity {QUAN = 600 }
},
});
inventoryList.Add(new Product
{
Id = "P103",
Name = "Camera",
Description = "Hd cameras",
quantity = new List<Quantity>
{
new Quantity {QUAN = 700 },
new Quantity {QUAN = 800 },
new Quantity {QUAN = 900 }
}
});
IEnumerable<string> model = (from sig in inventoryList
select new ViewModel
{
Name = sig.Name,
Description = sig.Description,
quan = sig.quantity.FirstOrDefault(),
}).ToList();
return View(model);
}
We can call each parameters of ViewModel in webgrid without using First().
WebgridSample.cshtml:
<div id="gridContent">
#grid.GetHtml(tableStyle: "webGrid",
headerStyle: "header",
alternatingRowStyle: "alt",
selectedRowStyle: "select",
columns: grid.Columns(
grid.Column("Id", ),
grid.Column("Name", " Name"),
grid.Column("Description", "Description", style: "description"),
grid.Column("Quantity", "quan "</i>)
))
when I define my Delete method below with [HttpPost], the Delete method cannot be called from the View. However, when deleting [HttpPost] line, it works normally. I tried lots of the things and actually it may be related to wrong usage of #Html.Hidden or #using (Html.BeginForm() in my View. So, could you please clarify me about these points below?
1) I do not open a View after clicking delete button on my WebGrid. After a confirmation method the Delete method in the Controller should be called and the record should be deleted by staying on the same page.So, is it wrong not using [HttpPost] for my Delete method below?
2) If it is possible, how should I do in order to use [HttpPost] for the Delete method? Which changes do I have to do on my View i.e. using form or hidden property?
View:
#model IEnumerable<MyProject.Domain.Entities.Applicant>
#using PRMeetingReg.WebUI.HtmlHelpers
#{
var grid = new System.Web.Helpers.WebGrid(
source: Model,
columnNames: new List<string>() { "Title" },
ajaxUpdateContainerId: "myGrid",
defaultSort: "Name",
canPage: true,
canSort: true,
rowsPerPage: 5
);
grid.SortDirection = SortDirection.Ascending;
}
<div class="Grid">
#grid.GetHtml(
tableStyle: "table",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
rowStyle: "webgrid-row-style",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webgrid-selected-row",
firstText: "<<",
lastText: ">>",
mode: WebGridPagerModes.All,
fillEmptyRows: true,
numericLinksCount: 5,
columns: grid.Columns(
grid.Column("ApplicantID", "No", canSort: true),
grid.Column("Name", "Name", canSort: true),
grid.Column("Surname", "Surname", canSort: true),
//for using multiple Html.ActionLink in a column using Webgrid
grid.Column("Actions", format: (item) =>
new HtmlString(
#Html.ActionImage("../../Content/icons/detail.png", "Detail", "icon-link", "Detail", "Admin", new { applicantId= item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/icons/edit.png", "Edit", "icon-link", "Edit", "Admin", new { applicantId= item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/icons/delete.png", "Delete", "icon-link", "Delete", "Admin", new { applicantId= item.ApplicantID }).ToString()
)
)
)
)
<p>
<input id="add" type="submit" value="Yeni Ekle" class="button" />
</p>
</div>
Controller:
[HttpPost]
public ActionResult Delete(int applicantId)
{
Applicant deletedApplicant = repository.DeleteApplicant(applicantId);
if (deletedApplicant != null)
{
TempData["message"] = string.Format("{0} was deleted",
deletedApplicant.Name);
}
return RedirectToAction("Index");
}
My HTML Helper:
public static MvcHtmlString ActionImage(this HtmlHelper html, string imagePath, string alt, string cssClass,
string action, string controllerName, object routeValues)
{
var currentUrl = new UrlHelper(html.ViewContext.RequestContext);
var imgTagBuilder = new TagBuilder("img");
imgTagBuilder.MergeAttribute("src", currentUrl.Content(imagePath));
imgTagBuilder.MergeAttribute("title", alt);
imgTagBuilder.MergeAttribute("class", cssClass);
string imgHtml = imgTagBuilder.ToString(TagRenderMode.SelfClosing);
var anchorTagBuilder = new TagBuilder("a");
anchorTagBuilder.MergeAttribute("href", currentUrl.Action(action, controllerName, routeValues));
anchorTagBuilder.InnerHtml = imgHtml;
string anchorHtml = anchorTagBuilder.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(anchorHtml);
}
Thanks in advance.
Your ActionImage custom helper generates an image containing an anchor tag inside (<a>). In HTML an anchor sends GET request. Your controller action is decorated with the HttpPost request which explains why it is never called.
One possibility to make this work is to use an AJAX request and perform a POST request instead of GET when clicking on the Delete link.
I have no idea why this is happening, I have set the values and debugged it, but it is just not passing the information from the controller to the view. Here is what is going on
Model:
public class QueueFilterModel
{
public string SelectedFilter { get; set; }
public string query { get; set; }
public List<string> MyFilterList { get; set; }
}
Controller:
[HttpGet]
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View();
}
View:
#model RazorARPP.Models.QueueFilterModel
#{
ViewBag.Title = "Queue";
}
<h2>Queue</h2>
<form action="" method="post" enctype="multipart/form-data" id="MyForm">
Filter
<div>
Filter Options:
</div>
<div>
#Html.DropDownList("test", new SelectList(Model.MyFilterList,Model.SelectedFilter))
</div>
<h3>Insert Instructions Here</h3>
#{
var DB = Database.Open("CHAVI");
var grid = new WebGrid(DB.Query("SELECT * FROM [TicketQueue]"), null, null, 20);
#grid.GetHtml(
tableStyle: "webgrid",
columns: grid.Columns(
grid.Column(header: "Link", style: "labelcolumn", format: (item) => Html.ActionLink("Edit Item", "EditQueue", new { id = item.QueueID})),
grid.Column("Description", "Description"),
grid.Column("QueueDate", "QueueDate"),
grid.Column("Note", "Note"),
grid.Column("Status", "Status"),
grid.Column("LastUpdated", "LastUpdated")
)
)
}
</form>
The grid part is working fine (and the query). The problem is in the dropdown, it isn't set to anything there. Any thoughts? Thanks.
Are you not passing the model to view?
Should it not be
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View(model);
}
Try using:-
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View(model);
}
I have table:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Add</legend>
<br />
#{
var grid = new WebGrid(ViewBag.produkty,null, "names", 5);
}
#grid.GetHtml(
tableStyle: "grid",
headerStyle: "head",
alternatingRowStyle: "alt",
columns: grid.Columns(
grid.Column("name"),
grid.Column("value"),
grid.Column(header: "Add", format: (item) =>
new HtmlString(
Html.TextBoxFor(model => model.add).ToString())),
grid.Column( header: "Ok", format: (item) =>
new HtmlString(
Html.ActionLink("OK", "add_method", new { ID_name = item.ID_name }).ToString()))
)
)
</fieldset>
}
Controller:
public ActionResult use()
{
var nam = (from d in baza.Names
select new { d.ID_name, d.name, d.value}).ToList();
ViewBag.names= nam;
return View();
}
public ActionResult add_method(int ID_name, useModel use)
{
Use us = new Use();
var dat = DateTime.Today;
us.value = use.add;
us.ID_Name= ID_name;
us.data = dat;
baza.Zuzycies.InsertOnSubmit(us);
baza.SubmitChanges();
return RedirectToAction("use", "Product");
}
Model:
public class useModel
{
public int ID_name{ get; set; }
public decimal value{get;set;}
public string date { get; set; }
}
So, I have list of product on page. And I want to add a value (amount of product) into TextBox and press a ActionLink "OK" next to the textbox. How can I get amount of product in add_method? Or how insert submit button next to every one product (instead ActionLink "OK"), then is enought make use POST method...
You can use a grid componet with built-in edits functions (like the telerik Grid).
I think it's better to use ajax not reagular post request for your scenario.
Or you can do that ajax calls to the server with jquery, just send the parameters to the controller.