Kendo grid Format number with whitespace as thousand separator and two decimal places - asp.net-mvc

I need to format numbers in a column with white space as thousand separator and with two decimal places. For example: 125895456.8942 -> 125 895 456.89
columns: [
{
field: "sumStartDebit",
title: "Debit",
width: "130px",
template: function (dataItem) {
if (dataItem.sumStartDebit == 0) { return "" }
else if (dataItem.sumStartDebit < 0) { return "<span style='color:red'>" + dataItem.sumStartDebit + "</span>" }
else { return "<span>" + dataItem.sumStartDebit + "</span>" }
},
locked: true,
},
]
What can i achieve it w/o culture? I have a function that works for thousand separator but not for my condition of two decimal places
function numberWithSpaces(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}

What about this:
function numberWithSpaces(x) {
return kendo.toString(x, "##,#.##").replace(/,/g, " ")
}
You format your string with the usual decimal seperator in your culture (in this case "," for en-US) and then replace that with a whitespace using regex.
For "12345678.0394" you would get "12 345 678.04"
You could inline this inside your template as well:
template: '#= kendo.toString(sumStartDebit, "##,#.##").replace(/,/g, " ")#'

Related

How to add more attributes in tooltip series in Angular NVD3 line chart

I need to add more attributes in tooltip series in Angular NVD3 line chart, if possible, without modifying the NVD3 source code. I know there are similar posts, but none of them covers this scenario.
Here is my tooltip section in options:
interactiveLayer: {
tooltip: {
contentGenerator: function (d) {
// output is key, value, color, which is the default for tooltips
console.log(JSON.stringify(d.series[0]));
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1)"}
// and I need more attributes to be added
// into data points, such as label, count, location (see data below)
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1), "label" : "some label", "count" : 23, "location" : "Paris"}
}
}
}
And here is my data:
$scope.data =
[
{
values: FirstGraphPointsArray,
key: 'Name',
color: 'rgba(255,140,0, 1)'
},
{
values: SecondGraphPointsArray
key: 'City',
color: 'rgba(255,140,0, 1)'
}
]
Finally, the structure of the arrays in data:
FirstGraphPointsArray -> [{ x: xVariable, y: yVariable, label: labelVariable, count: countVariable, location : locationVariable }, {second element...}, {third element...}];
SecondGraphPointsArray -> [a similar array...]
How to get more attributes (label, count, location) from these arrays into the contentGenerator: function (d). As mentioned above, I only receive the default ones from within function parameter (d)
console.log(JSON.stringify(d.series[0]));
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1)"}
I came up with a solution and wanted to share it, in case someone else comes across the same task. I ended up accessing some of the parameters from d through the default route - function(d), while some of the custom ones - directly from $scope.data.
Important: using the d.index, which indicates the place of the data point in the list is critical hear. This makes sure that for any given index the parameters pulled from the function(d) and those of pulled directly, belong to the same data point (see the code below).
interactiveLayer: {
tooltip: {
contentGenerator: function (d) {
var customTooltipcontent = "<h6 style='font-weight:bold'>" + d.value + "</h6>";
customTooltipcontent += "<table class='custom-tooltip-table'>";
customTooltipcontent += "<tr style='border-bottom: 1px solid green;'><td></td><td>Name</td><td>Value</td><td>Count</td></tr>";
for (var i = 0; i < d.series.length; i++) {
customTooltipcontent += "<tr><td><div style='width:10px; height:10px; background:" + d.series[i].color + "'></div></td><td>" + d.series[i].key + "</td><td>" + d.series[i].value + "</td><td>" + $scope.data[0].values[d.index].count + "</td><td>" + $scope.data[0].values[d.index].location + "</td></tr>"
}
customTooltipcontent += "</table>";
return (customTooltipcontent);
}
}
}

A different suffix for each line on Highstock/Highcharts with Thingspeak source

