Confused on getting DataTables Render Text Helper? - javascript

I am trying to render my DataTables table so that it allows HTML characters to be shown.
From my reading it seems that this can be done using the DataTables Text Helper (as seen here https://datatables.net/manual/data/renderers)
In the example they give they simply put:
data: 'product',
render: $.fn.dataTable.render.text()
However when I have tried this it appears to do nothing at all as all the columns in my DataTable still don't show any HTML special characters (and no errors). I understand that my code is more complex than this example, but is there something simple I am missing?
var dataTableZ = $('#results_table').DataTable({
data: data.value,
render: $.fn.dataTable.render.text(),
/*
Unrelated Code surrounding buttons and column ordering
*/
columns: searchColumnDetails
});
(Where data.value is some data coming back from an Ajax call)
I have tried looking for answers to my question and it seems I am running a version of DataTables that includes this function (1.10.20), but none of the examples I could find online shed any light into my confusion.
Thank you for any assistance!

I Managed to find an answer to my question on the DataTables Forums!
Datatables doesn't have an option called render. There is a columns.render. You need to use either columns or columnDefs to to apply the render. Something like this:
columnDefs: [ {
targets: 0,
render: $.fn.dataTable.render.text() } ]
By putting this code into my code, it worked as intended.
Forum Post: https://datatables.net/forums/discussion/59325/render-text-helper-not-showing-html/p1?new=1

Related

Custom Unobtrusive Validation Method Not Firing as Per Documentation

I've been attempting to implement a ASP.NET MVC custom validation method. Tutorials I've used such as codeproject explain that you add data-val-customname to the element. Then jQuery.validate.unobtrusive.js then uses the third segment of the attribute
data-val-<customname>
as the name of the rule, as shown below.
$.validator.addMethod('customname', function(value, element, param) {
//... return true or false
});
However I just can't get the customname method to fire. By playing around I have been able to get the below code to work, but according to all the sources I've read Unobtrusive validation should not work like this.
$.validator.addMethod('data-val-customname', function(value, element, param) {
//... return true or false
});
I've posted an example of both methods
jsfiddle example
Any help would be much appreciated
I've updated my question hopefully to make clearer.
I have finally found got there in the end, but still feels like too much hard work and therefore I've probably got something wrong. Initial I was scuppered by a bug in Chrome Canary 62 which refused to allow the adding of a custom method.
My next issue was having to load jQuery, jQuery.validate and jQuery.validate.unobtrusive in the markup and then isolate javascript implementation in a ES6 class. I didn't want to add my adaptors before $().ready() because of my class structure and loading of the app file independent of jQuery. So I had to force $.validator.unobtrusive.parse(document);.
Despite this I was still having issues and finally debugged the source code and found that an existing validator information that is attached to the form was not merging with the updated parsed rules, and essentially ignoring any new adaptors added.
My final work around and admit feels like I've done too much, was to destroy the initial validation information before my forced re-parse.
Here is the working jsfiddle demo
Here is some simplified code
onJQueryReady() {
let formValidator = $.data(document.querySelector('form'), "validator" );
formValidator.destroy();
$.validator.unobtrusive.adapters.add("telephone", [], function (options) {
options.rules['telephone'] = {};
options.messages['telephone'] = options.message;
});
$.validator.unobtrusive.parse(document);
$.validator.addMethod("telephone", this.handleValidateTelephoneNumber);
}

how to handle javascript that only runs on certain pages when bundled together

When working on small client sites, I often end up working with a main.js file that includes a bunch of jQuery plugins and small toggle functionality. Some of these code snippets are only relevant on certain pages, but ends up bundled together in one main.min.js file.
My question is, how do people write the individual code snippets in order to only execute that code when the correct page is being rendered?
Here's an example: Let's say I have a page with a search input field. This input is hooked up with jQuery autocomplete in order to show search suggestions as the user types. the code in main.js could look something like this:
var data = [
{
value: 'some value',
data: 'some data'
},
{...}
]
$('#autocomplete').autocomplete({
lookup: data,
lookupLimit: 10,
minChars: 3,
});
This code is only useful on the template that has that input field, but as main.js contains a bunch of other smaller bits like this that are useful globally and on other pages, the whole file is loaded on every pageview. What strategy should I use to only execute that piece of code when the page needs it?
I though of a few ways my self:
Check if the DOM-element (in this case #autocomplete) exists.
Check if the URL is == '/page-with-autocomplete'.
Use a class on , and check for that class i n order to run the script.
Other ideas? Any standard way to do this sort of thing? Anything considered a "best practice"?
Stick your JS in an if block and check for the unique DOM element on the page you want the script to run.
Although you can't just do:
if ( $('#my-el') ) {}
You have to check if the element has a length, like:
if ( $('#my-el').length ) {}

Querying the DOM in Windows 8 Apps from within a method

I'm struggling with this even after reading the MSDN documentation and the following online guides:
Codefoster
Stephen Walter
I think my problem is easy to fix and that I just am thinking about something in the wrong way. Basically I am querying my web service and on success running the following method. I am then trying to bind the result to my listview. For now I am using a hardcoded value publicMembers.itemlistwhich has been declared at the top of the document just to make sure I can actually bind to the list before doing it with my query results. Ignore line 2 for now.
Success Method:
_lookUpSuccess: function xhrSucceed(Result) {
var response = JSON.parse(Result.responseText);
listView = document.querySelector("#termTest");
ui.setOptions(listView, {
itemDataSource: publicMembers.itemList,
itemTemplate: document.querySelector(".itemtemplate"),
})
},
Now, instead of using document.querySelector, I have also tried with WinJS.Utilities.id and WinJS.Utilities.query, neither of which worked either. This doesn't break my code and introduce an error but it doesn't bind to the listview either so I think I have an issue in querying the right DOM element. However exactly the same code does work if I add it to the top of the script, it is only when I place it in this method that it stops working.
EDIT: Also to clarify, when I debug publicMembers.itemList is storing the values I expect them to be.
Please point out if I have explained things poorly and I will try and improve my question.
Thanks.
I haven't used WinJS.UI.setOptions, but rather this other way of setting the data source. Can you see if it works?
_lookUpSuccess: function xhrSucceed(result) {
var response = JSON.parse(result.responseText);
listView = document.querySelector("#termTest");
listView.winControl.itemDataSource = publicMembers.itemList;
},
This would assume you're defining the itemTemplate as part of the data-win-options attribute of your ListView's HTML element. You could also probably just do listView.winControl.itemTemplate = document.querySelector(".itemtemplate") if you prefer to set it programmatically.

How to (properly) render additional data in grid with RowExpander

I'm trying to render some data in the rowbody in a grid (with the RowExpander plugin).
My problem is that the ol' rowBodyTpl isn't enough for me as this data is from Records on Stores from the record being rendered (hmmm...).
Putting it simply: Every record of the grid has a store in it (lets call it Items). So, I want to render the record data and some data of the Items records aswell.
What would be the best(ish) way of doing so?
Override the renderer function of the rowexpander plugin, override the getAdditionalData, or none of these?
Thank you.
I know this question is a few years old, but here's a trick I currently use to handle this kind of situation. It takes advantage of "verbatim" blocks that XTemplates allow. These allow you to execute arbitrary code inside an XTemplate by wrapping it with {% ... %}. Inside those code blocks, this is set to the XTemplate itself. The XTemplate has an owner property that, in our case, references the RowExpander plugin itself, which, in turn, has a grid property to reference the grid. So, something like this allows you to add arbitrary data to the values passed into rowBodyTpl.
Ext.create('Ext.grid.Panel', {
...
injectRowBodyData: function(values) {
values.MyInjectedContent = "Here's some extra data!";
},
plugins: [
{
ptype: 'rowexpander',
rowBodyTpl: [
'{% this.owner.grid.injectRowBodyData(value); %}',
'<div>',
'<h1>{Title}</h1>',
'<p>{Content}</p>,
'<p>{MyInjectedContent}</p>',
'</div>'
]
}
]
});
Hhopefully Sencha will fix the plugin to provide a way to handle this in the future. But for now this works well. I tested this with v4.2.1.883, but this should work with any previous version of Ext 4. The only thing I can think of that may prevent it from working in the future is the XTemplate's owner property no longer being pointed to the plugin, or the plugin not having a reference to the grid with it's grid property.
How I "solve" this problem, it might help somebody else:
I overrode the getRowBodyFeatureData of the rowexpander plugin, as this function not only receives the data to be applied on the template, but also the record itself, so I just data added the extra stores/arrays from the record.
Not sure if its the best way, but hey... at least it works.
You can also use if else statements in rowBodyTpl:
Check for ":"
"<tpl if='phone == \":\"'>",
"<tpl else>",
"</tpl>"
Check for empty string
"<tpl if='phone == \"\"'>",
"</tpl>"
this sample is taken from here: link
This is how I usually do:
Ext.create('Ext.grid.Panel',{
border: true,
store: 'ds',
columns: []
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : ['<p><b>Title:</b>{name}<br/><b>Description:</b> {description}<br/><b>Experiment Design:</b> {experimentdesign}</p>']
}],
renderTo:
});

