I am new to MVC. using MVC 3.
I have PersonMaster Controller as below... having following two Actions.
public ActionResult TopTenPersons()
{
Thread.Sleep(2000);
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select top(10) from person_master").ToList();
return View("_PersonGrid", persons);
}
public ActionResult Index()
{
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select * from person_master").ToList();
return View("_PersonGrid",persons);
//return View();
}
Then, index.cshtml view is as follows..
#model System.Collections.Generic.ICollection<MyPracticeApp1.Models.Person_Master>
#section scripts{
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}
<h2>Persons</h2>
<p>
#Ajax.ActionLink("Click to top 10 Persons","TopTenPersons", new AjaxOptions{
UpdateTargetId="tbl_person",
InsertionMode=InsertionMode.Replace,
HttpMethod="GET"
})
</p>
<div id="tbl_person">
#Html.Action("Index","PersonMaster");
</div>
..and partial view _PersonGrid.cshtml which is called above in index view is as follows...
#model System.Collections.Generic.ICollection<MyPracticeApp1.Models.Person_Master>
#{
var persongrid = new WebGrid(Model);
}
#persongrid.GetHtml()
....But problem is that it directly shows partial view. It is not rendering Ajax Actionlink of index view. So, where is the mistake?
Change TopTenPersons to return a Partial View, not a View
public ActionResult Index()
{
var persons = DatabaseHelper.Instance.Database.Query<Person_Master>("select * from person_master").ToList();
return PartialView("_PersonGrid",persons);
}
add layout=null to _PersonGrid.cshtml
seems like
#{
Layout = null;
}
when you add this code It is not rendering full view..
Related
I can't quite figure out how to get a partial view to render a paged list using ajax.
The closest I've got it to working is the example from Using paging in partial view, asp.net mvc
I'm basically trying to create a page with a list of comments per user where the page can be changed in the same way as the answers tab on the stackoverflow users page.
The paging works fine the on the first pager click, but then the the partial view is all that is returned once I click on the pager again.
Controller:
public class ProductController : Controller
{
public IQueryable<Product> products = new List<Product> {
new Product{ProductId = 1, Name = "p1"},
new Product{ProductId = 2, Name = "p2"},
new Product{ProductId = 3, Name = "p3"},
new Product{ProductId = 4, Name = "p4"},
new Product{ProductId = 5, Name = "p5"}
}.AsQueryable();
public object Index()
{
return View();
}
public object Products(int? page)
{
var pageNumber = page ?? 1; // if no page was specified in the querystring, default to the first page (1)
var onePageOfProducts = products.ToPagedList(pageNumber, 3); // will only contain 25 products max because of the pageSize
ViewBag.OnePageOfProducts = onePageOfProducts;
return PartialView("_Products");
}
}
Views:
Index.cshtml:
<link href="/Content/PagedList.css" rel="stylesheet" type="text/css" />
<h2>List of Products</h2>
<div id="products">
#Html.Action("Products", "Product")
</div>
#section scripts{
<script type="text/javascript">
$(function() {
$('#myPager').on('click', 'a', function() {
$.ajax({
url: this.href,
type: 'GET',
cache: false,
success: function(result) {
$('#products').html(result);
}
});
return false;
});
});
</script>
}
_Products.cshtml:
#using PagedList.Mvc;
#using PagedList;
<ul>
#foreach(var product in ViewBag.OnePageOfProducts){
<li>#product.Name</li>
}
</ul>
<!-- output a paging control that lets the user navigation to the previous page, next page, etc -->
<div id="myPager">
#Html.PagedListPager((IPagedList)ViewBag.OnePageOfProducts, page => Url.Action("Products", new { page }))
</div>
Model
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
}
Can anyone show me what I'm doing wrong?
I ended up using the unobtrusive ajax example from the pagedlist source [https://github.com/troygoode/PagedList][1]
partial view:
#using PagedList;
#using PagedList.Mvc;
<ul id="names" start="#ViewBag.Names.FirstItemOnPage">
#foreach(var i in ViewBag.Names){
<li>#i</li>
}
</ul>
#Html.PagedListPager((IPagedList)ViewBag.Names, page => Url.Action("Index", new { page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions(){ HttpMethod = "GET", UpdateTargetId = "unobtrusive"}))
Index:
#{
ViewBag.Title = "Unobtrusive Ajax";
}
#using PagedList;
#using PagedList.Mvc;
#Styles.Render("~/Content/PagedList.css")
<h2>Unobtrusive Ajax</h2>
<p>Example of paging a list:</p>
<div id="unobtrusive">
#Html.Partial("UnobtrusiveAjax_Partial")
</div>
Controller:
public class UnobtrusiveAjaxController : BaseController
{
// Unobtrusive Ajax
public ActionResult Index(int? page)
{
var listPaged = GetPagedNames(page); // GetPagedNames is found in BaseController
if (listPaged == null)
return HttpNotFound();
ViewBag.Names = listPaged;
return Request.IsAjaxRequest()
? (ActionResult)PartialView("UnobtrusiveAjax_Partial")
: View();
}
}
Just in case, since the original question wasn't answered. I guess the problem was that on click handlers weren't reattached to the new pager elements generated by AJAX request. I also don't like unobstrusive AJAX solution in this case, since pager id is hardcoded in the nested view while passing it in some other way may be too cumbersome.
<script type="text/javascript">
// better not to clutter global scope of course, just for brevity sake
var attachHandlers = function() {
$('#myPager a').click(function() {
$('#myPager').load(this.href, function() {
attachHandlers();
});
return false;
});
};
$(document).ready(function () {
attachHandlers();
});
</script>
I have a newsletter text box that renders in a PartialView. This is the get action:
[ChildActionOnly]
public PartialViewResult NewsLetterSidebar()
{
return PartialView("_NewsLetterSidebar");
}
And this is the Razor view:
model Blog.Web.UI.ViewModels.NewsLetterViewModel
#{
ViewBag.Title = "_NewsLetterSidebar";
}
#using (Html.BeginForm("NewsLetter", "Home", FormMethod.Post))
{
<h3>News Letter</h3>
<div>
#Html.TextBoxFor(news => news.EmailAddress)
#Html.ValidationMessageFor(news => news.EmailAddress)
</div>
<div>
<input type="submit" value="Verify">
</div>
}
I want the success message to appear under the verify button in case of valid input. This is my post action:
[HttpPost]
public JsonResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
}
return Json("Done!");
}
How can I show the JSON message under the View?
Not tested but will help you to complete what you want.
[HTTPGET]
public JsonResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
}
return Json("Done!", JsonRequestBehavior.AllowGet);
}
replace this
#using (Html.BeginForm("NewsLetter", "Home", FormMethod.Post))
{}
with
#using (Ajax.BeginForm("NewsLetter", "Home", new AjaxOptions{ onsuccess:"ShowMessage"}))
{}
JS
function ShowMessage(data){
alert(data);
}
If you would like to use the first approach from my comment above, you need slightly modify your code. First of all, add Message property to your NewsLetterViewModel, then change the partial view:
#using (Ajax.BeginForm("NewsLetter", new AjaxOptions{UpdateTargetId = "newsletter-container"}))
{
<h3>News Letter</h3>
<span>#Model.Message</span>
<div>
#Html.TextBoxFor(news => news.EmailAddress)
#Html.ValidationMessageFor(news => news.EmailAddress)
</div>
<div>
<input type="submit" value="Verify">
</div>
}
Please noеe that your partial view should be wrapped into a html element with id="newsletter-container" on your page e.g:
<div id="newsletter-container">
#{Html.RenderPartial("_NewsLetterSidebar", new NewsLetterModel());}
</div>
Now, a small change in the controller:
[HttpPost]
public ActionResult NewsLetter(NewsLetterViewModel newsLetter)
{
var newsLetterViewModel = newsLetter.ConvertToNewsLetterModel();
if (ModelState.IsValid)
{
_newsLetterRepository.Add(newsLetterViewModel);
_newsLetterRepository.Save();
model.Message = "Done!";
}
return PartialView("_NewsLetterSidebar", model);
}
You also need to add jquery.unobtrusive-ajax.js to make it work.
Requirment: I have a drop down and a table on my cshtml page. The drop down displays a list of vendors and the details corresponding to selected vendor are displayed in table. I am submitting the form using jquery when the value of the drop down changes.
Problem: How to cath selected value of drop down in controller?
Code:
#Html.DropDownList("VendorList", new SelectList(Model.vendorList, "vendorId", "vendorName"))
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
}
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
$('#VendorList').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
the code in my controller is:
[AcceptVerbs("POST")]
public ActionResult SearchResult(FormCollection collection)
{
try
{
string vendorName = collection["searchItem"].ToString();
vendorName = vendorName.Trim();
List<Vendor> vendorList = Queries.compiledVendorQuery(dbContext, vendorName).ToList<Vendor>();
if(vendorList.Count() == 0)
return View("EmptySearch");
Vendor selectedVendor = vendorList[0];
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorList = vendorList;
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
catch (Exception e)
{
return View("EmptySearch");
}
}
[AcceptVerbs("POST")]
public ActionResult VendorDetails(FormCollection collection)
{
**here comes the control after postback
require value of the selected item**
Vendor selectedVendor = ??
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
Since you're not really using the FormCollection, you could just use an int (or whatever the ID is on your model) in your action method:
[HttpPost]
public ActionResult VendorDetails(int vendorId = 0)
{
Vendor selectedVendor = // Load from your data source using vendorId
... // Do the rest of your work
}
In your HTML, move your #Html.DropDownListFor() into your form, rename it to the argument name, then submit the form as normal. Since the display doesn't seem to have any affect on what gets sent to the server, I would pull this out and just leave the #Html.DropDownListFor() in the form:
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
#Html.DropDownList("vendorId", new SelectList(Model.vendorList, "vendorId", "vendorName"))
}
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
<script type='text/javascript'>
$(document).ready(function () {
$('#vendorId').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
Edit
Take a look at this article about MVC's model binding for an idea of how vendorId gets injected from the submitted form. Basically, the binder will match property names with the name attribute (by default) to your model. In this case, our model is just an int.
I have this simple MVC 3 application which simply has two controllers(Home and Edit), two actions one per controller and two views for each action,
each one of the views has an ajax action link which simply request the other view and displays the result in a div, the problem is that after a certain number of requests the page is getting slower, I checked that with fiddler and noticed that each time I press the action link the request will be send multiple times according to the equation (2 to the power n) where n is how many time the link was pressed, find below the controllers and views.
the Controllers
public class EditController : Controller
{
public ActionResult Index()
{
return View();
}
}
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Text = "Home Page";
return View();
}
}
And the views
Home View
#{
ViewBag.Title = "Home";
}
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script type="text/javascript">
function myCallback(xhr, status) {
alert(status);
}
</script>
<div id="divLoading" style="display: none">
Loading ...</div>
<div id="divResultText">
#Ajax.ActionLink("Edit Ajax", "Index", "Edit", null, new AjaxOptions
{
HttpMethod = "Get",
OnComplete = "myCallback",
UpdateTargetId = "divResultText",
LoadingElementId = "divLoading"
})
</div>
Edit View
#{
ViewBag.Title = "Edit";
}
#Ajax.ActionLink("Home", "Index", "Home", null, new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId = "divResultText",
LoadingElementId = "divLoading"
})
I have got the answer in
Ajax.ActionLink in MVC3 is getting slow after a number of requests
i have a button on the cshtml view..its clicked every-time an item is scanned.
The user has to do it one by one and once all the items have been scanned..i want to opem/pop up a new window plus redirect him to another page.. The condition whether it was the last item..is being checked in the controller method.
How can i call a javascript to open the new window from the controller..right before my 'redirecttoaction' ?
is there a better way to do it?
Here's a sample pattern:
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// TODO Process the scanned code model.Code
if (IsLastItem())
{
model.IsLast = true;
}
return View(model);
}
and inside the view:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.Code)
<input type="submit" value="OK" />
}
<script type="text/javascript">
#if (Model.IsLast)
{
<text>
window.open('#Url.Action("foo")', 'foo');
window.location.href = '#Url.Action("bar")';
</text>
}
</script>
Its not clean to call JavaScript from controller. Instead, move the logic of checking if its a last item to the client side and call appropriate controller action as appropriate.