Highcharts graph shows 265 series and no data after update to categories and series - highcharts

I inherited a small project that worked clunky and was actually quite wrong in its implementations and it almost has me tearing my head out.
http://stockfractions.com/doittest.php?TimeType=2&StartTimeFrameID=10&EndTimeFrameID=20&CompanyID=91,89&MetricID=2,3
What I am trying to do is to control what is shown on the graph so that i can export the final graph and dataset. The script basically does a pivot query in MySQL and then divides the data up by timeframe increments on the resultant page. Clicking the individual checkboxes changes whether than timeframe is part of the graph. However, every time I change the graph contents, it just shows a bunch of legends at the bottom for series going from 1 to 265 and no data. I have the code spitting out both the categories for the x-axis and the series data being passed to make sure that I am not losing my mind.
function setDynamicChart(chartCategories, chartData){
alert(chartCategories + '\n' + chartData);
$('#container123').highcharts({
chart: {
type: 'line'
},
title: {
text: 'Fundamental Company Analysis'
},
plotOptions: {
line: {
dataLabels: {
enabled: false
},
enableMouseTracking: true
}
},
xAxis: {
categories: chartCategories
},
series: chartData
});
}
is the function to change the graphdata
function regen(){
var datacount = parseInt(document.f1.datacount.value);
var linecount = parseInt(document.f1.linecount.value);
var xnames = [];
mst = document.getElementById('metrics').value;
var metricnames = mst.split(",");
var sseries = "";
//rebuild
cats = "";
for(a = 1; a <= linecount; a++){
xnames[a] = document.getElementById('name_'+a).value;
for(b = 1; b <= metricnames.length; b++){
temp = ""
for(z = 1; z <= datacount; z++){
if(document.getElementById('set_'+z).checked){//deals with datacount
if(a==1 && b==1 )
cats = cats + "'" + document.getElementById('TimeFrame'+z).value + "',";
temp = temp + document.getElementById('data_' + a + '_' + z + '_' + b).value + ",";
}
}
sseries = sseries + "{ name: '" + xnames[a] + "-" + metricnames[b-1] + "', data: [" + removeLastComma(temp) + "]}, "
}
}
cats = '[' + removeLastComma(cats) + ']';
sseries = '[' + removeLastComma(sseries) + ']';
//setDynamicChart(eval("cats"),eval("sseries"));
setDynamicChart(cats,sseries);
}
is the code to regenerate the graph.
Here is an example of the code produced
<form name='f1' id='f1'>
<div id='mytablee_data'>
<input id='set_1' type='checkbox' value='1' onclick='regen();' checked='checked' style='top:-2px;position:relative;vertical-align: middle;margin-right: 9px'/>
<input type='hidden' value='2005FY' id='TimeFrame1'>
2005FY Data
<table id='mytablee_1' class='tablesorter' border='1'>
<thead><tr><th align='center'>Company</th><th align='center'>Accounts Payable</th><th align='center'>Accounts Receivable</th></tr>
</thead>
<tbody>
<tr align='right'><td style='width:auto' align='left'>Advanced Micro Devices</td><td style='width:auto'>856</td><td style='width:auto'>0</td></tr>
<tr align='right'><td style='width:auto' align='left'>Amazon</td><td style='width:auto'>1366</td><td style='width:auto'>0</td></tr></tbody></table><p></p>
<input id='set_2' type='checkbox' value='2' onclick='regen();' checked='checked' style='top:-2px;position:relative;vertical-align: middle;margin-right: 9px'/>
<input type='hidden' value='2006FY' id='TimeFrame2'>
2006FY Data
<table id='mytablee_2' class='tablesorter' border='1'>
<thead><tr><th align='center'>Company</th><th align='center'>Accounts Payable</th><th align='center'>Accounts Receivable</th></tr>
</thead>
<tbody>
<tr align='right'><td style='width:auto' align='left'>Advanced Micro Devices</td><td style='width:auto'>1338</td><td style='width:auto'>0</td></tr>
<tr align='right'><td style='width:auto' align='left'>Amazon</td><td style='width:auto'>1816</td><td style='width:auto'>-103</td></tr></tbody></table><p></p>
<input id='set_3' type='checkbox' value='3' onclick='regen();' checked='checked' style='top:-2px;position:relative;vertical-align: middle;margin-right: 9px'/>
<input type='hidden' value='2007FY' id='TimeFrame3'>
2007FY Data
<table id='mytablee_3' class='tablesorter' border='1'>
<thead><tr><th align='center'>Company</th><th align='center'>Accounts Payable</th><th align='center'>Accounts Receivable</th></tr>
</thead>
<tbody>
<tr align='right'><td style='width:auto' align='left'>Advanced Micro Devices</td><td style='width:auto'>1009</td><td style='width:auto'>0</td></tr>
<tr align='right'><td style='width:auto' align='left'>Amazon</td><td style='width:auto'>2795</td><td style='width:auto'>-255</td></tr></tbody></table><p></p>
<input type='hidden' name='linecount' value='2'>
<input type='hidden' name='datacount' value='3'>
<input type='hidden' id='metrics' value="Accounts Payable,Accounts Receivable">
<input type='hidden' value='Advanced Micro Devices' id='name_1'>
<input type='hidden' value='856' id='data_1_1_1'>
<input type='hidden' value='1338' id='data_1_2_1'>
<input type='hidden' value='1009' id='data_1_3_1'>
<input type='hidden' value='0' id='data_1_1_2'>
<input type='hidden' value='0' id='data_1_2_2'>
<input type='hidden' value='0' id='data_1_3_2'>
<input type='hidden' value='Amazon' id='name_2'>
<input type='hidden' value='1366' id='data_2_1_1'>
<input type='hidden' value='1816' id='data_2_2_1'>
<input type='hidden' value='2795' id='data_2_3_1'>
<input type='hidden' value='0' id='data_2_1_2'>
<input type='hidden' value='-103' id='data_2_2_2'>
<input type='hidden' value='-255' id='data_2_3_2'></div>
</form>
The data elements go by the company, timeframe, metric so as to easily parse for selection changes

