I have an interesting problem while reloading partial views with ajax. I have a following setup in the master View:
<div>
<div id="items">
#Html.Partial("SubView", Model.Items);
</div>
<div>
SubView is generally a list of items in a table as follows:
<table class="table table-striped">
<tr>
<th>Date</th>
<th>Time</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
#Html.HiddenFor(modelItem => item.Id)
<td>#Html.DisplayFor(modelItem => item.Date)</td>
<td>#Html.DisplayFor(modelItem => item.Time)</td>
<td>
#Html.ActionLink("Delete", "Delete", new { itemId= item.Id, page = Model.PageNumber }, new { #class = "deleteItem" })
</td>
</tr>
}
DeleteItem Action in the controller does basically the following:
[HttpDelete]
public ActionResult DeleteItem(int itemId, int page)
{
this.dbService.DeletItem(expenseId);
return PartialView("SubView", this.GetPagedList(page));
}
In the script that I refer in the master View I have the following code:
$(document).ready(function () {
// delete expense
$(".deleteItem").click(function () {
$.ajax({
url: this.href,
type: 'delete',
success: function (result) {
$("#items").html(result);
}
});
return false;
});
This works fine the first time, but the second time it only loads the partial View -> since the JavaScript code is not being executed...
I am relatively new to that stuff and I am a bit confused what's going on here.
All 3rd party scripts are rendered in the Layout.cshtml
You can't attach a .click() event to a dynamically generated item. You have to structure it this way:
$(document).on('click', '.deleteItem', function() {
// Deletey stuff here.
});
For partial views to render, you have to make the return type PartialViewResult rather than ActionResult. Because ActionResult causes a redirection.
Try editing your DeleteItem function like this.
[HttpDelete]
public PartialViewResult DeleteItem(int itemId, int page)
{
this.dbService.DeletItem(expenseId);
return PartialView("SubView", this.GetPagedList(page));
}
Related
I am attempting to use partial views for the first time and I need some help. I am posting a string from Javascript to my ASP controller so that I can query my database using that string. Like so:
JavaScript
function findEmployees(userCounty) {
$.ajax({
type: "POST",
url: '#Url.Action("Index", "Contact")',
data: JSON.stringify(userCounty),
contentType: "application/json",
error: function (e) {
console.log(e)
console.log("error")
}
});
}
Controller
[HttpPost]
public ActionResult Index([FromBody]string userCounty)
{
string county = userCounty.Substring(0, userCounty.IndexOf(" "));
var query = from SOP in _context.SalesOffice_Plant
where SOP.County == county
select new SalesOffice_Plant
{
Employee = SOP.Employee
};
return PartialView(query.ToList());
}
[HttpGet]
public ActionResult Index()
{
ViewData["Title"] = "Contact Us";
ViewBag.Current = "Contact";
return View();
}
When I set break points - I can see that the string is passed correctly and my LINQ query works just fine. My problem occurs when I want to render a table of the employees in my Index page. The JavaScript returns a value to the controller after the page loads. This means I needed a way to "refresh the page". I was told to use a partial view to solve this problem and this is what I came up with.
Index.cshtml
#model IEnumerable<Project.Models.SalesOffice_Plant>
//A bunch of Html
#await Html.PartialAsync("_IndexPartial")
//More Html
_IndexPartial.cshtml
#model IEnumerable<Project.Models.SalesOffice_Plant>
<table class="table">
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Employee)
</td>
</tr>
}
</tbody>
Ideally, I would like a table of Employees to be generated and displayed in the Index.cshtml. However, when I load the page I get and error telling me that my #await Html.PartialAsync("_IndexPartial") 'is not set to an instance of an object.
Any pointers in the right direction would be very helpful.
When you use ajax,it would not reload your page after backend code finishing,so you need to use .html() method to render the backend result to html.
Here is a whole working demo:
Model:
public class SalesOffice_Plant
{
public int Id { get; set; }
public string County { get; set; }
public string Employee { get; set; }
}
View(Index.cshtml):
<button type="button" onclick="findEmployees('a ')">Find</button>
<div id="employee">
</div>
#section Scripts
{
<script>
function findEmployees(userCounty) {
$.ajax({
type: "POST",
url: '#Url.Action("Index", "Contact")',
data: JSON.stringify(userCounty),
contentType: "application/json",
error: function (e) {
console.log(e)
console.log("error")
},
success: function (res) {
$("#employee").html(res); //add this...
}
});
}
</script>
}
Partial View(_IndexPartial.cshtml):
#model IEnumerable<SalesOffice_Plant>
<table class="table">
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Employee)
</td>
</tr>
}
</tbody>
</table>
Controller:
[HttpPost]
public ActionResult Index([FromBody] string userCounty)
{
string county = userCounty.Substring(0, userCounty.IndexOf(" "));
var query = from SOP in _context.SalesOffice_Plant
where SOP.County == county
select new SalesOffice_Plant
{
Employee = SOP.Employee
};
return PartialView("_IndexPartial", query.ToList()); //must specify the partial view name
//otherwise it will match the action name as partial view name
}
[HttpGet]
public ActionResult Index()
{
ViewData["Title"] = "Contact Us";
ViewBag.Current = "Contact";
return View();
}
Result:
This is my /Books/userHome view:
#model CSBSTest.Models.tbl_Book
#{
ViewBag.Title = "UserHome";
Layout = "~/Views/Shared/_Profile.cshtml";
}
<h2>Books for sale by CUST Students</h2>
<br />
<br />
<table id="books" class="table table-bordered table-hover">
<thead>
<tr>
<th>Id</th>
<th>Book Name</th>
<th>Author</th>
<th>Version</th>
</tr>
</thead>
<tbody></tbody>
</table>
#section scripts
{
<script>
$(document).ready( function () {
var dataTable = $("#books").DataTable({
ajax: {
url: "/Book/GetBooks",
dataSrc: ""
},
columns: [
{
data:"Id"
},
{
data: "Name"
},
{
data: "Author"
},
{
data: "Version"
}
]
});
});
</script>
}
I am calling /Books/GetBooks as below:
public ActionResult UserHome()
{
return View();
}
public ActionResult GetBooks()
{
var list = _context.tbl_Book.ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
The GetBooks returns json result which is called from UserHome scripts section as shown above, I want to populate the list returned by /Books/GetBooks into jquery datatable but its gives the following exception:
.
any help will be highly appreciated thanks in advance.
var list = _context.tbl_Book.ToList();
Here "list" is database table object and you should not return it directly.
Use user defined model and than return it
public class customModel{
//properties
}
var list = _context.tbl_Book.ToList();
List<custommodel> test = list.select(a=>new custommodel{
//assingn properties
});
return Json(test , JsonRequestBehavior.AllowGet);
I am trying to build page that shows all selected movies depending on genre,
with $.post
If genre is not selected page should show all movies.It is default selection.
This is Controller code:
public class BrowseController : Controller
{
private MovieContext context = new MovieContext();
// GET: Browse
public ActionResult Index()
{
ViewBag.Genres = context.Genre.ToList();
IEnumerable<Movie> mov = TempData["movies"] as IEnumerable<Movie>;
if (mov == null)
{
IEnumerable<Movie> movies = context.Movies.ToList();
return View(movies);
}
return View(mov);
}
[HttpPost]
public ActionResult Index(int id = -1)
{
IEnumerable<Movie> model;
if (id != -1)
{
model = context.Movies.Where(x => x.GenreId == id);
}
else
{
model = context.Movies.ToList();
}
ViewBag.Genres = context.Genre.ToList();
TempData["movies"] = model;
return RedirectToAction("", "Browse");
}
}
And this is the view code:
#model IEnumerable<Movies.Models.Movie>
#using Movies.Models
#{
ViewBag.Title = "Index";
var Movie = Model.FirstOrDefault();
List<Genre> Genres = ViewBag.Genres;
}
#Html.DropDownListFor(m => Movie.GenreId, new SelectList(Genres, "Id",
"Name"), "")
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Rating)
</th>
<th>
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td></td>
</tr>
}
</table>
#section Scripts{
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script>
$('select#Movie_GenreId').on('change', function () {
var value = $(this).find(':selected').val();
var url = "/Browse/Index";
$.post(url, { id: value });
});
</script>
}
I checked Chrome Debugging tool and Network tab and I see in Preview tab of response that there are no errors and Get Browse/Index action is returning expected results but I don't see them in View. Not sure why.
You make a POST request , but you don't handle the response. For instance, you forget to update the DOM structure.
For doing this, you have to attach a callback function to the returned response.
$.post(url, { id: value },function(response){
//here is request response
});
Also, when you use AJAX, the purpose is to update DOM without refresh page to see the updates.
The solution is to return a JSON object with all the informations and then, handle them in the callback function of $.post method.
I am trying to make some blocks of code work from a blank MVC project (no authentication) before applying its logic to my actual project but I can't seem to do it right. I'm trying to have a table in a partial view to reload/refresh/update itself every certain span of time so it'll reflect any changes that was made and that happened in another webpage/browser.
The snippet that fires a function every few second work but the rendering/refreshing is where it gets trippy. I've been following this example with no luck (Refresh Partial View Div in MVC 5).
Here are my code:
View(Index.cshtml)
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div id="peopletablediv">
#{ Html.RenderAction("Person");}
</div>
Partial View (Person.cshtml)
#model IEnumerable
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
Controller(PeopleController.cs)
public class PeopleController : Controller
{
private WebApplication1Context db = new WebApplication1Context();
// GET: People
public ActionResult Index()
{
return View();
}
public ActionResult Person()
{
return PartialView(db.People.ToList());
}
}
JavaScript(within the index.cshtml only since I'm just testing)
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(document).ready(function () {
var url = '#Url.Action("Person")';
var div = $("#peopletablediv");
setInterval(function () {
div.load(url);
}, 2000);
});
</script>
I've only a few months experience in asp.net MVC and web development in general. Which part would I be getting wrong here?
I have a "Details" View that I am displaying to the user to find out if any statuses are associated with any projects.
When the "GET" for the "Details" view is performed, only a dropdownlist appears asking the user to select an item from the list. In the View, I simply check if the "Model" is null to display the rest of the view or not (the associated projects for that status).
During the "POST", a "status" is retrieved with its associated 'projects'. While coming back into the View, I am expecting the Model not to be null (since it found a status and its associated projects).
If the Model is not null, I want to display the rest of the View.
In the "POST", why is the Model still null? See below code & screenshots. Please copy and paste the screenshot to your favorite image viewer for better viewing.
fyi, after looking in the browser with the debugging tool, I can see that there is no html displayed after the dropdownlist?????
Model
namespace YeagerTechDB.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
[Serializable, DataContract(IsReference = true)]
public partial class Status
{
public Status()
{
Projects = new HashSet<Project>();
}
[Key]
[ScaffoldColumn(true)]
[DataMember]
public short StatusID { get; set; }
[Required]
[StringLength(30)]
[Display(Name = "Status")]
[DataMember]
public string StatusDescription { get; set; }
[DataMember]
public virtual ICollection<Project> Projects { get; set; }
}
}
JS
$.ajax({
url: Url,
data: JSON.stringify(status_Input),
//data: AddAntiCSRFToken(JSON.stringify(status_Input)),
dataType: "html",
type: "POST",
contentType: "application/json; charset=utf-8",
async: true,
beforeSend: function ()
{
$('<div id="divLoadMsg" style="text-align:center"><img src="~/Content/progress.gif" /><br/><b>Please wait...</b></div>').dialog({
modal: true, resizable: false, height: 'auto', width: 'auto', minHeight: '30px',
open: function () { $('.ui-dialog-titlebar').hide(); }, close: function () { $('.ui-dialog-titlebar').show(); $(this).dialog('destroy').remove() }
});
},
success: function (data, status)
{
if (status == "success")
{
// Retrieved data
}
},
CONTROLLER
// GET: Statuses/StatusProjects/Details
public ActionResult Details()
{
return View();
}
// POST: Statuses/StatusProjects/Details/5
[HttpPost]
public async Task<ActionResult> Details(short? id)
{
if (id == null)
{
return View("IDIsNull");
}
Status status = await db.GetProjectsByStatusIDAsync(id);
if (status == null)
{
return View("ObjectModelNull");
}
return View();
}
VIEW
#model YeagerTechDB.Models.Status
#using YeagerTechDB.ViewModels.Statuses
#{
ViewBag.Title = "Statuses";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>Select Status to see associated Projects</h3>
<div>
#Html.Partial("_SelectStatusProjects", new StatusesDDL());
</div>
#if (Model != null) // Needed for GET
{
<div>
<table class="table table-condensed">
<tr>
<th>
Associated Projects for selected Status
</th>
<th></th>
</tr>
<tr>
<th align="right">Project ID</th>
<th>Project Description</th>
<th>Project Name</th>
<th align="right">Quote</th>
<th>Notes</th>
<th>Created Date</th>
<th>Updated Date</th>
</tr>
<tbody>
#foreach (var item in Model.Projects)
{
<tr>
<td align="right">
#Html.DisplayFor(m => item.ProjectID)
</td>
<td>
#Html.DisplayFor(m => item.Description)
</td>
<td>
#Html.DisplayFor(m => item.Name)
</td>
<td align="right">
#Html.DisplayFor(m => item.Quote)
</td>
<td>
#Html.DisplayFor(m => item.Notes)
</td>
<td>
#Html.DisplayFor(m => item.CreatedDate)
</td>
<td>
#Html.DisplayFor(m => item.UpdatedDate)
</td>
</tr>
}
</tbody>
</table>
</div>
}
EDIT
After making the change that Kundan suggested, I can tell during debugging, if I step through the code, it goes into the View after the POST. The Model is not null and it then properly cycles through the child records that I want displayed on the screen.
However, after that is finished, those records are not displayed on the browser window! The only thing that appears is the dropdownlist again without any display beneath that.
Nothing else is executed after the debugging of the View on the POST which is correct.
The only change that was made in this process is returning the object model of the View (status) as Kundan suggested.
How come the records are not being displayed in the browser after the POST?
fyi, after looking in the browser with the debugging tool, I can see that there is no html displayed after the dropdownlist?????
fyi, I also tried running the page without the dropdownlist and forcing in a value during debugging which would bring back some projects, the same way as if I had selected it from the drop down list. Even with the html removed for the dropdownlist, it went through the View cycled through the collection, but did not emit any html?
Here are the screen shots...
The Model is null because you didn't pass back it to View from your controller. The code should be like below:
[HttpPost]
public async Task<ActionResult> Details(short? id)
{
if (id == null)
{
return View("IDIsNull");
}
Status status = await db.GetProjectsByStatusIDAsync(id);
if (status == null)
{
return View("ObjectModelNull");
}
return View(status);
}
This will fix your issue.