Generate a column dynamically with JQuery DataTables where table is based on a model - asp.net-mvc

In an ASP.Net MVC application I have a table that's based on a model passed to the view. For this reason, the table is not based on a Json and the fields have no column names that I can reference in the 'columns'[] section of the script (or at least I don't know how!...). Still, the table works fine except that I can't manage to generate a calculated field. In all the various experiments I keep getting a NaN or undefined result, depending on the various attempts, and I understand this is because evidently I'm not referencing the proper data value, but how can I do that if I don't have column names?
The table is properly structured, thead, tbody and tfoot have the same number of columns. This is the html for the table:
<table id="mainTable" class="table table-hover">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.Value1)</th>
<th>#Html.DisplayNameFor(model => model.Value2)</th>
<th>test</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Value1)</td>
<td>#Html.DisplayFor(modelItem => item.Value2)</td>
<td></td>
</tr>
}
</tbody>
<tfoot><tr><th></th><th></th><th></th></tr></tfoot>
</table>
The render function on first and second columns works just fine. The third column is where I am trying to calculate and display the difference between first and second column, and that's where I get NaN or undefined. This is the script:
<script>
$(document).ready(function () {
// DataTable
var table = $('#mainTable').DataTable({
responsive: true,
columns: [
{ render: function (data, type, row) { return data + '$' } },
{ render: function (data, type, row) { return data + '$' } },
{ render: function (data, type, row) { return (row.Value1 - row.Value2) + '$' }}]
});
});
</script>
This is the result I'm getting on this particular attempt. I've tried other versions, unfortunately with similar disappointing results:
Value 1 Value 2 test
200.00$ 100.00$ NaN$
etc...
I have also tried this:
columns: [ { data: 'Value1', render: function (data, type, row) { return data + '$' } } ]
and this
columns: [ { name: 'Value1', render: function (data, type, row) { return data + '$' } } ]
and this
columns: [ { data: 'Value1', name: 'Value1', render: function (data, type, row) { return data + '$' } } ]
but in all cases the entire script fails.
I also tried to assign names with columnDefs [...] but no luck.
Would someone be so kind to tell me what I'm doing wrong, or what I should do to make this work?
Thank you!

Related

knockout custom bindinghandler and custom jquery UI widget

I'm trying to create a custom knockout bindingHandler to add a custom jQuery UI widget but have run into trouble trying to access the elements created during binding. I'm sure there's something fundamental about this that I'm missing. I have the following html:
<table data-bind="myGrid: {}">
<thead>
<tr data-bind="foreach: { data: columns, as: 'column' }">
<th data-bind="text: column"></th>
</tr>
</thead>
<tbody data-bind="foreach: { data: rows, as: 'row' }">
<tr data-bind="foreach: { data: $parent.columns, as: 'column' }">
<td data-bind="text: row[column]"></td>
</tr>
</tbody>
</table>
And the following javascript:
var vm = {
columns: [
'A', 'B'
],
rows: []
};
$.widget("my.grid", {
_create: function() {
var columns = this.element.find('th');
}
});
ko.bindingHandlers.myGrid = {
init: function (element) {
//$(element).grid();
},
update: function(element) {
$(element).grid();
}
};
ko.applyBindings(vm);
When the widget is created, it needs to find each th element created from the binding. However, the elements don't appear to be created at that point in time. I have tried both the init and update methods of the bindinghandler.
This works if I manually add the widget to the element, just not within the bindinghandler.
When and how do I access the elements created from data-binding so that my jQuery widget can modify them?
You need to take control of the bindings to your descendant elements within your custom binding handler.
See http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html
But basically, do something like:
ko.bindingHandlers.myGrid = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// bind our child elements (which will create the virtual foreach elements)
ko.applyBindingsToDescendants(bindingContext, element);
// make your grid widget
$(element).grid();
// tell KO we have already bound the children
return { controlsDescendantBindings: true };
},
update: function() { ... }
};

What is the sequence or flow to implement this view in MVC4

