Making a button visible based on number of records in datatable - asp.net-mvc

I am using jquery datatable in asp.net mvc and i want to show a submit button which will be saving the data to the database only if there is atleast one row in the datatable.
I am trying this code, however its not working
<tr id="trbtnSubmit">
<td colspan="9" align="center">
<input type="submit" name="btnSubmit" value="Save"
class="btn btn-edit btn-text" />
</td>
</tr>
<script>
var PopUp, dataTable;
$(document).ready(function () {
dataTable = $("#tblCustomerList").DataTable({
"ajax": {
"url": "/Customer/GetCustomers",
"type": "GET",
"data": "json"
},
"lengthChange": false,
"pageLength": 10,
"columns": [
{ "data": "Number" },
{ "data": "Name" },
{ "data": "fileName" },
{ "data": "mD5Hash" },
{ "data": "dataSizeInGB" },
{
"data": "Id",
"render": function () {
return "<a href='#'><i class='fa fa-eye'></a></i><a href='#' style='margin-left:5px'><i class='fa fa-pencil'></i></a><a href='#' style='margin-left:5px'><i class='fa fa-trash'></a></i>";
},
"orderable": false,
"width": "40px"
},
],
"language": {
"emptyTable": "No Customers , click on <b>New Customer</b> to add Customers"
}
});
var table = $('#tblCustomerList').DataTable();
if (!table.data().any()) {
$('#trbtnSubmit').hide();
} else {
$('#trbtnSubmit').show();
}
});
</script>

Since you didn't specify the version of datatables, I assume it's v1.10.
And there are 2 side notes I want to make before going into your problem:
Difference between .datatable() and .DataTable()
Enable server-side processing
Difference Between .datatable() and .DataTable()
I saw you declared another variable, var table, at the bottom of your sample code to get another instance of DataTables and check if there is any data? You actually don't need to.
.DataTable() returns a DataTables API instance, while .datatable() returns a jQuery object.
So if you intent to make usages on the DataTables APIs after you initialize the table, you can just use the varirable you declared from the beginning, var dataTable since you used .DataTable() way.
Enable Server-side Processing
Server-side processing is enabled by turning on the serverSide option, and configuring the ajax option. You're missing the first one, whose default is false.
So you might need to add serverSide option in your code:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
ajax: {
...
},
...
});
Enough said. Now looking at your problem ...
DataTables Callbacks
There are many ways to achieve what you want to do, and I like to use callbacks so that you can configure your DataTables in one place.
There are lots of callbacks you can use, and the one I would use is drawCallback:
dataTable = $("#tblCustomerList").DataTable({
serverSide: true,
...,
language: {
emptyTable: "No Customers , click on <b>New Customer</b> to add Customers"
},
drawCallback: function(settings) {
$('#trbtnSubmit').toggle(settings.aoData.length > 0);
}
});
Hopefully my code is readable enough without any additional explanations :)

Related

How can I include custom variables in AMP analytics?

A few months ago we introduced AMP to our Rails application. Our implementation includes the following:
<amp-analytics type="googleanalytics">
<script type="application/json">
{
"vars": {
"account": <%= ga.profile_code.inspect.html_safe %>
},
"triggers": {
"trackPageview": {
"on": "visible",
"request": "pageview"
}
}
}
</script>
</amp-analytics>
However, we now realise that we are missing some important custom variables that are used in the Google Analytics script for our non-AMP pages. These are set within a script as follows (where _gaq is an array):
<% ga.variables.each do |vars| %>
_gaq.push([ '_setCustomVar', <%= vars[:placement] %>, '<%= vars[:label] %>', '<%= vars[:variable] %>', <%= vars[:scope_number] %> ]);
<% end %>
Is it possible in AMP Analytics to set custom variables without any restriction on the variable names? If so, how?
You should notice that Custom Variables are only available for legacy google analytics tracking. For the latest implementation, you will need to replace your custom variables with custom dimensions instead. You could check the migration guide Here and Here.
After you have made a migration, you can check the implementation of sending custom dimensions and custom metrics in AMP page.
For example, you can send a custom dimension with a pageview by
including the Custom Dimension parameter (or any other parameters you
want to include with the hit) in the extraUrlParams section. This
section can be included at the trigger level for single requests or at
a global level to send the data with all requests.
<amp-analytics type="googleanalytics">
<script type="application/json">
{
"vars": {
"account": "UA-XXXXX-Y"
},
"extraUrlParams": {
"cd3": "AMP"
},
"triggers": {
"trackPageviewWithCustomData": {
"on": "visible",
"request": "pageview"
},
"trackEvent" : {
"on": "visible",
"request": "event",
"vars": {
"eventCategory": "ui-components",
"eventAction": "header-click"
},
"extraUrlParams": {
"ni": "1"
}
}
}
}
</script>
</amp-analytics>