I've got the code for Highcharts in combination with Thingspeak from here:
https://forum.arduino.cc/index.php?topic=213058.0
My problem is, I am not able to implement the different suffix into the code :-(. I've tried a lot, but I dont understand the mechanism behind the Java code.
I've tried some things, but result is, I only have one datafield for the first series but not for the other series...
Formatter function is on line 246.
My different yAxies on line 286.
How can formatter decide which yAxies do actual series use?
Maybe somebody have fun to help me?
http://jsfiddle.net/cbmj8rku/
Best regards, David
Each series is assigned to one yAxis. You can detect which series uses which axis for example by axis title:
tooltip: {
formatter: function() {
var points = this.points,
title,
result = '';
Highcharts.each(points, function(p) {
result += p.y;
title = p.series.yAxis.axisTitle.textStr;
if (title === 'yAxis1') {
result += 'suffix1<br>'
} else if (title === 'yAxis1') {
result += 'suffix2<br>'
} else {
result += 'suffix2<br>'
}
});
return result
}
}
Live demo: http://jsfiddle.net/BlackLabel/ncvtxoke/
I changed the code like this:
http://jsfiddle.net/cbmj8rku/20/
formatter: function() {
var d = new Date(this.x + (myOffset*60000));
var _Min = (d.getMinutes()<10) ? '0' + d.getMinutes() : d.getMinutes();
var _Sec = (d.getSeconds()<10) ? '0' + d.getSeconds() : d.getSeconds();
var s = d.getHours() + ':' + _Min + ':' + _Sec + '<br/>';
$.each(this.points, function () {
s += '<br/>' + this.series.name + ' <b>' + this.y + this.series.yAxis.userOptions.labels.suffix + '</b>';this.series.tooltipOptions.valueSuffix[this.point.index];
});
return s;
}

How to Add Custom Data to Highchart.js Tooltip

Can you please take a look at This Demo and let me know how I can add some custom data from an array to tooltip in highchart?
var extras = ["Values More Than 1000", "Values More Than 2000", "Values More Than 3000", "Values More Than 4000", "Values More Than 5000"];
As you can see the array length is equal to the column numbers so the extras[0] with go with tooltip for column 1
some thing like
You can customize the tooltip with the formatter option.
tooltip: {
formatter: function () {
var index = this.series.points.indexOf(this.point);
return extras[index] + ': ' + this.y;
},
style: {
width: 250,
fontSize: '15px'
}
}
Here's a jsFiddle:
http://jsfiddle.net/opgp10mj/3/

How to group non-empty lines with PEG.js

I'm trying to parse a categories file with PEG.js
How can I group categories (set of non-empty lines followed by a blank line)
stopwords:fr:aux,au,de,le,du,la,a,et,avec
synonyms:en:flavoured, flavored
synonyms:en:sorbets, sherbets
en:Artisan products
fr:Produits artisanaux
< en:Artisan products
fr:Gressins artisanaux
en:Baby foods
fr:Aliments pour bébé, aliment pour bébé, alimentation pour bébé, aliment bébé, alimentation bébé, aliments bébé
< en:Baby foods
fr:Céréales pour bébé, céréales bébé
< en:Whisky
fr:Whisky écossais
es:Whiskies escoceses
wikipediacategory:Q8718387
For now I can parse line by line with this code:
start = stopwords* synonyms* category+
language_and_words = l:[^:]+ ":" w:[^\n]+ {return {language: l.join(''), words: w.join('')};}
stopwords = "stopwords:" w:language_and_words "\n"+ {return {stopwords: w};}
synonyms = "synonyms:" w:language_and_words "\n"+ {return {synonyms: w};}
category_line = "< "? w:language_and_words "\n"+ {return w;}
category = c:category_line+ {return c;}
I got:
{
"language": "en",
"words": "Artisan products"
},
{
"language": "fr",
"words": "Produits artisanaux"
}
but I want (for each group):
{
{
"language": "en",
"words": "Artisan products"
},
{
"language": "fr",
"words": "Produits artisanaux"
}
}
I tried this too, but it doesn't group and I got \n at the beginning of some lines.
category_line = "< "? w:language_and_words "\n" {return w;}
category = c:category_line+ "\n" {return c;}
I found a partial solution:
start = category+
word = c:[^,\n]+ {return c.join('');}
words = w:word [,]? {return w.trim();}
parent = p:"< "? {return (p !== null);}
line = p:parent w:words+ "\n" {return {parent: p, words: w};}
category = l:line+ "\n"? {return l;}
I can parse this...
< fr:a,b
fr:aa,bb
en:d,e,f
fr:dd,ee, ffff
and get grouped:
[
[ {...}, {...} ],
[ {...}, {...} ]
]
But there is a problem with "lang:" at the beginning of each category, if I try to parse "lang:" my catégories are not grouped...
I find it's useful to break down iteratively the parse (problem decomposition, old-school à la Wirth). Here's a partial solution that I think gets you in the right direction (I didn't parse the Line elements of categories.
start =
stopwords
synonyms
category+
category "category"
= category:(Line)+ categorySeparator { return category }
stopwords "stopwords"
= stopwordLine*
stopwordLine "stopword line"
= stopwordLine:StopWordMatch EndOfLine* { return stopwordLine }
StopWordMatch
= "stopwords:" match:Text { return match }
synonyms "stopwords"
= synonymLine*
synonymLine "stopword line"
= synonymLine:SynonymMatch EndOfLine* { return synonymLine }
SynonymMatch
= "synonyms:" match:Text { return match }
Line "line"
= line:Text [\n] { return line }
Text "text"
= [^\n]+ { return text() }
EndOfLine "(end of line)"
= '\n'
EndOfFile
= !. { return "EOF"; }
categorySeparator "separator"
= EndOfLine EndOfLine* / EndOfLine? EndOfFile
My use of mixed case is arbitrary and not very stylish.
There's also a way to save the solutions online: http://peg.arcanis.fr/2WQ7CZ/

JQGrid Filter Toolbar not filtering rows when using a Formatter on a column

So in a current app, I have to use a custom Formatter on a couple rows in my jqGrid. All these do is take a few fields from my ajax call, concat them into one, and place that into a row.
EG ( data.toStreet + data.toCity + data.toState + data.toZip ) comes back as "Street City, State Zip" into the "To Address" column. This works fine and the data displays correctly, but when using the filtering toolbar, the filter is only based on the first val (data.street). below is a super simplified version of the pieces of code in question.
$('#grid').jqGrid({
...
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name:"toStreet" formatter: ToAddressFormatter},
{name:"fromStreet" formatter: FromAddressFormatter}
],
...
}),
$('#grid').jqGrid('filterToolbar',
{
stringResult:true,
searchOnenter: true,
defaultSearch: 'cn'
}
});
ToAddressFormatter = function(el, opt, rowObj){
var address = rowObj.toStreet+ " " + rowObj.toCity + ", " + rowObj.toState + " " + rowObj.toZip;
return address;
},
FromAddressFormatter = function(el, opt, rowObj){
var address = rowObj.fromStreet+ " " + rowObj.fromCity + ", " + rowObj.fromState + " " + rowObj.fromZip;
return address;
}
So if the value in the cel says "123 fake st, springfield, Va 22344" after being formatted, the filter toolbar can only search on "123 fake st" and nothing else.
Does anybody have any clue on how to remedy this, or possibly why it's happening and a good workaround??
EDIT:
I have included the beginning of my grid. Also, the property Address of result.d is created in the code below, and not returned from the webservice. My column is mapped to "Address" which displays the formatting properly, but still does not search as intended.
$('#grdDisasters').jqGrid({
datatype: function(postdata) {
var obj = { "showActive": $('#btnFilterActive.pressed').length > 0 ? true : false, "showInactive": $('#btnFilterActive.pressed').length > 0 ? true : false,
'page': postdata.page, 'rows': postdata.rows, 'sortIndex': postdata.sidx, 'sortDirection': postdata.sord, 'search': postdata._search,
'filters': postdata.filters || ''
};
$.ajax({
url: "/GetGrid",
data: JSON.stringify(obj),
success: function(result) {
for (var i = 0, il = result.d.rows.length; i < il; i++) {
LoadedDisasters[i] = result.d.rows[i];
result.d.rows[i].cells.Address = result.d.rows[i].cells.Street + " " + result.d.rows[i].cells.City + ", "+ result.d.rows[i].cells.State+ " "+ result.d.rows[i].cells.Zip;
}
result.d = NET.format(result.d);//just correctly format dates
UpdateJQGridData($('#grdDisasters'), result.d);
},
error: function(result) {
//alert("Test failed");
}
});
jqGrid has a problem filtering rows when data is formatted using custom/predefined formatter.
You will have to filter rows on the server-side.
Add 2 more request parameter in your controller to handle jqgrid search request:
When jqGrid requests for filtered raws it will add a parameter: _search with value: true
and all the search parameter like col1=abc&col4=123 meaning user wanted to filter using column named col1 and column named col4 with values respectively: abc and 123
Use those values and query the database with like operation something as follows:
select id, concat(street1, street2, city, state, zip) as address
where address like "%abc%" and id like "%123%"
return these rows as json to jqGrid and display those in the current page. So basically you will have to have a jqGrid with server-side paging, sorting and searching. You can not use client-side paging, sorting and searching features. Also, make sure you don't have loadonce: true set.
I think that you fill the grid in the wrong way. If your source data has toStreet, toCity, toState, toZip, fromStreet, fromCity, fromState, fromZip properties and you need to have composed addressTo and addressFrom you should do this in another way. Your problem is that toStreet and fromStreet will be saved locally in the internal data parameter in the original format like you get it from the server. The local searching uses the data parameter, so the toStreet and fromStreet like you get there from the server will be used.
You don't posted more full code of jqGrid which you use. So I suppose that you use datatype: 'json', datatype: 'jsonp' or datatype: 'xml' in combination with loadonce: true. You should define colModel
$('#grid').jqGrid({
...
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name: "addressTo", ...},
{name: "addressFrom", ...}
],
beforeProcessing: function (data) {
var i, rows = data.rows, l = rows.length, item;
for (i = 0; i < l; i++) {
item = rows[i];
item.addressTo = item.toStreet + " " + item.toCity + ", " +
item.toState + " " + item.toZip;
item.addressFrom = item.fromStreet+ " " + item.fromCity + ", " +
item.fromState + " " + item.fromZip;
}
}
...
});
The exact code depend on the format of the input data. The advantage of the usage of beforeProcessing is that it will be called before the data will be processed by jqGrid. So you can do any modification in the data or like in the above.
UPDATED: The code of datatype can be easy implemented in another way using standard jqGrid options. So I suggest to use the following settings:
datatype: "json",
url: "/GetGrid",
postData: {
// add and to the list of parameters sent to the web service
showActive: function () {
return $('#btnFilterActive.pressed').length > 0;
},
showInactive: function () {
return $('#btnFilterActive.pressed').length > 0;
}
},
prmNames: {
// rename some parameters sent to the web service
sort: "sortIndex",
order: "sortDirection",
search: "search",
// don't send nd parameter to the server
nd: null
// you leave the nd is you don't set any "Cache-Control" HTTP header
// I would recommend you to set "Cache-Control: private, max-age=0"
// For example
// HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan(0));
},
serializeGridData: function (postData) {
// control modification of the the data (parameters) which will be sent
// to the web method
if (typeof postData.filters === "undefined") {
postData.filters = "";
}
return JSON.stringify(postData);
},
ajaxGridOptions: { contentType: "application/json" },
jsonReader: {
root: "d.rows",
page: function (obj) { return obj.d.page; },
total: function (obj) { return obj.d.total; },
records: function (obj) { return obj.d.rows.length; },
repeatitems: false
},
loadError: function (jqXHR, textStatus, errorThrown) {
// see an implementation example in the answers
// https://stackoverflow.com/a/6969114/315935
// and
// https://stackoverflow.com/a/5501644/315935
},
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name: "addressTo", ...},
{name: "addressFrom", ...}
],
beforeProcessing: function (data) {
var i, rows, l, item;
data.d = NET.format(data.d); // just correctly format dates
rows = data.d.rows;
l = rows.length;
for (i = 0; i < l; i++) {
item = rows[i];
LoadedDisasters[i] = item;
item.addressTo = item.toStreet + " " + item.toCity + ", " +
item.toState + " " + item.toZip;
item.addressFrom = item.fromStreet+ " " + item.fromCity + ", " +
item.fromState + " " + item.fromZip;
}
}
...
The usage of nd: null with setting of "Cache-Control: private, max-age=0" I described in the answer. You can download the corresponding demo project which use this. In general one needs just include one additional line where you call SetMaxAge
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public MyGridData GetGrid(...) {
HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan(0));
...
}
See more about caching control you can read here.

Resources