MVC Pass Paramater from ActionLink to View to return Recordset - linq

I would like to pass a value from a link to a View and display the fields of the single record on the page.
Lets say I have #Html.ActionLink(item.Title, "Article/"+#item.ID, "News") which outputs /News/Article/1, I would need a Controller called NewsController with a /News/Article View.
I already have the following:
NewsController:
namespace WebApplication1.Controllers
{
public class NewsController : Controller
{
private WebApplication1Entities db = new WebApplication1Entities();
public ActionResult Article()
{
var articleModel = (from m in db.News where (m.Id == 1) && (m.Active == true) select m);
return View(articleModel);
}
[ChildActionOnly]
public ActionResult LatestNews()
{
var latestModel = (from m in db.News where (m.Id != 1) && (m.Active == true) select m);
return View(latestModel);
}
}
Not sure if I should use FirstOrDefault() as it can only be one record as the Id is unique, but unsure how to reference item objects inside the View without an IEnumerable list. At present the Id is set to 1 but I would like the recordset to reflect the Id passed.
Not sure what code to put inside the View, Article though, here is what I have so far:
Article.cshtml
#model IEnumerable<WebApplication1.Models.News>
#foreach (var item in Model) {
ViewBag.Title = #item.Title;
<div class="row">
<article class="span9 maxheight">
<section class="block-indent-1 divider-bot-2">
<h2>#item.Title</h2>
#item.Summary
#item.Content
</section>
</article>
<article class="span3 divider-left maxheight">
<section class="block-indent-1">
<h2>Latest News</h2>
#{ Html.RenderAction("LatestNews", "News"); }
</section>
</article>
</div>
}
LatestNews.cshtml
#{ Layout = null; }
#model IEnumerable<Shedtember.Models.News>
<ul class="nav sf-menu clearfix">
#foreach (var item in Model)
{
#Html.MenuLink(item.Title, "Article/"#item.ID, "News")
}
</ul>
This works for Id 1 but this needs to be dynamic.
Any help would be much appreciated :-)

In your RouteConfig class map a route as follows:
routes.MapRoute("Article", "Article/{id}", new {controller = "News", action = "Article"});
then in your Article method you can add and use the id parameter as follows:
public ActionResult Article(int id)
{
var articleModel = (from m in db.News where (m.Id == id) && (m.Active == true) select m);
return View(articleModel);
}

Related

How can I set selected model with list?

In my controller I set the items in the ViewBag:
List<ShopItemModel> items = new List<ShopItemModel>();
/* populate my items */
ViewBag.Items = items;
So on the cshtml i run thru the list, but how do I connect it so on postback sets the argument of the Post method in the controller?
The CSHTML:
#model Models.ShopItemModel
<h2>Webshop</h2>
#foreach( var item in ViewBag.Items)
{
using (Html.BeginForm())
{
<p>#item.Name</p> <!-- List the item name, but not bounded? -->
#Html.LabelFor(model => model.Name, new { Name = item.Name }) <!-- outputs just "Name", not the items name -->
<input type="submit" value="Buy" />
}
}
The post version of the method in the controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(ShopItemModel m)
{
return View();
}
But how do I fix this binding? So I fetch the selected item from the list?
In your view:
using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
#Html.LabelFor(model => model[i].Name)
}
}
This will produce html controls like this:
<input name="ShopItemModel[3].Name" ...
If you're using this in a form, in your controller, iterate over the POSTed model data:
foreach (var item in model)
{
... do something to each item
}
You can use a foreach loop in the view rather than a for loop, example here

MVC 4 Razor using Ajax forms to update a foreach loop

