Update HTML page after jquery.click - javascript

I have an onclick function which basically just returns sorted data like following:
$(document).ready(function () {
$(".feedbackClick").click(function () {
$.post("/Analyze/GetSortedByFeedback")
.done(function (data) {
var sellers = $('<table />').append(data).find('#tableSellers').html();
$('#tableSellers').html(sellers);
});
});
});
});
And this is how the table looks like that I'm trying to update after the jquery post:
<table id="tableSellers" class="table table-striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-title"><h4><i class="fa fa-user" style="text-align:center"></i> <span>Username</span></h4> </th>
<th class="column-title"> <h4><span class="glyphicon glyphicon-tasks salesClick" aria-hidden="true"></span></h4></th>
<th class="column-title"><h4><i class="fa fa-star feedbackClick"></i></h4></th>
</tr>
</thead>
<tbody>
#foreach (var item in ViewBag.rezultati)
{
<tr>
<td>#item.StoreName</td>
<td>
<b>
#item.SaleNumber
</b>
</td>
<td><b>#item.Feedback</b></td>
</tr>
}
</tbody>
</table>
The click would basically just fetch the results and update the table in HTMl...
Can someone help me out?
Edit:
This current method doesn't works... I trigger the event but nothing happens... The code in the Action is called properly, but the results aren't displayed...
Edit 2:
This is the content of the data object after .done:
System.Collections.Generic.List`1[WebApplication2.Controllers.ResultItem]
Edit 3:
This is the action:
public List<ResultItem> GetSortedByFeedback()
{
return lista.OrderByDescending(x => x.Feedback).ToList();
}
Edit4 this is the data after the Alexandru's post:
Array[100]
Now I can do:
data[0].Feedback
And this outputs in console:
61259

Please use this:
public JsonResult GetSortedByFeedback()
{
var list=lista.OrderByDescending(x => x.Feedback).ToList();
return Json(list);
}
If your method is GET please use this:
public JsonResult GetSortedByFeedback()
{
var list=lista.OrderByDescending(x => x.Feedback).ToList();
return Json(list,JsonRequestBehavior.AllowGet);
}
Then please use this:
.done(function (data) {
$('#tableSellers tbody').empty();
$.each(data,function(i,item){
var tr='<tr><td>'+item.StoreName+'</td><td><b>'+item.SaleNumber+'</b></td><td><b>'+item.Feedback+'</b></td></tr>';
$('#tableSellers tbody').append(tr);//append the row
});
});

What you are trying to do is actually appending a JSON data to a HTML element which is of course will not work as expected.
Consider using a template engine like jQuery Templates. You will be able to compile a HTML template and use it to render your data whenever you need. For example:
var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";
// Compile the markup as a named template
$.template( "movieTemplate", markup );
$.ajax({
dataType: "jsonp",
url: moviesServiceUrl,
jsonp: "$callback",
success: showMovies
});
// Within the callback, use .tmpl() to render the data.
function showMovies( data ) {
// Render the template with the "movies" data and insert
// the rendered HTML under the 'movieList' element
$.tmpl( "movieTemplate", data )
.appendTo( "#movieList" );
}

TRy something like this:
$(document).ready(function () {
$("body").on("click",".feedbackClick",function() {//delegate the click event
$.get("/Analyze/GetSortedByFeedback",function(data) {
var sellers = $(data).find('#tableSellers').html();//find the table and take the html
$('#tableSellers').html(sellers);//append the html
});
});
});
Note: you need to return html (in your case) from the ajaxed page
from #Alexandru partial response you can do the following
public JsonResult GetSortedByFeedback()
{
var list=lista.OrderByDescending(x => x.Feedback).ToList();
return Json(list,JsonRequestBehavior.AllowGet);
}
js:
$(document).ready(function () {
$("body").on("click",".feedbackClick",function() {//delegate the click event
$.get("/Analyze/GetSortedByFeedback",function(data) {
$('#tableSellers tbody').empty();//empty the table body first
$.each(data,function(i,item){//loop each item from the json
$('#tableSellers tbody').append('<tr><td>'+item.StoreName+'</td><td><b>'+item.SaleNumber+'</b></td><td><b>'+item.Feedback+'</b></td></tr>');//build and append the html
});
});
});
});

Related

Ajax paging is duplicating _layout page while using pagination to replace page content

I am using x.PagedList to use pagination in my ASP.NET MVC page. The only problem I have with the plugin is , it used a page refresh when I navigate between pages.
To avoid that I am using jQuery calls to replace page contents as explained in this article.
My View and javascript looks like this.
<div id="circuitsContent">
<table class="table">
<tr>
--Header
</tr>
#foreach (var item in Model)
{
<tr>
--Loop through and create content
<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>
</div>
<div id="circuitContentPager">
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Circuits", new { page }))
</div>
#section scripts
{
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$(document).on("click", "#circuitContentPager a[href]", function () {
$.ajax({
url: $(this).attr("href"),
type: 'GET',
cache: false,
success: function (result) {
$('#circuitsContent').html(result);
}
});
return false;
});
});
</script>
And this is my controller code:
public ActionResult Circuits(int? page)
{
var pageNumber = page ?? 1;
var circuits = _repo.GetAllCircuits().OrderBy(circ=>circ.ID).ToList();
var pagedCircuits = circuits.ToPagedList(pageNumber, 25);
return View(pagedCircuits);
}
What am I missing here?
Your ajax call returns the html from Circuits() method which is the same view you have used to render the page initially, which includes all the initial html, but you only replacing part of of the existing page, so elements such as the paging buttons generated by the #Html.PagedListPager() method are going to be repeated. Your also generating invalid html because of duplicate id attributes (you will have multiple <div id="circuitsContent"> elements
There are 2 ways you could solve this.
Create a separate controller method that returns a partial view of just the <table> and call that method, however you would need to extract the value of the page number for the href attribute of you pager buttons to pass that as well.
Using your current Circuits() method, test if the request is ajax, and if so, return a partial view of just the <table>.
public ActionResult Circuits(int? page)
{
var pageNumber = page ?? 1;
var circuits = _repo.GetAllCircuits().OrderBy(circ=>circ.ID);
var pagedCircuits = circuits.ToPagedList(pageNumber, 25);
if (Request.IsAjaxRequest)
{
return PartialView("_Circuits", pagedCircuits);
}
return View(pagedCircuits);
}
Note: Do not use .ToList() in your query. That is defeating the whole purpose of using server side paging because .ToList() immediately downloads all the records fro the database.
Where _Circuits.cshtml would be
#model IEnumerable<yourModel>
<table class="table">
<thead>
<tr>
// <th> elements
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
.... // Loop through and create content
</tr>
}
</tbody>
</table>
Note that your header elements should be in a <thead> element and the records in a <tbody> element.

reload datatable after ajax success

I use JQuery DataTable. I send data to datatable onclick in json file at ajax succes .the first click everything is good,But the next click I get only the right data ANd wrong value of dataTables_info it display always the first value of dataTables_info And paginatio AND row too from the first result.
This is the first display of data in datatable:
ALL the next Click I get only right data:
For this exemple they are one result showing in picture below but everything else(info ,show,pagination) belong to first search showing in the first picture :
In the second Exemple When I click at any page of pagination I get the content of the first page result!!
This is my function ONclick:
$ ( '#ButtonPostJson' ).on('click',function() {
$("tbody").empty();
var forsearch = $("#searchItem").val();
$.ajax({
processing: true,
serverSide: true,
type: 'post',
url: 'searchData.json',
dataType: "json",
data: mysearch,
/* bRetrieve : true,*/
success: function(data) {
$.each(data, function(i, data) {
var body = "<tr>";
body += "<td>" + data.name + "</td>";
..........................
..........................
body += "</tr>";
$('.datatable-ajax-source table').append(body);
})
;
/*DataTables instantiation.*/
$('.datatable-ajax-source table').dataTable();
},
error: function() {
alert('Processus Echoué!');
},
afterSend: function(){
$('.datatable-ajax-source table').dataTable().reload();
/* $('.datatable-ajax-source table').dataTable({bRetrieve : true}).fnDestroy();
$(this).parents().remove();
$('.datatable-ajax-source table').dataTable().clear();*/
}
});
});
I try everything and i dont know what I miss.
I use this jquery for datatable:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
Thanks.
Use like it
$('#product_table').DataTable().ajax.reload();
Get table id first, like:
var table=('#tableid').Datatable();
table.draw();
just put these lines after ajax success function to reload datatable
On a button clik you dont need to empty your table body and make initiate the datatable again with the ajax.
you just have to call your ajax again as you have already initiate on document ready function
just use
$("#Table_id").ajax.reload();
check the below link, you will have better idea.
https://datatables.net/reference/api/ajax.reload()
Let me know if this doesn't help you
I had this same problem. I found a function I wrote on a project that deals with this. Here is a simple 2 column table I made.
<table id="memberships" class="table table-striped table-bordered table-hover" width="100%">
<thead>
<tr>
<th>Member Name</th>
<th>Location</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Member Name</th>
<th>Location</th>
</tr>
</tfoot>
</table>
This is my script to populate it:
function drawTable(){
var table = $('#memberships').DataTable();
table.destroy();
value = $("#memberName").val();
console.log("member name-->>" + value);
$('#memberships').DataTable({
responsive:true,
pageLength: 50,
ajax:{
"url": `//BACKEND API CALL`,
"type":"get",
"dataSrc": 'members'//my data is in an array called members
},
columns: [
{"data": "name_display" },
{"targets": 0,
"data": "membershipID",
"render": function ( data, type, full, meta ) {
return '<button type="button" class="btn btn-info btn-block"
onclick="editMember(' + data + ')">Edit Member</button><button
type="button" class="btn btn-danger btn-block"
onclick="deleteMember(' + data + ')">Delete</button>';
}
}
]
});
$.fn.dataTable.ext.errMode = 'none';
}
You can ignore my column render function. I needed 2 buttons based on the data returned. The key was the table.destroy in the function. I created the table in a variable called table. I destroy it right in this initialization because it allowed me to use this same function over and over. The first time it destroys an empty table. Each call after that destroys the data and repopulates it from the ajax call.
Hope this helps.
Update: After playing with datatables alot more I found that setting table to a variable in a global scope to your function allows you to use reload.
var table = $('#memberships').DataTable({});
Then
table.ajax.reload();
should work.
I created this simple function:
function refreshTable() {
$('.dataTable').each(function() {
dt = $(this).dataTable();
dt.fnDraw();
})
}
use below code..it perfectly work, it keep your pagination without lose current page
$("#table-example").DataTable().ajax.reload(null, false );
$('.table').DataTable().ajax.reload();
This works for me..
$("#Table_id").ajax.reload(); did not work.
I implemented -
var mytbl = $("#Table_id").datatable();
mytbl.ajax.reload;
.reload() is not working properly untill we pass some parameter
var = $("#example").DataTable() ;
datatbale_name.ajax.reload(null, false );
Try This i hope it will work
$("#datatable_id").DataTable().ajax.reload();