I'm still learning about MVC4.
Imagine the following scenario: I've got three dropDownLists and one big div for the content. I don't know how to deal the loading on demand.
The flow is simple, when page is loaded, display the data in the first dropdownlist. When this one has a value, the second one should load the information on demand (using the selected value from ddl1) and so on, until change the value on the ddl3 and displays the data.
Until here I have detected two partial views. I'm not sure if I should create 5 because each ddl must be in one partial view.
Another thing, what would you recomend to maintain the SelectList, should I have to use ViewBag or maintain in a viewModel the collections foreach ddl?
I just one to know if you can clarrify this scenario. I mean, give an idea about how can I start doing this? In fact, I forgot to mention this doubt but I don't if I have to use AJAX.
I got stuck , few weeks back in same kind of stuff:-
Let your MVC calls be like :-
private void LoadDropdown1()
{
var _data;//Your logic to get the data
ViewData["Dropdown1"] = new SelectList(_data, "Dropdown1Id", "Name");
}
private void LoadDropdown2(int dropdownParameterId)
{
var _data = "";//Use your ID to get the data
ViewData["Dropdown2"] = new SelectList(_data, "Dropdown2Id", "Name");
}
Your .cshtml be :-
#using (Html.BeginForm())
{
<div>
<table>
<tr>
<td><b>Select a District:</b></td>
<td>#Html.DropDownListFor(m => m.Dropdown1Id, ViewData["Dropdown1"] as IEnumerable<SelectListItem>, "Select One", new {#id="Dropdown1Id"})</td>
</tr>
<tr>
<td><b>Select:</b></td>
<td>#Html.DropDownListFor(m => m.Dropdown2Id, ViewData["Dropdown2"] as IEnumerable<SelectListItem>, "Select One")</td>
</tr>
</table>
</div>
}
Now AJAX call is best to load data to your dropdown:-
$(function () {
$('select#Dropdown1').change(function () {
var id = $(this).val();
$.ajax({
url: 'Bla Bla',
type: 'POST',
data: JSON.stringify({ id: id }),
dataType: 'json',
contentType: 'application/json',
success: function (data) {
$.each(data, function (key, data) {
$('select#Dropdown1').append('<option value="0">Select One</option>');
// loop through the LoadDropdown1 and fill the dropdown
$.each(data, function (index, item) {
$('select#Dropdown1').append(
'<option value="' + item.Id + '">'
+ item.Name +
'</option>');
});
});
}
});
});
});
What i am trying to say is.. Load your 1st dropdown the way you prefer. Then On change event of 1st dropdown, you can fire an ajax call to fetch data for 2nd dropdown.... Similarly..
Reference:- on select change event - Html.DropDownListFor

Web API with Knockout.js - Why isn't this working?

I have a web API which successfully returns an array of blog posts in JSON format:
[{"ID":1,"Title":"First Blog Post","Body":"Some Content"},{"ID":2,"Title":"Second BlogPost","Body":"Some other content"}]
For exercise purposes, I want to display all posts in a list using Knockout.js.
Here is my code:
<script>
$(document).ready(function () {
function AppViewModel() {
var self = this;
self.posts = ko.observableArray([
{ Title: 'Default Title', Body: 'Default Body' },
]);
$.getJSON('api/posts', function (data) {
ko.mapping.fromJSON(data, {}, self.posts);
});
}
ko.applyBindings(new AppViewModel());
});
My bindings:
<tbody data-bind="foreach: posts">
<tr>
<td data-bind="text: Title"></td>
<td data-bind="text: Body"></td>
</tr>
</tbody>
My table shows up empty, it's not showing the JSON data for some reason...
ANSWER: I had to change fromJSON to fromJS and it works! Thanks so much for your help everyone
In your case you need to specify the update target for the mapping.
From the Knockout Mapping plugin documentation:
If, like in the example above, you are performing the mapping inside
of a class, you would like to have this as the target of your mapping
operation. The third parameter to ko.mapping.fromJS indicates the
target. For example,
ko.mapping.fromJS(data, {}, someObject);
So in your case:
$.getJSON('api/posts', function (data) {
ko.mapping.fromJSON(data, {}, self.posts);
});
A working JSFiddle
Also note that that the property names are case sensitive and they should match in the JSON and in your viewmodel and bindings. e.g you retrive "Title" but you are using title
The json being returned has title case property names, but the original in self.posts has lowercase property names. I assume you are binding to the lowercase version in your template. Consider changing the json returned to lowercase too.

one idea for jqgrid print view