Where to start...I can find similar things on the Internet as to how, but they never seem to work with my specific way of wanting to do something. I have tried with and without partial views with very little success.
Quick rundown: I have a strongly-typed View with an Ajax form. underneath the form, I have a foreach loop that repeats a code block. I need to be able to update the code block from the forms choices (filters).
Here's my View, 'FindATeacher.cshtml', as it currently stands (after trying many different ideas):
#model Teachers.Models.OmniModel
#{
ViewBag.Title = "FindATeacher";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Find a Teacher</h2>
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions { HttpMethod = "Post", OnSuccess = "onSuccess" }))
{
<div id="ContentFilter">
<div class="filterLabels">
<p>Search by Name</p>
<p>Filter By Instrument</p>
<p>Filter By City</p>
</div>
<div class="filterObjects">
<p>
<input type="text" id="nameTXT" />
<button type="submit" id="findButton">find</button>
</p>
<p>#Html.DropDownList("InstrumentID", (SelectList)Model.Instruments, "-- Select an Instrument --", new { id = "instrumentDD" })</p>
<p>#Html.DropDownList("CityID", (SelectList)Model.Cities, "-- Select a City --", new { id = "cityDD" })</p>
</div>
</div>
}
<hr />
#foreach (var r in Model.Teachers)
{
<div id="ContentResults">
<div id="avatar">
<img src="i" />
</div>
<div id="demographics">
<h6>#r.Teacher</h6>
<strong>#r.StudioName</strong>
<p>#r.URL</p>
<p>#r.StreetAddress</p>
<p>#r.City, #r.AddressStateID #r.Zip</p>
<p>#r.Phone</p>
<p>#r.EmailAddress</p>
</div>
<div id="studioDetails">
<p><strong>Instrument(s) Taught</strong></p>
<p>
#{
var instrumentString = r.Instruments.Aggregate("", (a, b) => a + b.Instrument + ", ");
if (instrumentString.Length != 0)
{
instrumentString = instrumentString.Remove(instrumentString.LastIndexOf(","));
}
}
#instrumentString
</p>
<br />
#if (r.Information != "" && r.Information != null)
{
<p><strong>Information</strong></p>
<p>#r.Information</p>
}
</div>
</div>
}
Now here's my Controller. I get the results back correctly in the Controller, just not updating the code block:
public ActionResult FindATeacher()
{
Model.Instruments = new SelectList(TeacherService.GetInstrumentList(0),"InstrumentID","Instrument");
Model.Cities = new SelectList(TeacherService.GetCityList(),"CityID","City");
Model.Teachers = TeacherService.GetTeacherList("", 0);
return View(Model);
}
[HttpPost]
public JsonResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList("John", 0, 0);
return Json(Model.Teachers);
}
Thanks.
#VishalVaishya presents the right idea, but there's a simpler way, which doesn't involve custom javascript code: AjaxOptions has an UpdateTargetId property that the AJAX toolkit will interpret to mean you want the given target to be updated with the results sent back from the controller.
FindATeacher.cshtml:
#using (Ajax.BeginForm("FilterTeachers", "Home", new AjaxOptions {
HttpMethod = "Post", UpdateTargetId = "TeacherList" }))
{
...
}
<hr />
<div id="TeacherList">
#Partial("TeacherList", Model.Teachers)
</div>
TeacherList.cshtml
#model IEnumerable<Teacher>
#foreach(var teacher in Model)
{
...
}
Controller action:
[HttpPost]
public ActionResult FilterTeachers(String teacherName, String instrumentID, String cityID)
{
Model.Teachers = TeacherService.GetTeacherList(teacherName, instrumentID, cityID);
return PartialView("TeacherList", Model.Teachers);
}
You can try following method:
Separate your foreach loop into another partial view.
And load your partial view on filter / click event and pass filtered parameters to your controller-action.
JS change event code will be something like this:
var teacherName = ''; //get your selected teachername
var instrumentID = ''; //get your selected instrumentid
var cityID = ''; //get your selected city id
var url = '#Url.Action("FilterTeachers", "ControllerName", new { teacherName = "teacher-Name", instrumentID="instrument-ID", cityID="city-ID" })';
url = url.replace("teacher-Name", teacherName).replace("instrument-ID", instrumentID).replace("city-ID", cityID);
$('#result').load(url);

Best way to fill dropdownlist in mvc3 application