MVC 4: Create HTML textboxes dynamically with JQUERY and PartialViewResult. How to fill the model if the code is added dynamically?

I am creating form input fields with JQUERY like
$('#students').live('change', function () {
var value = $(this).val();
if (value) {
$.ajax({
type: "GET",
timeout: 10000,
url: "#Url.Action(MVC.Company.ManageWorkReport.GetStudent())",
data: { studentId: value },
cache: false,
success: function (data) {
if (data) {
$("#students tbody").html(data);
}
},
error: function (xhr, status, error) {
alert(xhr.responseText);
}
});
}
return false;
});
HTML code to insert data is
#using (Html.BeginDefaultForm(MVC.Company.ManageWorkReport.Create()))
{
<table class="table table-striped table-bordered bootstrap-datatable datatable" id="students">
<thead>
<tr>
<th>Ime in Priimek</th>
<th>Vrsta</th>
<th>Začetek dela</th>
<th>Konec dela</th>
<th>Enota</th>
<th>Cena za enoto</th>
<th>Količina</th>
<th>Neto znesek</th>
<th>Bruto znesek</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="11">Podatek še ne obstaja</td>
</tr>
</tbody>
</table>
#Html.SimpleSubmitAndCancelButton(Translations.Global.SAVE, Translations.Global.CANCEL)
}
and C#
[HttpGet]
public virtual PartialViewResult GetStudent(int studentId)
{
StudentsWorksReportsFormModel studentsWorksReportsFormModel = new StudentsWorksReportsFormModel();
.....
var view = PartialView("StudentWorkReportResult", studentsWorksReportsFormModel);
return view;
}
Problem is that when I enter data in form and click SUBMIT button model is always empty. Why model is empty if I fill page with JQUERY and later enter data in text fields? How to fill the model also that I can insert data in DB.
In order for the model binder to pick you new values up you will need to set the name property of the controls.
Each item needs to be indexed and set with the property name.
So for example if your collection was MyCollection to set a Name property on the first item you would add the following:
Name="MyCollection[0].Name"
The second etc:
Name="MyCollection[1].Name"
The Features and Foibles of ASP.NET MVC Model Binding
You will need to loop through your collection if you are returning a partial view, something like this:
#for(i = 0; i < Model.StudentWorkReportFormModel.Count; i++)
{
#Html.TextBoxFor(modelItem => Model.StudentWorkReportFormModel[i].StartDate})
}

