My local JSON file contains documents (ending in .docx, .pdf, etc). I have a table that's rendering those documents and I want to be able to render the text '.docx' (and what not) into a separate column, with each text string corresponding to a document. The end goal is to replace the texts with their respective icons, i.e. a MS Word one for .docx.
So far I have an .includes('docx' || 'DOCX' || 'pptx') method that correctly shows the values as true and false in the table's column:
|true||Example.docx|
|false||Other.popx|
How can I include a loop (or something else) in the code I have to display the texts of 'docx', 'pptx', etc. instead of true and false?
Loading doc title data:
loadTableData() {
$.noConflict();
let tableRes = KMdocs.d.results.filter(function(val) {
return (val.FileLeafRef.trim().length > 0);
}).map(function(obj) {
return {
"Path": obj.EncodedAbsUrl,
"Titles": obj.File.Name,
"Categories": obj.ResourceType.results.map(function(val) {
return val.Label;
}).join(";"),
"Blank": "",
"docImg": obj.File.Name.includes('docx' || 'DOCX' || 'pptx')
// ----- this is where I'd like to include the code
}
})
Rendering table data:
$('#km-table-id').DataTable( {
columns: [
// { data: "Blank" },
{ data: "Categories" }, // hidden
{ data: "docImg" },
{ data: "Titles" } // must be in last position to respond w/ checkboxes
],
columnDefs: [
...etc
This will filter for docx and pptx and then return the value if it's provided
function documentType(fileName) {
return [fileName].filter(function(filter) {
return filter.toLowerCase().includes('docx') || filter.toLowerCase().includes('pptx')
}).map(function(filename) {
//Get File Extension
return filename.split('.').pop();
}).pop();
}
Usage would be:
"docImg": documentType(obj.File.Name)
Related
I'm using handsontable 0.35.1 with a float column. Aim is to allow users to copy paste from spreadsheets (and csvs opened in excel). Problem is, that it comes with some junk that i need to get rid of. Some examples of inputs which are not correctly validated are:
1,000.00
USD 100.00
'10000.00 ' //note there are trailing spaces
I would like to find a way i can manipulate input right before it's written. The only way i've found so far is with beforeChange, but the problem is validation. The system changes input, but seems to have validated already. If i blur in and blur out again, it works.
Here's the fiddle. Steps to reproduce: Enter number a123 -- which should be corrected to 123 and validated as a correct number.
I've tried using beforeValidation instead, but it doesn't work as i intend.
You can use beforePaste callback to clean your input
options = {
columns: [
{ type: 'date' },
{ type: 'numeric', numericFormat: {pattern: '0,0.00'} }
],
colHeaders: ["Date", "Float"],
beforePaste: (data, coords) => {
data.forEach((col, colIndex) => {
col.forEach((row, rowIndex) => {
let value = row.trim().replace(/[^0-9\.\-\+]/g, '')
data[colIndex][rowIndex] = value
})
})
return true
},
}
$('#hot-sheet').handsontable(options)
here is fiddle https://jsfiddle.net/xpvt214o/348195/
Note: you can't create new data array, you've to update data array instead of creating new.
I updated the example https://jsfiddle.net/fma4uge8/29/ this works all in 1 function.
function trimFloat(value) {
return value.trim().replace(/[^0-9\.\-\+]/g, '');
}
options = {
columns: [
{ type: 'date' },
{ type: 'numeric', numericFormat: {pattern: '0,0.00'}, trimWhitespace: true }
],
colHeaders: ["Date", "Float"],
beforeChange: function(changes, source){
let that = this;
_.each(changes, function(change){
if (_.isString(change[3])) {
let value = trimFloat(change[3]);
//prevent endless loop
if (value !== change[3]) {
change[3] = trimFloat(change[3]);
that.setDataAtCell(change[0], change[1], change[3]);
}
}
})
}
}
$('#hot-sheet').handsontable(options)
I am trying to insert a href into one of my columns in DataTables but Im having some issues since I need the actual href to show my slug and then the full company name.
Example how it should be formatted: "company"
Real data: Toyota Cars.
I am using columns.render which seems to be the correct function but I can't wrap my head around how I can get 'company' between the a tags. The function does not even make use of the "data" specifier, instead it takes the data first in my ajax file which in this case is slug.
My DataTable.js file
ajax: '/api/datatable',
columns: [
{ data: 'slug' },
{ data: 'company' },
],
"columnDefs": [
{ targets: [0, 1], visible: true},
{ "targets": 0,
"data": "This doesnt even seem needed?",
"render": function ( data, type, row, meta ) {
return 'full company name';
}
}
],
I will go ahead and give an answer, based on the assumption that you are trying to merge values of 2 columns. If my assumption is not correct, please, update the question to clarify "expected vs actual" results.
You are using data parameter in render function. That parameter is based on the value you specified in columns.data. In your case (with target === 0), data will contain the value that DataTable got for { data: 'slug' } column.
If you want to merge values from different columns into one, then render function is the correct way to do it. However, instead of data, you should use row parameter, which contains all key-value fields for a row.
For example:
// ...
"targets": 0,
"data": null,
"render": function ( data, type, row, meta ) {
return ''+row.company+'';
// or whatever your row object key-value structure is
}
// ...
I have autoGroupColumnDef and I want to setup text filter. But values of the column come from getDataPath method. But I need another value in the filter.
autoGroupColumnDef: {
headerName: "Systems",
filter: 'text',
valueGetter: function(params) {
var result = params.data.hospName || params.data.hospitalSystem;
return result;
},
cellRendererParams: {
suppressCount: true,
innerRenderer: function(params) {
var result = params.data.hospName || params.data.hospitalSystem;
return result;
}
}
},
After trying on couple of things,
Option 1: You can make use of [filterParams][1]. This only helps to play around with options/choices in the filterMenu..
function filterCellRenderer(params) {
//other than params.value nothing else will be there..
// params.data won't be there when its called from filter popup
return params.value+" Custom";
}
var gridOptions= {
...,
treeData: true,
components: {
...,
filterCellRenderer: filterCellRenderer
},
autoGroupColumnDef: {
...,
filterParams: {
cellRenderer: 'filterCellRenderer',
//values: ["A", "XYZ"] //you can feed directly specific values. These need to be part of filePath. Else filtering won't work.
}
}
}
Option 2: If you are looking for custom filter (tweak with GUI), or you want to post processing after it has been configured by ag-grid you can define the following:
var gridOptions = {
...
getMainMenuItems: getMainMenuItems,// function to build your own menu
postProcessPopup: function(params){
// edit the popup..
//params.type gives whether its column menu or not.
//params.ePopup gives handler to popup which you can modifiy.
},
...
}
OR you can build your own custom filter as described here
By using node js I generate the array below(2) , by parsing through multiple json files for a particular value.
My json files contains a list of IDs with their status : isAvailable or undefined.
So In my code i parse through all my json files but looking only for the first ID and get the statuts of Availability in the picture bellow. When it's true t means that the ID is available. As you can see the name of the file, it's the date and the hour the json was produced.
So What I want to achieve is write a function or anything simple, where i go through the array you can see in the picture.
Example:
We can see that the status is available for the first file, I wanna recover first file name with status available
("{ fileName: '2017-03-17T11:39:36+01:00',
Status: Available }"
when the status stop being available, in our example that would be here ( { fileName: '2017-04-06T11:19:17+02:00', contents: undefined } )
get:
{ fileName: '2017-04-06T11:19:17+02:00', Status: unavailable }
(2)
So here is part of my code where I generate this array :
Promise.mapSeries(filenames, function(fileName) {
var contents = fs
.readFileAsync("./availibility/" + fileName, "utf8")
.catch(function ignore() {});
return Promise.join(contents, function(contents) {
return {
fileName,
contents
};
});
}).each(function(eachfile) {
if(eachfile.contents){
jsonobject = JSON.parse(eachfile.contents);
if(jsonobject && jsonobject.hasOwnProperty('messages'))
// console.log(jsonobject.messages[0].message.results[2]);
eachfile.contents = jsonobject.messages[0].message.results[1].isAvailable;
}
eachfile.fileName = eachfile.fileName.substring('revision_'.length,(eachfile.fileName.length-5));
console.log(eachfile);
})
May someone help me please
Thank you,
Suppose you have an array:
[
{
filename : "2017-03-23 00:00:00",
contents : true
},
...
{
filename : "2017-03-23 00:00:00",
contents : undefined
},
{
filename : "2017-03-23 00:00:00",
contents : undefined
},
{
filename : "2017-03-23 00:00:00",
contents : true
}
]
where the ... represents a long stream of objects where the contents value is true.
You want to end up with a list of objects without consequent objects with the same contents value, meaning the result would look like:
[
{
filename : "2017-03-23 00:00:00",
contents : true
},
{
filename : "2017-03-23 00:00:00",
contents : undefined
},
{
filename : "2017-03-23 00:00:00",
contents : true
}
]
Im going to use jQuery because this is a javascript framework I am familiar with, but you should be able to translate it with ease to whatever framework you're using.
function doit(dataArray) {
var resultList = [];
var currentContent = "";
$.each(dataArray, function(index, value) {
if(currentContent != value.content) {
resultList.push(value);
currentContent = value.content;
}
});
console.log(resultList);
}
Note that you need an array with the data that looks like the data in your picture, however, you print every row. You might need to add those rows into a new array, and then pass that array to this function.
At first glance, I thought using xml data in javascript would be as simple as finding an xml-to-json library and turning my xml into a javascript object tree.
Now, however, I'm realizing that it's possible to create structures in xml that don't map directly to json.
Specifically, this:
<parentNode>
<fooNode>data1</fooNode>
<barNode>data2</barNode>
<fooNode>data3</fooNode>
</parentNode>
The xml-to-json tools I've found convert the previous to something like this:
{
parentnode:{
foonode:[
'data1',
'data3'
],
barnode:'data2'
}
}
in which, the order of the child nodes has been changed. I need to preserve the order of my child nodes. Anyone have any solution that's more elegant than
a) abandoning the idea of automatic conversion and just designing my own javascript object structure and writing code to handle this specific xml schema
or
b) abandoning the idea of any conversion at all, and leaving my xml data as an xml document which I'll then traverse.
There are established mappings from XML to JSON with limitations (see Converting Between XML and JSON) and mappings from JSON to XML (see JSONx as defined here and conversion rules by IBM). A mapping from XML to JSON that preserves order, however, has not been defined yet. To fully capture all aspects of XML, one should express the XML Infoset in JSON. if you only care about XML elements (no processing instructions, etc.), I'd choose this structure:
[
"parentNode",
{ } /* attributes */
[
[ "fooNode", { }, [ "data1" ] ]
[ "fooNode", { }, [ "data2" ] ]
[ "fooNode", { }, [ "data3" ] ]
]
]
I implemented the same mapping as mapping between XML and Perl data structures that are just like JSON with XML::Struct. The structure further corresponds to the abstract data model of MicroXML, a simplified subset of XML.
If you need the same element name often and you care about ordering it might be better to stay with XML. What benefits do you expect from using JSON?
Why not try:
{ parentNode: [
["fooNode", "data1"],
["barNode", "data2"],
["fooNode", "data3"] ]
}
I think it would more or less solve the problem.
And yes, I think you should abandon automatic conversion if it's not flexible enough; instead you might look for an API that makes such mappings trivial.
I devised this, recently:
(just a thought experiment)
var someTinyInfosetSample = {
"doctype": "html",
"$": [
{ "": "html" },
[ { "": "head" },
[ { "": "title" }, "Document title" ]
],
[ { "": "body" },
[ { "": "h1" }, "Header 1" ],
[ { "": "p", "class": "content" },
"Paragraph... (line 1)", [ { "": "br" } ],
"... continued (line 2)"
]
]
] };
(at https://jsfiddle.net/YSharpLanguage/dzq4fe39)
Quick rationale:
XML elements are the only node type (besides the document root) which accepts mixed content (text nodes and/or other elements, comments, PIs, and defines an order of its child nodes; hence the use of JSON arrays (child indices being then 1-based, instead of 0-based, because of the reserved index 0 to carry the node type (element) info; but one can note that XPath nodesets also use a 1-based index, btw);
XML attribute name/value maps don't need any ordering of the keys (attribute names) wrt. their owner element, only uniqueness of those at that element node; hence the use of a JSON object at index 0 of the container array (corresp. to the owner element);
and finally, after all, while "" is a perfectly valid JSON key in object values, it's also the case that neither XML elements or attributes can have an empty name anyway... hence the use of "" as a special, conventional key, to provide the element name.
And here's what it takes to turn it into HTML using my small "JSLT" (at https://jsfiddle.net/YSharpLanguage/c7usrpsL/10):
var tinyInfosetJSLT = { $: [
[ [ function/*Root*/(node) { return node.$; } ],
function(root) { return Per(this).map(root.$); }
],
[ [ function/*Element*/(node) { return { }.toString.call(node) === "[object Array]"; } ],
function(element) {
var children = (element.length > 1 ? element.slice(1) : null),
startTag = element[0],
nodeName = startTag[""],
self = this;
return children ?
Per("\r\n<{stag}>{content}</{etag}>\r\n").map
({
stag: Per(this).map(startTag),
etag: nodeName,
content: Per(children).map(function(child) { return Per(self).map(child); }).join("")
})
:
Per("<{stag}/>").map({ stag: Per(this).map(startTag) });
}
],
[ [ function/*StartTag*/(node) { return node[""]; } ],
function(startTag) {
var tag = [ startTag[""] ];
for (var attribute in startTag) {
if (attribute !== "") {
tag.push
(
Per("{name}=\"{value}\"").
map({ name: attribute, value: startTag[attribute].replace('"', """) })
);
}
}
return tag.join(" ");
}
],
[ [ function/*Text*/(node) { return typeof node === "string"; } ],
function(text) {
return text.
replace("\t", "&x09;").
replace("\n", "&x0A;").
replace("\r", "&x0D;");
}
]
] };
(Cf. https://jsfiddle.net/YSharpLanguage/dzq4fe39/1)
where,
Per(tinyInfosetJSLT).map(someTinyInfosetSample)
yields (as a string):
<html>
<head>
<title>Document title</title>
</head>
<body>
<h1>Header 1</h1>
<p class="content">Paragraph... (line 1)<br/>... continued (line 2)</p>
</body>
</html>
(but above the transform could also be easily adapted to use a DOM node factory, and build an actual DOM document, instead of building a string)
'HTH,