jQuery + TableSorter: Error when table is empty

jQuery's plugin TableSorter doesn't seem to handle a situation where it is attached to an empty table. Is there a neat way around this?
In my application the user can filter and search the data and eventually he or she will come up with a search criteria which doesn't return any values. In these situations it would be nice to "detach" the TableSorter or somehow fix it's code so that it works with an empty table.
I'm currently using the plugin like this:
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
This works well, until the table is empty. Then I get the following error:
Line: 3
Error: '0.length' is null or not an object
Any ideas? Is it possible to change the script so that the tablesorter is only added to the table if it has rows?
I think you can do it for your self.
if ($("#transactionsTable").find("tr").size() > 1)
{
//> 1 for the case your table got a headline row
$("#transactionsTable")
.tablesorter({ widthFixed: true, widgets: ['zebra'] })
.tablesorterPager({ container: $("#pager"), positionFixed: false });
}
If your table got a tbody tag it is easier:
if ($("#transactionsTable").find("tbody").find("tr").size() > 0)
This way is maybe not the most professional one, but it should work under this circumstatances.
The issue is related to the fact that several parts of the codebase use rows[0] to determine 1) total number of columns, 2) the parser type to use per column (eg "text" vs "digit").
Until this bug gets fixed, here is an easy workaround:
Create a fake row in each table with contents like ("fake", 123, 123, 123, "fake"). Note how my fake contents match the "type" of the column to avoid confusing the column type detector. <tr class="fake_row"><td>fake</td><td>123</td></tr>
Add CSS styling to make the fake row not render:
tr.fake_row {
display: none;
}
This seems to work effectively, allowing tablesorter to initialize and run error-free and has no impact on the rendered output.
A more generic approach would be to override the tablesorter plugin itself to check for empty tables (until they fix the issue). See this post on overriding jquery core methods: http://www.bennadel.com/blog/1624-Ask-Ben-Overriding-Core-jQuery-Methods.htm
(function () {
// Store a reference to the original tablesorter plugin.
var originalTableSorter = jQuery.fn.tablesorter;
// Define overriding method.
jQuery.fn.tablesorter = function () {
if (this.find('tbody tr').size() == 0) {
if (typeof console != "undefined" && console.log) {
console.log('skipping tablesorter initialization - table is empty');
}
return;
}
// Execute the original method.
originalTableSorter.apply(this, arguments);
}
})();
This has been fixed in the lastest tablesorter (see issue 95).
Since overwriting plugins is always a bad idea, here's a different approach: If you just want to make sure your data table contains actual data rows, the jQuery selector :has() gets the job done, too.
$('table.tablesorter:has(tbody tr)').tablesorter({
// your tablesorter config here
});

Categories

Resources