Well.. first of all I would advice you to read some tutorials about JS. Otherwise you will lose all hairs. Mainly problem is with regen() function. In short, you are generating JSON string manually, for some unknown reason (too much PHP?).
I would upgrade your method:
function regen(){
var datacount = parseInt(document.f1.datacount.value);
var linecount = parseInt(document.f1.linecount.value);
var xnames = [];
mst = document.getElementById('metrics').value;
var metricnames = mst.split(",");
// series and categories in Highcharts should be arrays
var sseries = [],
cats = [];
for(a = 1; a <= linecount; a++){
xnames[a] = document.getElementById('name_'+a).value;
for(b = 1; b <= metricnames.length; b++){
// data in series should be an array too
temp = [];
for(z = 1; z <= datacount; z++){
if(document.getElementById('set_'+z).checked){//deals with datacount
if(a==1 && b==1 ) {
//push categories to the array
cats.push(document.getElementById('TimeFrame'+z).value);
}
// Highcharts requires values to be number, not a string -> parse that string to the value
temp.push(parseFloat(document.getElementById('data_' + a + '_' + z + '_' + b).value));
}
}
// generate series objects
sseries.push({ name: xnames[a] + "-" + metricnames[b-1], data: temp});
}
}
setDynamicChart(cats,sseries);
}
Extra advice: To debug JS, don't use alert(), but rather console.log() - it's easier to deal with developer tools, than some string in the alert popup.

Thanks so much. I saw something else online and took out the brackets for data. Here is the code in case anyone else is suffering the same way, and thanks Pawel for pointing me in the right direction.
function regen(){
var datacount = parseInt(document.f1.datacount.value);
var linecount = parseInt(document.f1.linecount.value);
var xnames = [];
mst = document.getElementById('metrics').value;
var metricnames = mst.split(",");
var sseries = [], cats = [];
for(a = 1; a <= linecount; a++){
xnames[a] = document.getElementById('name_'+a).value;
for(b = 1; b <= metricnames.length; b++){
temp = [];
for(z = 1; z <= datacount; z++){
if(document.getElementById('set_'+z).checked){//deals with datacount
if(a==1 && b==1 )
cats.push(document.getElementById('TimeFrame'+z).value);
temp.push(parseFloat(document.getElementById('data_' + a + '_' + z + '_' + b).value));
}
}
var itemx = {
name: "'" + xnames[a] + "-" + metricnames[b-1] + "'",
data: temp
};
sseries.push(itemx);
}
}
setDynamicChart(cats,sseries);
}