Jquery datatable - Inline edit columns and save all details on clicking 'save' button

I am using following Jquery Datatables code:
$(document).ready(function() {
table = DataTable({
"ajax": {
"url" : '/Book/list/' + book_id,
"dataSrc": function(data) {
return data.book_details;
},
"searching": false
"columns": [
{ "data": "id"},
{ "data": "book_name" },
{ "data": "price"},
{ "data": "rank"},
]
});
I want to edit the 'Price' column - Tried editor plugin but since that is not an opensouce plugin, I am not able to use it.
And the second thing i need is :
After editing 'price' column for every row, by clicking save button, it has to save every modified value in datatable.
Anyone please help?

DataTables Error : “Requested unknown parameter”

var headers = [{ "mDataProp": "Agents" },{ "mDataProp": "Buyer" },{ "mDataProp": "Date" }];
$(document).ready(function () {
$('#data-table').dataTable({
"bFilter": false,
"bLengthChange": false,
"iDisplayLength": 25,
"bJQueryUI": true,
"bServerSide": true,
"bProcessing": true,
"sPaginationType": "full_numbers",
"aoColumns": headers,
"sAjaxSource": '/report/TestPaging',
});
});
If I remove the aoColumns from my code the datatable is generated normally, but when I add aoColumns I get :
DataTables warning (table id = 'data-table'): Requested unknown parameter 'Agents' from the data source for row 0
HTML:
<table id="data-table">
<thead>
<tr>
<th>tmp</th>
<th>tmp</th>
<th>tmp</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
How can I configure header names? I need them for my sorting.
Do they have to be same as in "th" tags?
Json response from my controller is ok because it renders fine when I remove aoColumns
I have string[][](var data) with 3 strings in each line and return it as
Json(new{
sEcho = param.sEcho,
iTotalRecords = visitRepository.Query.Count(),
iTotalDisplayRecords = visitRepository.Query.Count(),
aaData = data
}, JsonRequestBehavior.AllowGet);
The error you are experiencing is caused by a mismatch between the contents of the JSON and your aoColumns definition. The names you are targeting in aoColumns must be exactly the same as those in the JSON, and the length of each object in the JSON must be equal to the number of columns in the original HTML table. See the docs for clarification. In your case, the JSON should look like this :
[{
"Agents": "tM4Ga0zX",
"Buyer": "ZKwMEiIa",
"Date": "K3lS2yn9"
},
...]
...And your JSON doesnt follow that scheme. If you are not using aoColumns, then the data is inserted by index, not by name - and that is why it is working for you without it.
You configure header names (titles) by the sTitle property :
aoColumns: [
{ mDataProp: "Agents", sTitle : "Agents" },
{ mDataProp: "Buyer", sTitle : "Buyer" },
{ mDataProp: "Date", sTitle : "Date" }
]
see this demonstration based on your question -> http://jsfiddle.net/kLR7G/

Using Asp.Net C# MVC4 and Json, how can I get my chart to update in line with my paged datatable

I am using datatables and charts. I would prefer to return standard data through the model but cant for some odd reason, and the controls only seem to work with Json. Perhaps it's just my understanding. But at this point I am completely lost.
What I want to do is actually (in theory) quite simple.
Action result 1 returns a table which has paged data to a view as a Json result because that is what datatables require. This works fine.
Here are the controller actionresults for this:
public ActionResult AjaxVitalsHandler()
{
return PartialView();
}
[HttpPost]
[AccessRequired(AccessFeature.Vitals, AccessLevel.Read)]
public ActionResult AjaxVitalsHandler(JQueryDataTableParamModel param)
{
int start = param.iDisplayStart;
int perPage = Math.Min(param.iDisplayLength, 100);
int currentPage = (start / perPage) + 1;
int id = _accountSession.CurrentUserId;
//...Bunch of code here to do basic queries and get the data...All working fine.
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = model.TotalItemCount,
iTotalDisplayRecords = model.TotalItemCount,
aaData = result
});
}
Here is the corresponding partial view (This is a partial view loaded into a main view with RenderAction, nothing special):
<table class="table table-striped table-bordered table-hover"
id="vitalsTable"
data-request-url="#Url.Action("AjaxVitalsHandler")">
<thead>
<tr>
<th class="hidden-480">Date</th>
<th class="hidden-480">Weight (kg)</th>
<th class="hidden-480">Height (cm)</th>
<th class="hidden-480">BMI</th>
<th class="hidden-480">B/P</th>
</tr>
</thead>
</table>
Finally the corresponding DataTables code (which for some odd reason gives errors when placed in the partial view but not in the main view, (not my question but anyway):
<script>
$(document).ready(function ()
{
var urlRequest = $('#vitalsTable').data("request-url");
$('#vitalsTable').dataTable({
"bSort": false,
"bServerSide": true,
"sAjaxSource": urlRequest,
"sServerMethod": "POST",
"bProcessing": true,
"bFilter": false,
"aLengthMenu": [[10], [10]],
"aoColumns": [
{ "mDataProp": "VitalsDate" },
{ "mDataProp": "weight" },
{ "mDataProp": "height" },
{ "mDataProp": "bmi" },
{ "mDataProp": "bp" },
]
});
});
</script>
Action result 2 returns a chart which has the same data to another view as a Json result because that is what flot charts require. This works fine but only for the first page of data.
Here are the controller actionresults for this:
public ActionResult LoadVitalsChartData2()
{
return PartialView();
}
//[HttpPost]
[AccessRequired(AccessFeature.Vitals, AccessLevel.Read)]
public JsonResult LoadVitalsChartData()
{
int id = _accountSession.CurrentUserId;
//Bunch of code here to retrieve the data...Problem here.
//There seems to be no way to sync the Ajax call back to that it refreshes
//the data here too.
//Ideally what I want is that when the page button is pressed, it reloads this
//chart too and passes to it the relevant columns of data for plotting.
//Presently I can only get it to do the first page.
//The queries work, but how do I pass the relevant page data from the above
//action result so I am not just getting the first page of data every time.
return Json(new
{
weightData = weightResult,
xLabels = xAxisResult,
heightData = heightResult
//There is security issues around AllowGet inside a post method.
//I would like to fix this but it is also not my question.
}, JsonRequestBehavior.AllowGet);
}
Here is the corresponding partial view (This is a partial view loaded into a main view with RenderAction, nothing special):
<div id="VitalsChart" class="chart"
data-request-url="#Url.Action("LoadVitalsChartData")">
</div>
Finally the corresponding chart code this was copied and pasted from the site and only slightly modified so I put it into a separate file, if you would like to see the full code go here there is a lot of reading but I don't see anywhere to do paging:
Charts.initCharts();
Obviously I want my chart to display the data that is currently displayed in the table. i.e. if my table has 100 items paged in sets of 10, then when my table is displaying items 20 to 30, my chart should show the data for those items. It only shows the data for the first items 1 to 10. The chart itself doesn't need to handle paging, it just needs the 10 items to display and to know when the table updates. This is all available from the data sent to the table and its paging event.
So how do get this out of my table and pass it to my chart.
I have tried extracting the data to an array of some sort so it can be shared. flot charts doesn't like this. I also tried extracting the data to a common action method and passing it to another actionresult but I cant figure out how to do it.
I have tried converting all the data from anonymous types to standard class types by defining the class and casting it. But I still get errors.
This has been done before. A paged table and a chart that corresponds to the data displayed in it. Why is this so difficult to do in C# MVC4.
If there was a way I could use the above with standard data instead of Json, I would be laughing cause I know the solution. In fact, I have the solution. When querying the data, wrap it in a Paging wrapper so only the data required is returned. Then do 2 queries one in each action result for the same dataset passing only the page number to the Paging wrapper. But alas, this is for standard C# and Razor with EF and Linq. My wonderful controls require Json. This should be a lot easier but I don't know what I am missing.
It is hard to post much more code on this, I have tried so many different ways that it would make the post very long. But any one in isolation or any part of one will serve only to confuse issues.
Finally: I got some clues how to do this and started making progress but the examples I am looking for on the datatables site are not good. Here is one of my many attempts so far which is not working right (it just gives me a standard datatables error, not a JavaScript error):
$('#vitalsTable').live('page', function ()
{
var tbl = $('#vitalsTable').dataTable(
{
"aoColumnDefs": [{
"aTargets": [0],
"mData": function (source, type, val)
{
return "Hello";
}
}]
});
alert("Data ==> " + tbl);
Charts.initCharts();
});
Effectively what I am looking to do, is get a column of data when the page changes and plot this data on my chart. The page contains 10 items. So I should have a column of data with 10 items in it that can be passed to my chart for plotting.
Another snippet of code suggests that I should detect the page change event like above and before it I should do this:
var my_chart = $.plot($("#vitalsTable"), [{}]);
Then inside it I should do something like this:
my_chart.setData([new_data_set]);
my_chart.draw();
But again, I don't know how to make it work.
Thanks for any help.
This is really surprising for me. SO is a great resource, and I love it. But this is the first time I came across a problem that SO users never answered. Anyway, Finally after 8 days I worked out the answer to my question. So I am going to pop it here for reference for myself in the future cause I always come back here. S/O is like my new coding bible.
Essentially the controller was not the problem. Even the view was not the problem but instead the way I was doing the jQuery in the view.
I was advised to do something like this on other forums which essentially adds a new event handler to my data tables.
$('#vitalsTable').live('page', function ()
{
var tbl = $('#vitalsTable').dataTable(
{
"aoColumnDefs": [{
"aTargets": [0],
"mData": function (source, type, val)
{
return "Hello";
}
}]
});
alert("Data ==> " + tbl);
Charts.initCharts();
});
Above this code in my datatables code I had something like this:
<script>
$(document).ready(function ()
{
var urlRequest = $('#vitalsTable').data("request-url");
$('#vitalsTable').dataTable({
"bSort": false,
"bServerSide": true,
"sAjaxSource": urlRequest,
"sServerMethod": "POST",
"bProcessing": true,
"bFilter": false,
"aLengthMenu": [[10], [10]],
"aoColumns": [
{ "mDataProp": "VitalsDate" },
{ "mDataProp": "weight" },
{ "mDataProp": "height" },
{ "mDataProp": "bmi" },
{ "mDataProp": "bp" },
]
});
});
</script>
In actuality, all I needed to change was the code directly above, to the code below:
<script>
$(document).ready(function ()
{
var urlRequest = $('#vitalsTable').data("request-url");
$('#vitalsTable').dataTable({
"bSort": false,
"bServerSide": true,
"sAjaxSource": urlRequest,
"sServerMethod": "POST",
"bProcessing": true,
"bFilter": false,
"aLengthMenu": [[10], [10]],
"fnDrawCallback": function (oSettings)
{
Charts.initCharts(oSettings);
},
"aoColumns": [
{ "mDataProp": "VitalsDate" },
{ "mDataProp": "weight" },
{ "mDataProp": "height" },
{ "mDataProp": "bmi" },
{ "mDataProp": "bp" },
]
});
});
</script>
Once I did that, I simply needed to make minor adjustments to the client side chart.js file which takes in the data through the Charts.initCharts function and all worked well.
Later I had problems with the anonymous types, so I tried replacing them with proper classes like what C# does behind the scenes. But I found that it was even easier than this to solve. My tip, watch carefully the capitalisation of your variables on the view, controller and client side chart.js. They have to correspond exactly. Took me 2 days of messing around to find that out. It's surprising how simple changes sometimes take the longest.
I hope others looking at this find it useful. If not, post a comment and I will try to answer it.

JQuery Datatables and ASP.NET MVC Parameter to ActionResult

I'm trying to return a View with a Jquery datatable, whose action is launched from a previous page with the ActionLink--
#Html.ActionLink("View Audit", "Audit", new { id= Model.ID })
The Jquery datatable is then pre-filtered with the ID passed from the Model ID.
Here is my JS file...(incidentally, a static value e.g. 10005 works here in the fnServerParams, but I need the value to be dynamic based on whatever Model ID is chosen from theprevious screen)
var oTable = $('#myAuditTable').dataTable({
"sAjaxSource": "GetAuditLog",
"fnServerParams": function ( aoData )
{ aoData.push({ "name": "ID", "value": 10005 })
},
"aoColumns": [
....
Here is my Audit.cshtml page.
#model IEnumerable<Models.AuditLog>
<table id="myAuditTable" width="100%">
<tr>...</tr>
</table>
and in the Controller
public ActionResult GetAuditLog(int ID){
var logs = db.AuditLog.Where(c => c.ID == ID).ToList();
var result = from c in logs
select new[] { ....
};
return Json(new
{
aaData = result
}, "text/x-json", JsonRequestBehavior.AllowGet);
}
So I normally would pass a parameter in MVC like so:
public ActionResult Audit(int ID)
{
return View();
}
But since the GetAuditLog is the action getting results, how do I get the int ID to the GetAuditLog action in order to pass the filter the records, which in turn get passed as JSON. I can't call GetAuditLog in the ActionLink, because its job is to pull JSON, not render a View.
I'm not sure what I'm missing. I've gone through this guy's articles cause they are pretty comprehensive as far as integrating ASP.NET and datatables.
http://www.codeproject.com/Articles/155422/jQuery-DataTables-and-ASP-NET-MVC-Integration-Part
But cannot find an exact fit to my problem.
This post seems to come close...
How do I access the JQuery DataTables plugin aoData values in MVC3?
But doesn't quite apply since he seems to be working with a successfully passed-in parameter.
Thanks for any help.
Hi you can achieve this by two ways:
First create a hidden field having value from Model.Id and then assign this hidden field value to your datatable() function in like this
in view:
<input type="hidden" id="ID" value="#Model.ID" name="ID" />
and then put your below peace of code under document.ready and assign value ID from hidden field like this :
$(document).ready(function(){
var oTable = $('#myAuditTable').dataTable({
"sAjaxSource": "GetAuditLog",
"fnServerParams": function ( aoData )
{ aoData.push({ "name": "ID", "value": $("#ID").val() })
},
"aoColumns": [
....
});
Second: Put your datatable() function in your view under script tag and assign Model.Id directly like this:
<script type="text/javascript">
var oTable = $('#myAuditTable').dataTable({
"sAjaxSource": "GetAuditLog",
"fnServerParams": function ( aoData )
{ aoData.push({ "name": "ID", "value": '#Model.ID' })
},
"aoColumns": [
....
</script>
Hope this will resolve this issue.

Resources