partial view is not display back anything error 404 is generated

I am trying to fix this problem I got an error 404 on the partial view path url: localhost:49259/Panier/TableContent. This TableContent is under the Panier folder.
I can't figure out what is wrong with the URL.
Does the TableContent should be under this folder ViewModels instead since it is using this model
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel?
Thanks
TableContent.cshtml (partial view) from Panier
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Table Content";
}
<a href="#" class="TableContent">
<table>
<tr>
<th>
Produit
</th>
<th>
Prix (unitaire)
</th>
<th>
Quantite
</th>
<th></th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr id="row-#item.ProduitId">
<td>
#Html.ActionLink(item.Produit.Description, "Details", "Produit", new { id =
item.ProduitId }, null)
</td>
<td>
#item.Produit.Prix
</td>
<td id="item-count-#item.PanierId">
#item.Quantite
</td>
<td>
<a href="#" class="RemoveLink" data-id="#item.PanierId"> Enlever du panier
</a>
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
</a>
Index.cshtml from Panier
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$('.RemoveLink').click(function () {
$.ajax({
url: '/Panier/RemoveFromCart',
data: { id: $(this).data('id') },
type: 'POST',
cache: false,
success: function (result) {
$('#row-' + result.DeleteId).remove();
$('#row-' + result.DeleteId).fadeOut('slow');
$('#cart-status').text('Cart (' + result.CartCount + ')');
$('#update-message').text(result.Message);
$('#cart-total').text(result.CartTotal);
$.get("/Panier/TableContent").done(function (data) { <==error 404
$("#TableContent").html(data); });
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
return false;
});
});
</script>
<h3>
<em>Details</em> du panier:
</h3>
<p class="button">
#Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<div id="table-content">
#Html.Partial("TableContent") <=== partial view call
</div>
PanierController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tp1WebStore3.Models;
using Tp1WebStore3.ViewModels;
namespace Tp1WebStore3.Controllers
{
public class PanierController : Controller
{
//
// GET: /Panier/
Tp1WebStoreDBEntities dbProduit = new Tp1WebStoreDBEntities();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
// Set up our ViewModel
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
// Return the view
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
// Retrieve the album from the database
var addedProduit = dbProduit.Produits
.Single(produit => produit.ProduitId == id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedProduit);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
//
// AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
string produitDescription = dbProduit.Paniers
.Single(item => item.PanierId == id).Produit.Description;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(produitDescription) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
/* return View("CartSummary"); */
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
}
}
You'll want to keep your partial view inside the view folder (not view models)... the specific subdirectory is up to you but I believe it will default to looking in shared.
I'd suggest specifying more of the URL when you call the partial view and see if that fixes your issue...
For Example:
Html.Partial("~/Views/Shared/TableContent.cshtml")
More Info Here:
Render partial from different folder (not shared)
Ok I realize I misunderstood the question and the 404 was being generated by the script call not the #Html.Partial at the bottom of the file.
I'm going by this snippet from the comments...
$.get("~/Views/Shared/TableContent").done(function (data) { $("#TableContent").html(data); });
I see two issues here... First is that you are going to want to resolve your path differently as the "~" operator isn't going to help in javascript. You can use #url.Action("TableContent") in this case to get the actual url on the server and pass it in to your get statement.
The second issue is that I believe TableContent is just a view without a corresponding action. This is fine for rendering inline with a Html.Partial, however the server isn't going to be able to render it outside of that context. You'll want to add a corresponding action and call that instead from your ajax.
Your controller, Panier, doesn't seem to have a method called TableContent which should return the partial view TableContent.cshtml.
Also, when you refer the urls, try to use the Url.Action in the ajax / get calls:
url: '/Panier/RemoveFromCart',
Should be:
url: '#Url.Action("RemoveFromCart","Panier")',
Another way of solving this is to create an action TableContent in the Panier Controller which would call the partial view TableContent. The TableContent.cshtml should be in the same directory as Index (ie /Views/Panier)
public PartialViewResult TableContent()
{
return PartialView("TableContent");
}
You'll then need to replace a line in the ajax call
$.get("/Panier/TableContent")
becomes
$.get('#Url.Action("TableContent", "Panier")')

Refreshing list after ajax call with Knockout JS

I have a list of attachments on a page which is generated using a jQuery $.ajax call and Knockout JS.
My HTML looks like (this is stripped back):
<tbody data-bind="foreach: attachments">
<tr>
<td data-bind="text: Filename" />
</tr>
</tbody>
I have a function that gets the list of attachments which is returned as a JSON response:
$(function () {
getFormAttachments();
});
function getAttachments() {
var request = $.ajax({
type: "GET",
datatype: "json",
url: "/Attachment/GetAttachments"
});
request.done(function (response) {
ko.applyBindings(new vm(response));
});
}
My view model looks like:
function vm(response) {
this.attachments = ko.observableArray(response);
};
There is a refresh button that the use can click to refresh this list because over time attachments may have been added/removed:
$(function () {
$("#refresh").on("click", getAttachments);
});
The initial rendering of the list of attachments is fine, however when I call getAttachments again via the refresh button click the list is added to (in fact each item is duplicated several times).
I've created a jsFiddle to demonstrate this problem here:
http://jsfiddle.net/CpdbJ/137
What am I doing wrong?
Here is a fiddle that fixes your sample. Your biggest issue was that you were calling 'applyBindings' multiple times. In general you will call applyBindings on page load and then the page will interact with the View Model to cause Knockout to refresh portions of your page.
http://jsfiddle.net/CpdbJ/136
html
<table>
<thead>
<tr><th>File Name</th></tr>
</thead>
<tbody data-bind="foreach: attachments">
<tr><td data-bind="text: Filename" /></tr>
</tbody>
</table>
<button data-bind="click: refresh">Refresh</button>
javascript
$(function () {
var ViewModel = function() {
var self = this;
self.count = 0;
self.getAttachments = function() {
var data = [{ Filename: "f"+(self.count*2+1)+".doc" },
{ Filename: "f"+(self.count*2+2)+".doc"}];
self.count = self.count + 1;
return data;
}
self.attachments = ko.observableArray(self.getAttachments());
self.refresh = function() {
self.attachments(self.getAttachments());
}
};
ko.applyBindings(new ViewModel());
});
--
You may also want to look at the mapping plugin - http://knockoutjs.com/documentation/plugins-mapping.html. It can help you transform JSON into View Models. Additionally it is able to assign a property to be the "key" for an object... this will be used to determine old vs new objects on subsequent mappings.
Here is a fiddle I wrote a while back to demonstrate a similar idea:
http://jsfiddle.net/wgZ59/276
NOTE: I use 'update' as part of my mapping rules, but ONLY so I can log to the console. You would only need to add this if you wanted to customize how the mapping plugin updated objects.

Categories

Resources