Related

Datatables show details multiple rows returns undefined

I am trying to show multiple rows of child row in datatables. I am unable to figure out why it is returning undefined when I view the data. I even tried moving the function before the init the datatable but that didn't really change the result. This is an MVC (asp) project and the html shown below is test data but in reality I am pulling the data from sql server. Below is my code:
JS
var table = $('#E1, #E2, #E3').DataTable({
initComplete: function () {
this.api().columns('.select-filter').every(function () {
var column = this;
var select = $('<select><option value="">Show
All</option></select>')
.appendTo(column.header())
.on('change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.data().unique().sort().each(function (d, j) {
var val = $('<div/>').html(d).text();
select.append('<option value="' + val + '">' + val + '</option>');
});
});
},
sort: false,
scrollX: true,
fixedColumns: {
leftColumns: 2,
heightMatch: 'auto'
},
fixedHeader: {
headerOffset: 50
},
buttons: [
'excel'
],
deferRender: true,
deferLoading: true,
lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]]
});
$('#E1, #E2, #E3').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format({
'Key 1': tr.data('key-1'),
'Key 2': tr.data('key-2'),
'Key 3': tr.data('key-3'),
'Key 4': tr.data('key-4'),
'Key 5': tr.data('key-5')
})).show();
tr.addClass('shown');
}
});
function format(data) {
var html = '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:600px;">';
for (var key in data) {
console.log(data[key]);
html += '<tr>' +
'<td>' + key + '</td>' +
'<td>' + data[key] + '</td>' +
'</tr>';
}
return html += '</table>';
}
HTML
<thead>
<tr>
<th>Item 1</th>
<th>Item 2</th>
<th>Item 3</th>
<th>Item 4</th>
</tr>
</thead>
<tbody>
<tr data-key-1="Value 1" data-key-2="Value 2" data-key-3="Value 3" data-key-4="Value 4" data-key-5="Value 5">
<td class="details-control">data 1a</td>
<td class="details-control">data 1b</td>
<td class="details-control">data 1c</td>
<td class="details-control">data 1d</td>
</tr>
<tr data-key-1="Value 1" data-key-2="Value 2" data-key-3="Value 3" data-key-4="Value 4" data-key-5="Value 5">
<td class="details-control">data 2a</td>
<td class="details-control">data 2b</td>
<td class="details-control">data 2c</td>
<td class="details-control">data 2d</td>
</tr>
</tbody>
Resolved it as follows:
HTML
<tr data-child-value1="data1" data-child-value2="data2" data-child-value3="data3">
<td>data1</td>
<td>data2</td>
<td>data3</td>
</tr>
JS
$('#example').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format(tr.data('child-value1'), tr.data('child-value2'), tr.data('child-value3'))).show();
tr.addClass('shown');
}
});
function format(value1,value2,value3) {
var html = '<table cellpadding="5" cellspacing="0" border="0">';
html += '<tr>' +
'<td> D1</td>' +
'<td>' + value1+ '</td>' +
'</tr>' + '<tr>' +
'<td> D2</td>' +
'<td>' + value2+ '</td>' +
'</tr>' + '<tr>' +
'<td> D3 </td>' +
'<td>' + value3+ '</td>' +
'</tr>';
return html += '</table>';
}

Alternative way to submit temp html table in MVC