I would like to have two views in jqgrid:
1) the regular grid view with sortable columns, pagination, etc (It's great and works really well...love it!).
2) a "print view" which can easily be styled with css and customized for print. The class structure should not be too complicated because I want to easily make my own style sheet. One important thing is to be able to repeat the column headers on each printed page. (I do not like to print from a jqgrid. Even when I add the jqgrid stylesheet with "media=print", the printed results are very hard to control.)
So, what I did was to first create a jqGrid. Then, using it's data, create my own table and print from that. It's a bit of a hack. But it works.
1- Create the grid and insert it into a div. Note I called "build_print_view" in the "loadComplete" function, based on the presence of a variable. This allows me to control whether I want to show "print view" or a "grid view" first:
function classGrid(select_val, showgrid){
jQuery.get('/lookupgrid/lookupgrid/get_grid', function(data) {
var _html= jQuery(data);
jQuery('#resultdiv').html(_html);
var gridtable = jQuery("#list");
var formdata = new Array();
formdata.push({
name: "var1",
value: "whatever"
});
formdata.push({
name: "var2",
value: "whateverelse"
});
var lastsel;
console_log("in classGrid");
gridtable.jqGrid({
url:'/lookupgrid/lookupgrid/class_grid',
colNames:['var1','var2'],
colModel :[
{
name:'var1',
index:'var1',
width:95
},
{
name:'var2',
index:'var2',
width:95
}],
datatype: 'json',
mtype: 'POST',
pager: '#pager',
rowList:[10,20,30],
loadComplete: function() {
if(!showgrid){
build_print_view();
}
},
onSelectRow: function(id){
var rowdata = gridtable.jqGrid('getRowData',id);
alert('Selected row ID ' + id + " var1 is " + rowdata.var1);
},
loadonce: true,
postData:formdata,
width: 800,
height: 300,
pgtext:"Page {0}",
viewrecords: true,
gridview: true,
caption: 'Class Results'
});
gridtable.jqGrid('navGrid','#pager',{
edit:false,
add:false,
del:false
});
});
}
2 - In build_print_view() you can extract the data from the jqgrid and put it into a table, which can be styled however you like with your own stylesheets.
function build_print_view(){
var gridtable = jQuery("#list");
var lista = gridtable.jqGrid('getGridParam','data');
var tablestr = "";
for(var i=0;i<lista.length;i++){
var rowData = lista[i];
tablestr += "<tr>"
tablestr += "<td class=\"wide cycle\" style=\"width:50px;\" id=\"sku\">"+rowData.var1+"</td>";
tablestr += "<td class=\"wide cycle\" style=\"width:300px;\" id=\"skudesc\">"+rowData.var2+"</td>";
tablestr += "</tr>";
}
jQuery.get('/lookupgrid/lookupgrid/get_print_view', function(data) {
var _html= jQuery(data);
_html.find('#printresults').append(tablestr);
jQuery('#resultdiv').html(_html);
});
}
3 - The rest of the table, and etc tags are returned by the ajax "get" call to "/lookupgrid/lookupgrid/get_print_view" and I just plop tablestr into "#printresults" div, i.e.:
<div id="printview">
<table id="clsitems" class="wide">
<thead>
<tr>
<th colspan="10" class="wide" id="label">
</th>
</tr>
<tr>
<td class="wide label">
var1:
</td>
<td class="wide label">
var2:
</td>
</tr>
</thead>
<tbody id="printresults">
</tbody>
</table>
</div>
4 - The only weirdness is that if "print view" is requested, the jqGrid gets created and flashes on the screen for a second, and then the print view table replaces it in its div.
Actually, if there were a good way to just construct the jqGrid without displaying it, I would prefer that. I could then display the jqGrid later if "screen view" were requested.

jquery - tablesort only works in one direction

This sorts in one direction, but not the other. Is there something wrong with the table specifications. It wold be great if someone could post an HTML sample that has sorting working in both directions on a column with dollar values that include commas in them.
// create sorter
<script type="text/javascript" id="js">
$(document).ready(function() {
// call the tablesorter plugin
$("table.tablesorter").tablesorter({
// enable debug mode
debug: false
});
});
</script>
Not sure if a prefix is needed here (table.tablesorter):
// add parser through the tablesorter addParser method
<script type="text/javascript" id="js">
$.tablesorter.addParser({
// set a unique id
id: 'money',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
return s.toLowerCase().replace("\$","").replace(",","");
},
// set type, either numeric or text
type: 'numeric'
});
Not sure if table.tablesorter is needed here:
// specify column
$(function() {
$("table.tablesorter").tablesorter({
headers: {
// column to be handled specially
7: {
sorter:'money'
}
}
});
});
</script>
The following is the top of the table:
<table cellspacing="1" class="tablesorter">
<thead>
<tr>
<th>Name</th>
<th>Major</th>
<th>Gender</th>
<th>English</th>
<th>Japanese</th>
<th>Calculus</th>
<th>Overall grades</th>
<th>Money</th>
</tr>
</thead>
<tbody>
<tr>
<td>Student01</td>
<td>Languages</td>
<td>male</td>
<td>80</td>
<td>70</td>
<td>75</td>
<td>bad</td>
<td>$1.00</td>
</tr>
Since you are working with numbers, you'll need to parse the string into a real number. Change this line in your parser:
format: function(s) {
return parseFloat( s.toLowerCase().replace("\$","").replace(",","") );
}

Resources