I have an Index view in an MVC3 application with a #model which is ienumerable. In this model I have an accountID which I want to use to populate my dropdownlist in the view filter with the accounts so that the user will be able to filter for accounts.
Which is the best way to achieve this?
Thanks in advance.
This is the view:
#model IEnumerable<MoneyAdmin.Model.ContaAReceber>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("_SubmenuAdmin")
<div class="tituloCadastro">
Lista de Contas a Receber
</div>
<div class="buttonContainer novo">
#Html.ActionLink("Nova Conta", "Create")
</div>
<div class="filtros">
#using (Html.BeginForm()) {
<div class="filterField">
<label>Data Inicial:</label>
#Html.TextBox("dataInicial", #DateTime.Now.ToShortDateString())
</div>
<div class="filterField">
<label>Data Final:</label>
#Html.TextBox("dataFinal", #DateTime.Now.ToShortDateString())
</div>
<div class="filterField">
<label>Tipo de Conta:</label>
#Html.DropDownList("contaID")
</div>
<input type="submit" value="Atualizar" />
}
</div>
And the controller method:
public ViewResult Index(string dataInicial, string dataFinal, string contaID)
{
var crs = from cr in db.contasareceber.Include("contas")
select cr;
if (!string.IsNullOrEmpty(dataInicial) && !string.IsNullOrEmpty(dataFinal))
{
DateTime di = DateTime.Parse(dataInicial);
DateTime df = DateTime.Parse(dataFinal);
crs = crs.Where(cr => cr.dataPagamento >= di && cr.dataPagamento <= df);
}
return View(crs.ToList());
}
I think the best way to achieve what you're after would be to use a ViewModel. You'd load the stuff you want to display in your View through this. So you'd create a dropdownlist with your accountlist which will be loaded in your controller. You'll also have your IEnumerable ContaAReceber in there which will also be loaded in your controller. Then your controller will pass the ViewModel to the View. Sort of hard to give you an exact answer as you haven't shown us your Model. But you can use this as a guide.
ViewModel:
public class ContaAReceberViewModel
{
public int ContaAReceberID {get;set;}
public List<SelectListItem> ContaAReceberList {get;set;}
public IEnumerable<ContaAReceber> ContaAReceber {get;set;}
}
Dropdownlist in Razor View :
#Html.DropDownListFor(m => m.ContaAReceberID, Model.ContaAReceberList)
You can use ViewBag instead of creating a ViewModel to transport your data.
ViewModel
public class ContaFilterViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
ActionResult
public ViewResult Index(string dataInicial, string dataFinal, string contaID)
{
var crs = from cr in db.contasareceber.Include("contas")
select cr;
// select uniquely all available Contas
ViewBag.UniqueContas = crs.Select(x => new ContaFilterViewModel() { Id = x.ContaId, Name = x.ContaName}).Unique().ToList();
if (!string.IsNullOrEmpty(dataInicial) && !string.IsNullOrEmpty(dataFinal))
{
DateTime di = DateTime.Parse(dataInicial);
DateTime df = DateTime.Parse(dataFinal);
crs = crs.Where(cr => cr.dataPagamento >= di && cr.dataPagamento <= df);
}
// return filtered Contas
return View(crs.ToList());
}
View
<div class="filterField">
<label>Tipo de Conta:</label>
#Html.DropDownList("contaID", new SelectList((ContaFilterViewModel)ViewBag.UniqueContas, "Id, "Name"))
</div>
Thanks for everyone!
I found the answer as like this.
Populate the viewbag in the controller like that:
ViewBag.Contas = new SelectList(db.contas, "contaID", "nome");
Then use it in the dropdownlist like that:
#Html.DropDownList("Contas");
Simple and it works!
Thanks for everyone!

PagedList in asp.net mvc 3 not returning anything to any page after 1