I always use the hard coded way for submitting temp table in MVC
Ex: I have to submit the following temp table after Jquery manipulating
#using (Html.BeginForm("GridSumbit", "ControllerName", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table class="Vista" id="table1">
<thead>
<tr>
<th>
col 1
</th>
<th>
col 2
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<input type="submit" value="Submit" />
}
Jquery
function AddRow(val1,val2) {
var col1 = '<input name="col1" type="hidden" value="' + val1 + '" />';
var col2 = '<input name="col2" type="hidden" value="' + val2 + '" />';
$('#table1 tbody:last').append('<tr><td>' + col1 + '</td><td>' + val2 + '</td></tr>');
}
Controller
public ActionResult GridSumbit(List<GridRows> grid)
{
.....
Model
public class GridRows {
public string col1 {set;get;}
public string col2 {set;get;}
}
Is there an alternative way to do this ? more organized way...
For model binder to correctly map the form data to your action method parameter, which is a list of GridRow class, your form element's name attribute value should be like
[{index}].col1
where {index} is the zero based index.
So if you are adding 2 rows, your inputs should be like this
<input name="[0].col1" type="hidden" value="a" />
<input name="[0].col2" type="hidden" value="b" />
<input name="[1].col1" type="hidden" value="c" />
<input name="[1].col2" type="hidden" value="d" />
You can do this by fixing your AddRow method. Here is a simple solution where i am reading the table row length and using that to derive the index. Based upon your HTML markup/client side code, make adjustments to this. All you need is the correct name attribute value in the above format.
function AddRow(val1, val2) {
var index = $('#table1 tr').length-1;
var col1 = '<input name="[' + index+'].col1" type="text" value="' + val1 + '" />';
var col2 = '<input name="[' + index +'].col2" type="text" value="' + val2 + '" />';
$('#table1 tbody:last').append('<tr><td>' + col1 + '</td><td>' + col2 + '</td></tr>');
}

Sum of Row and Column . Sum of row is done but when do sum of column then is show sum of column same every textboxes

foreach (TSM.Models.Tasks itm in lstTasks.Where(x => x.Project.ID == item.ID).ToList())
{
<tr id="tmsData">
<td> </td>
<td>#itm.TaskName</td>
#for (int i = 1; i < 8; i++)
{
<td > <input class="txtTaskHours date#(Date.AddDays(i).ToString("MMddyyyy"))" style="width:50px;" type="number" id="#(itm.ID.ToString() + ':' + Date.AddDays(i).ToString("MMddyyyy"))" /></td>
}
<td><strong><input class="JKL" style="width:50px" /></strong></td>
</tr>
<tr>
</tr>
}
}
<tr>
<td></td>
<td></td>
#for (int i = 1; i < 8; i++)
{
<td ><strong><input class="JKLL " id="Tue" style="width:50px" /></strong></td>
}
<td></td><script>
$(document).ready(function () {
$(".txtTaskHours").on('keyup change', calculateSum);
});
function calculateSum() {
var $input = $(this);
var $row = $input.closest('tr');
var sum = 0;
$row.find(".txtTaskHours").each(function () {
sum += parseFloat(this.value) || 0;
});
$row.find(".JKL").val(sum.toFixed(2));
//adding column values
var eid = ($input.attr('id'));
var arrTaskTextBoxes = $('.date' + eid.substr(eid.indexOf(":") + 1, 8));
var sum = 0.00
for (var i = 0; i < arrTaskTextBoxes.length; i++) {
if (arrTaskTextBoxes[i].value != '') {
sum+= parseFloat(arrTaskTextBoxes[i].value) || 0;
}
}
$(".JKLL").val(sum.toFixed(2));
//document.getElementById('Tue').value = sum.toFixed(2);
console.log(sum);
}
This is my script code i tried this but when sum of column is take
place then if we fill data in top to bottom then its show sum in whole of the
textbox. Row sum is done very properly way but sum of the column issue is
coming sum of column show is correct but is sow all the text boxes that is
give in the bottom row. I use this script method here i am using eid by which
id of every textbox we take.

Knockout Paging in MVC with Web API

I can't get this code to page. The table's page size is always the same - the number of items returned from the Web API call. The parameter that is passed-in is ignored (3). Also, the back and forward button elements don't have icons (icon-step-backward and icon-step-forward), but this is secondary to the page size.
HTML
<table class="table">
<thead>
<tr>
<th data-column="LastName">Last Name</th>
<th data-column="FirstName">First Name</th>
<th data-column="EnrollmentDate">Enrollment Date</th>
</tr>
</thead>
<tbody data-bind="foreach: students">
<tr>
<td data-bind="text: LastName" />
<td data-bind="text: FirstName" />
<td data-bind="text: EnrollmentDate" />
</tr>
</tbody>
<tfoot>
<tr>
<td>
Number of items per page:
<select id="pageSizeSelector" data-bind="value: pageSize">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</td>
<td colspan="3">
<button data-bind="click: previousPage" class="btn"><i class="icon-step-backward"></i></button>
Page<label data-bind="text: currentPageIndex() + 1" class="badge"></label>
<button data-bind="click: nextPage" class="btn"><i class="icon-step-forward"></i></button>
</td>
</tr>
</tfoot>
</table>
KNOCKOUT and JQUERY
<script type="text/javascript">
var viewModel = function () {
self = this;
self.currentPage = ko.observable();
self.pageSize = ko.observable(3);
self.currentPageIndex = ko.observable(0);
self.students = ko.observableArray();
self.currentPage = ko.computed(function () {
var pagesize = parseInt(self.pageSize(), 3),
startIndex = pagesize * self.currentPageIndex(),
endIndex = startIndex + pagesize;
return self.students.slice(startIndex, endIndex);
});
self.nextPage = function () {
if (((self.currentPageIndex() + 1) * self.pageSize()) < self.students().length) {
self.currentPageIndex(self.currentPageIndex() + 1);
}
else {
self.currentPageIndex(0);
}
}
self.previousPage = function () {
if (self.currentPageIndex() > 0) {
self.currentPageIndex(self.currentPageIndex() - 1);
}
else {
self.currentPageIndex((Math.ceil(self.students().length / self.pageSize())) - 1);
}
}
}
$(document).ready(function () {
$.ajax({
url: "http://localhost:12769/api/student",
type: "GET"
}).done(function (data) {
var vm = new viewModel();
vm.students(data);
ko.applyBindings(vm);
}).error(function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.responseText || textStatus);
});
});
</script>
JSON Returned From Web API
[{"$id":"1","ID":1,"LastName":"Alexander","FirstMidName":"Carson","EnrollmentDate":"2005-09-01T00:00:00","Enrollments":[{"$id":"2","EnrollmentID":1,"CourseID":1050,"StudentID":1,"Grade":0,"Course":{"$id":"3","CourseID":1050,"Title":"Chemistry","Credits":3},"Student":{"$ref":"1"}},{"$id":"4","EnrollmentID":2,"CourseID":4022,"StudentID":1,"Grade":2,"Course":{"$id":"5","CourseID":4022,"Title":"Microeconomics","Credits":3},"Student":{"$ref":"1"}},{"$id":"6","EnrollmentID":3,"CourseID":4041,"StudentID":1,"Grade":1,"Course":{"$id":"7","CourseID":4041,"Title":"Macroeconomics","Credits":3},"Student":{"$ref":"1"}}]},{"$id":"8","ID":2,"LastName":"Alonso","FirstMidName":"Meredith","EnrollmentDate":"2002-09-01T00:00:00","Enrollments":[{"$id":"9","EnrollmentID":4,"CourseID":1045,"StudentID":2,"Grade":1,"Course":{"$id":"10","CourseID":1045,"Title":"Calculus","Credits":4},"Student":{"$ref":"8"}},{"$id":"11","EnrollmentID":5,"CourseID":3141,"StudentID":2,"Grade":4,"Course":{"$id":"12","CourseID":3141,"Title":"Trigonometry","Credits":4},"Student":{"$ref":"8"}},{"$id":"13","EnrollmentID":6,"CourseID":2021,"StudentID":2,"Grade":4,"Course":{"$id":"14","CourseID":2021,"Title":"Composition","Credits":3},"Student":{"$ref":"8"}}]},{"$id":"15","ID":3,"LastName":"Anand","FirstMidName":"Arturo","EnrollmentDate":"2003-09-01T00:00:00","Enrollments":[{"$id":"16","EnrollmentID":7,"CourseID":1050,"StudentID":3,"Grade":null,"Course":{"$ref":"3"},"Student":{"$ref":"15"}}]},{"$id":"17","ID":4,"LastName":"Barzdukas","FirstMidName":"Gytis","EnrollmentDate":"2002-09-01T00:00:00","Enrollments":[{"$id":"18","EnrollmentID":8,"CourseID":1050,"StudentID":4,"Grade":null,"Course":{"$ref":"3"},"Student":{"$ref":"17"}},{"$id":"19","EnrollmentID":9,"CourseID":4022,"StudentID":4,"Grade":4,"Course":{"$ref":"5"},"Student":{"$ref":"17"}}]},{"$id":"20","ID":5,"LastName":"Li","FirstMidName":"Yan","EnrollmentDate":"2002-09-01T00:00:00","Enrollments":[{"$id":"21","EnrollmentID":10,"CourseID":4041,"StudentID":5,"Grade":2,"Course":{"$ref":"7"},"Student":{"$ref":"20"}}]},{"$id":"22","ID":6,"LastName":"Justice","FirstMidName":"Peggy","EnrollmentDate":"2001-09-01T00:00:00","Enrollments":[{"$id":"23","EnrollmentID":11,"CourseID":1045,"StudentID":6,"Grade":null,"Course":{"$ref":"10"},"Student":{"$ref":"22"}}]},{"$id":"24","ID":7,"LastName":"Norman","FirstMidName":"Laura","EnrollmentDate":"2003-09-01T00:00:00","Enrollments":[{"$id":"25","EnrollmentID":12,"CourseID":3141,"StudentID":7,"Grade":0,"Course":{"$ref":"12"},"Student":{"$ref":"24"}}]},{"$id":"26","ID":8,"LastName":"Olivetto","FirstMidName":"Nino","EnrollmentDate":"2005-09-01T00:00:00","Enrollments":[]}]
One reason it might not be working for you, is that you are using parseInt with a radix of 3. So in your currentPage ko computed, the line var pagesize = parseInt(self.pageSize(), 3) is going to result in a NaN. See the MDN docs for more info.
Here's a helpful paging extension for a KO observable array, and it will clean up your view model as well. See this fiddle for a working example. In your case, your viewmodel would simply be
var viewmodel = function(){
var self = this;
self.students = ko.observableArray().paged(3);
}
Your HTML would be this:
<table data-bind="foreach: students.pagedItems">
<!-- normal data binding syntax here -->
</table>
And some pagination controls. These are using Bootstrap classes, but gives you an idea of how to use them:
<ul class="pagination">
<li data-bind="css: { disabled: students.currentPageIndex() === 0 }">«</li>
</ul>
<ul class="pagination" data-bind="foreach: students.allPages">
<li data-bind="css: { active: pageNumber === ($root.students.currentPageIndex() + 1) }">
</li>
</ul>
<ul class="pagination">
<li data-bind="css: { disabled: students.currentPageIndex() === students.maxPageIndex() }">»</li>
</ul>
<br />
<span data-bind="text: students.currentStatus"></span>
And here's the extension. I have a second option to pass a sorting function in, but it is completely optional.
ko.observableArray.fn.paged = function (perPage, sortComparator) {
var items = this;
items.currentPage = ko.observable();
items.pageSize = ko.observable(perPage);
items.currentPageIndex = ko.observable(0);
items.currentItemPage = ko.computed(function () {
var pagesize = parseInt(items.pageSize(), 10),
startIndex = pagesize * items.currentPageIndex(),
endIndex = startIndex + pagesize;
return this().slice(startIndex, endIndex);
}, items);
items.pagedItems = ko.computed(function () {
var size = parseInt(items.pageSize(), 10),
start = items.currentPageIndex() * size;
if (typeof (sortComparator) === "function") {
var sorted = this().sort(sortComparator);
return sorted.slice(start, start + size);
} else {
return this().slice(start, start + size);
}
}, items);
items.maxPageIndex = ko.computed(function () {
return Math.ceil(this().length / items.pageSize()) - 1;
}, items);
items.allPages = ko.computed(function () {
var pages = [];
for (var i = 0; i <= items.maxPageIndex() ; i++) {
pages.push({ pageNumber: (i + 1) });
}
return pages;
}, items);
items.currentStatus = ko.computed(function () {
var pagesize = parseInt(items.pageSize(), 10),
start = pagesize * items.currentPageIndex(),
end = start + pagesize;
if (items.currentPageIndex() === items.maxPageIndex()) end = this().length;
return 'Showing ' + (start + 1) + ' to ' + end + ' of ' + this().length;
}, items);
items.nextPage = function () {
if (((items.currentPageIndex() + 1) * items.pageSize()) < items().length) {
items.currentPageIndex(items.currentPageIndex() + 1);
} else {
items.currentPageIndex(0);
}
};
items.previousPage = function () {
if (items.currentPageIndex() > 0) {
items.currentPageIndex(items.currentPageIndex() - 1);
} else {
items.currentPageIndex((Math.ceil(items().length / items.pageSize())) - 1);
}
};
items.moveToPage = function (index) {
items.currentPageIndex(index);
};
return items;
};