I am using paged list in a search actionresult to page my results. It returns events within a date range or category.The first page returned is fine, but the second never has any results. There are over 7 results that the query returns when I check a breakpoint. Here is my search controller;
public ActionResult Search(DateTime? q, DateTime? e, int? EventCategoryId, Event model)
{
var SearchEvents = db.Events
.OrderByDescending(r => r.start)
.Where(r =>
r.start >= q &&
r.end <= e &&
r.EventCategoryId == EventCategoryId ||
r.start >= q ||
r.EventCategoryId == EventCategoryId);
ViewBag.QValue = model.start;
ViewBag.EValue = model.end;
ViewBag.ListValue = model.EventCategoryId;
ViewBag.EventCategoryId = new SelectList(db.EventsCategories, "Id", "Name", ViewBag.ListValue);
var pageIndex = model.Page ?? 1;
var results = SearchEvents.ToPagedList(pageIndex, 4);
ViewBag.Names = results;
return View(results);
}
}
And here is my view;
#model IPagedList<RealKaac.Models.Event>
#{
ViewBag.Title = "SearchResults";
}
#using PagedList;
#using PagedList.Mvc;
#using System.Linq;
<div id="Content">
<h2>SearchResults</h2>
<div id="EventSearch">
#using (Html.BeginForm("Search", "Event"))
{
<p class="EventPar">Start Date: </p>
<input id ="datepicker" type ="text" name ="q" value="#ViewBag.QValue" />
<p class="EventPar">End Date: </p>
<input id ="datepickerend" type ="text" name ="e" value ="#ViewBag.EValue" />
<p class="EventPar">Category:</p>
#Html.DropDownList("EventCategoryId")
<input id="EventButton" style="padding:1px;" type ="submit" name ="Search" value = "Search" />
}
</div>
<div id="IndexEvents">
#foreach (var item in Model)
{
<div class ="event">
<div class="eventname">
#*<p>#Html.DisplayFor(modelItem => item.Name)</p> *#
</div>
<div class = "etitle">
<p>#Html.DisplayFor(modelItem => item.title)</p>
</div>
<div class="eventsdesc">
<p>#Html.DisplayFor(modelItem => item.EventDescription)</p>
</div>
<ul class ="datelink">
<li style="margin-right:120px;">This event starts on the
#Html.DisplayFor(modelItem => item.start) and ends on the
#Html.DisplayFor(modelItem => item.end)</li>
<li>Click #Html.DisplayFor(modelItem => item.EventWebsite) for more info.</li>
</ul>
</div>
}
</div>
</div>
#Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Search", new { page }))
I'm fairly new at this so I'm probably missing something small, any advice is greatly appreciated.
Thanks.
The Url.Action has only one parameter to it (the page #), which doesn't match the controller's method. It isn't providing access to any of the other parameters (such as the start/end dates). So, the second "page" query for the next 4 Events likely isn't working. If you created a SearchModel that had the necessary properties on it, you should easily be able to send the values from one page to the next.
public ActionResult Search(SearchModel search) {
//... (your search code)
// ... then, before returning the View,
ViewBag.SearchParameters = search;
return View(results);
where SearchModel has properties like:
public class SearchModel {
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int Page? { get; set; }
// etc.
}
Then, you could:
#Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Search", new SearchModel { search = ViewBag.SearchParameters }))
Or you could just use named parameters:
#Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Search", new { page = page, q = ViewBag.QValue, /* ... etc. */ }))

Working with ASP.NET Razor and HTML

I have a list of categories and sub categories which is passing from controller to the view. Now, I want them to be represented in the HTML like following. But, I dont know how can i achieve this by using foreach or table or whatever.
EDIT : Code
public ActionResult Electronics()
{
var topCategories = pe.Categories.Where(category => category.ParentCategory.CategoryName == "Electronics").ToList();
//var catsAndSubs = pe.Categories.Include("ParentCategory").Where(c => c.ParentCategory.CategoryName == "Electronics");
return View(topCategories);
}
With this view code, I am just able to pull a vertical list.
#foreach (var cats in Model)
{
<li>#cats.CategoryName</li>
foreach (var subcats in cats.SubCategories)
{
<li>#subcats.CategoryName</li>
}
}
When designing HTML mark-up it is very important to consider semantics. What meaning are you trying to convey? That doesn't look like tabular data to me so please don't put it in tables :P
Based on your wireframe above, the way I would probably structure this is like this:
<h1>Category Directory</h1>
<h2>Multimedia Projectors</h2>
<h2>Home Audio</h2>
<p>
Amplifiers, Speakers
</p>
Adjust the hX tags to reflect their position within the document's hierachy. Remember to only ever have ONE h1 per page (or per <acticle>, or <section> if using HTML5).
If instead you wind up turning this into something like a Superfish menu then this is the markup that you would use:
<nav id="category_menu">
<ul>
<li>
Multimedia Projectors
</li>
<li>
Home Audio
<ul>
<li>
Amplifiers
</li>
<li>
Speakers
</li>
</ul>
</li>
</ul>
</nav>
Edit
Your model is not suitable for creating your desired view, the relationship is bottom-up, but to conveniently construct the view you will want the relationships defined top-down. You need to start by converting the data model into a view model, such as:
class CategoryViewModel
{
string CategoryName { get;set; }
IList<CategoryModel> SubCategories { get;set; }
}
and to make this:
IList<CategoryViewModel> Map(IList<CategoryDataModel> dataModel)
{
var model = new List<CategoryViewModel>();
//Select the categories with no parent (these are the root categories)
var rootDataCategories = dataModel.Where(x => x.ParentCategory == null);
foreach(var dataCat in rootDataCategories )
{
//Select the sub-categories for this root category
var children = dataModel
.Where(x => x.ParentCategory != null && x.ParentCategory.Name = cat.Name)
.Select(y => new CategoryViewModel() { CategoryName = y.CategoryName })
.ToList();
var viewCat = new CategoryViewModel()
{
CategoryName = dataCat.CategoryName,
SubCategories = children
};
model.Add(viewCat);
}
return model;
}
Then your view:
<h1>Category Directory</h1>
#foreach(var category in Model)
{
#Html.Partial("Category", category)
}
Category partial:
<h2>#Html.ActionLink(Model.CategoryName, "Detail", new { Model.CategoryName })</h2>
#if(Model.SubCategories.Count> 0)
{
<p>
#for (var i = 0; i < Model.SubCategories.Count; i++)
{
var subCat = Model.SubCategories[i];
#Html.ActionLink(subCat.CategoryName, "Detail", new { subCat.CategoryName })
#if(i < Model.SubCategories.Count - 1)
{
<text>,</text>
}
}
</p>
}
Note that my current solution only supports 2 levels of categories (as per your wireframe). It could however be easily extended to be recursive.

Resources