MVC Html helper to make a label editable

I have a html table generated in my view, does anyone know of any helpers available that I could use so that one of the fields could be edited in-line.
View:
<table>
<caption>Configuration values for current management group</caption>
<thead>
<tr>
<th scope="col">Device Type</th>
<th scope="col">Section</th>
<th scope="col">Name</th>
<th scope="col">Value</th>
<th scope="col">Operation</th>
</tr>
</thead>
<tbody>
#foreach (var param in Model.ParamData)
{
<tr>
<td>#param.DeviceType</td>
<td>#param.Group</td>
<td>#param.Name</td>
<td>#param.Value</td>
<td>#(param.IsMerge ? "Merge" : "Delete")</td>
</tr>
}
</tbody>
</table>
As you can see there is nothing special here, I would like an edit column that would work in a similar way to a web forms gridview. The only field to be edited would be value, and it would always be a textbox.
Im sure people must have done this before but the only example Ive seen on line was for mvc 1.
I could knock something up using jquery but am sure there must be loads of examples already and dont want to re-invent the wheel.
Ive done it myself, if anyones interested:
#foreach (var param in Model.ParamData)
{
<tr>
<td>#param.DeviceType</td>
<td>#param.Group</td>
<td>#param.Name</td>
<td>
<div class="#("ViewValueDiv_" + param.ParamaterValueId)">
#param.Value
</div>
<div class="#("EditValueDiv_" + param.ParamaterValueId)" style="display:none;">
<input type="text" name="#("EditValue_" + param.ParamaterValueId)" value="#param.Value" class="#("Input_" + param.ParamaterValueId)" />
</div>
</td>
<td>#(param.IsMerge ? "Merge" : "Delete")</td>
<td>
<div class="#("EditButtonDiv_" + param.ParamaterValueId)">
<input type="button" value="Edit" class="EditButton" Id="#param.ParamaterValueId" />
</div>
<div class="#("UpdateCancelButtonDiv_" + param.ParamaterValueId)" style="display:none;">
<input type="button" value="Update" class="UpdateButton" id="#("U" + param.ParamaterValueId)" />
<input type="button" value="Cancel" class="CancelButton" id="#("C" + param.ParamaterValueId)" />
</div>
</td>
</tr>
}
$(document).ready(function () {
$(".EditButton").click(function () {
var id = $(this).attr('id');
$(".ViewValueDiv_" + id).hide();
$(".EditValueDiv_" + id).show();
$(".EditButtonDiv_" + id).hide();
$(".UpdateCancelButtonDiv_" + id).show();
oldvalue = $(".Input_" + id).val();
});
$(".CancelButton").click(function () {
var id = $(this).attr('id').substr($(this).attr('id').indexOf("C") + 1);
$(".ViewValueDiv_" + id).show();
$(".EditValueDiv_" + id).hide();
$(".EditButtonDiv_" + id).show();
$(".UpdateCancelButtonDiv_" + id).hide();
$(".Input_" + id).val(oldvalue);
});
$(".UpdateButton").click(function () {
var id = $(this).attr('id').substr($(this).attr('id').indexOf("U") + 1);
NewValue = $(".Input_" + id).val();
if (NewValue) {
$.ajax({
url: "/Terminals_configuration/UpdateConfigValue",
data: { valueId: id, newValue: NewValue },
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred.");
},
success: function (data) {
$(".ViewValueDiv_" + id).show();
$(".EditValueDiv_" + id).hide();
$(".EditButtonDiv_" + id).show();
$(".UpdateCancelButtonDiv_" + id).hide();
$(".ViewValueDiv_" + id).html(NewValue);
}
});
} else {
alert("You didn't supply a new value");
}
});
});

Resources