Sorting custom (currency) formatted column in backgrid - javascript

I'm using Backgridjs to display data from json object to table. I'm currently using a formatter to format string-numbers into currency. Once I did that the sorting no longer work properly as it sorting as a string rather than number. How can I enable sorting with backgrid after formatting my column ?
Backgrid support numbers, int, date/momentjs. Couldn't find extension for currency
this is my formatter class
formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
fromRaw: function(rawData) {
var re = /\-/;
if (rawData === "" || rawData == null) {
return "";
} else if (rawData.match(re)) {
return "-" + accounting.formatMoney(rawData.substr(1));
} else {
return accounting.formatMoney(rawData);
}
},
toRaw: function(formattedData) {
return formattedData;
}
}),
And this is my grid
var grid = new Backgrid.Grid({
collection: collection,
columns: [
{
name: "cost",
label: "Cost",
cell: "number",
formatter: currencyFormater
sortable: true
},
{
name: "type",
label: "Type",
cell: Backgrid.NumberCell,
sortable: true
}
]});
Example of data:
{ id: 1, cost: "150", type: 3 },
{ id: 2, cost: "12516.30", type: 2 },
{ id: 3, cost: "21400.85", type: 1 },
{ id: 4, cost: "146558.50", type: 1 },
{ id: 5, cost: "139982.75", type: 1 }

I ended up using sortValue to do specific sorting base on value. In my case I used parseFloat with the string value.
var grid = new Backgrid.Grid({
collection: collection,
columns: [
{
name: "cost",
label: "Cost",
cell: "number",
sortValue: function(model) {
return parseFloat(model.get("cost"));
},
formatter: currencyFormater
sortable: true
},
…
]});

Related

Datatables date sort vs date display

I am using Datatables to display a table and I am pulling a list of datestimes from a MySQL database. These date times are not standard dates and look like this:
12/30/19 # 04:17 pm
How can I sort these accurately with Datatables?
Here is my code:
getRes(function (result) { // APPLIED CALLBACK
$('#resdatatable').DataTable({
data: result, // YOUR RESULT
order: [[ 0, "desc" ]],
autoWidth: false,
responsive: true,
columns: [
{ data: 'id', title: 'ID' },
{ data: 'bookingdatetime', title: 'Booking Date' },
{ data: 'name', title: 'Name' },
{ data: 'class', title: 'Class' },
{ data: 'pickupdatetime', title: 'Pick up' },
{ data: 'duration', title: 'Duration' },
{ data: 'dropdatetime', title: 'Drop off' },
{ data: 'age', title: 'Age' },
{ data: 'coverage', title: 'Coverage' },
{ data: 'quote', title: 'Quote' },
{
data: 'status',
title: 'Status',
render: function(data, type, row) {
let isKnown = statusList.filter(function(k) { return k.id === data; }).length > 0;
if (isKnown) {
return $('<select id="resstatus'+row.id+'" onchange="changeResStatus('+row.id+')" data-previousvalue="'+row.status+'">', {
id: 'resstatus-' + row.id, // custom id
value: data
}).append(statusList.map(function(knownStatus) {
let $option = $('<option>', {
text: knownStatus.text,
value: knownStatus.id
});
if (row.status === knownStatus.id) {
$option.attr('selected', 'selected');
}
return $option;
})).on('change', function() {
changeresstatus(row.id); // Call change with row ID
}).prop('outerHTML');
} else {
return data;
}
}
}
]
});
});
/**
* jQuery plugin to convert text in a cell to a dropdown
*/
(function($) {
$.fn.createDropDown = function(items) {
let oldTxt = this.text();
let isKnown = items.filter(function(k) { return k.id === oldTxt; }).length > 0;
if (isKnown) {
this.empty().append($('<select>').append(items.map(function(item) {
let $option = $('<option>', {
text: item.text,
value: item.id
});
if (item.id === oldTxt) {
$option.attr('selected', 'selected');
}
return $option;
})));
}
return this;
};
})(jQuery);
// If you remove the renderer above and change this to true,
// you can call this, but it will run once...
if (false) {
$('#resdatatable > tbody tr').each(function(i, tr) {
$(tr).find('td').last().createDropDown(statusList);
});
}
function getStatusList() {
return [{
id: 'Confirmed',
text: 'Confirmed'
}, {
id: 'Unconfirmed',
text: 'Unconfirmed'
}, {
id: 'Communicating',
text: 'Communicating'
}, {
id: 'Open',
text: 'Open'
}, {
id: 'Closed',
text: 'Closed'
}, {
id: 'Canceled',
text: 'Canceled'
}, {
id: 'Reallocated',
text: 'Reallocated'
}, {
id: 'No Show',
text: 'No Show'
}];
}
I need to sort bookingdatetime, pickupdatetime, dropdatetime accurately (they are currently being converted into MM/DD/YY in the PHP script)
Maybe you can prepend hidden <span> elements containing the respective unix timestamps in the cells that have dates (by manually parsing the dates). Then using such columns to sort alphabetically would practically sort time-wise.

ExtJS Add filtering in Grid for hasMany association

I have a data model that I want to be able to add a generic amount of filters to. I am specifying a name and a value. How can I add these hasMany associated fields as filters to my grid? I have attempted to write custom filtering option, but I can't have filters show up without an attached dataIndex, which is not available for the hasMany association.
Ext.define('AirGon.model.Project', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Link', type: 'string' },
{ name: 'Title', type: 'string' },
{ name: 'Description', type: 'string' },
{ name: 'MappedMetadata', mapping: 'Metadata'},
{ name: 'XMax', type: 'float' },
{ name: 'XMin', type: 'float' },
{ name: 'YMax', type: 'float' },
{ name: 'YMin', type: 'float' }
],
hasMany: { model: 'Metadata', name: 'Metadata', associationKey: 'Metadata' }
});
Ext.define('Metadata', {
extend: 'Ext.data.Model',
fields: ['Name', 'Value']
});
This is my custom filtering attempt. I am getting the DataStore from the main store and then adding custom rendering, but I can't filter or sort this column because of the lack of a dataIndex.
var column = {
header: 'Meta',
//?????????dataIndex: 'MappedMetadata[0]',?????
sortable: true,
filterable: true,
filter: {
type: 'string'
},
renderer: function (value, meta, record) {
console.log(record.MetadataStore.data.items[index].data)
return record.MetadataStore.data.items[index].data.Value;
}
}
Data. The data is modeled so that a variable amount of metadata can be entered and the 'tag' will not be known by the system.
{
"Link": "link.com",
"Title": "project",
"Description": "descript",
"State": "",
"Metadata": [
{
"Name": "County",
"Value": "32"
},
{
"Name": "Info",
"Value": "info"
},
{
"Name": "State",
"Value": "TN"
}
],
"XMin": "-1",
"XMax": "-1",
"YMin": "1",
"YMax": "1"
}
I was able to solve this by dynamically flattening the data model and adding columns once the store has been loaded. Although this breaks the MVC structure this was the best solution I came up with so it might be able to help you.
var defaultColumns = [];
var store = Ext.getStore('store');
store.on('load', function (store) {
var model = store.model;
var fields = model.getFields();
store.getAt(0).MetadataStore.data.items.forEach(function (item, index) {
var header = item.data.Name;
//isField returns a boolean if the field is already part of the data model
if (!isField(fields, header)) {
//Add a new metadata field to the data model
var field = { name: header, mapping: 'Metadata[' + index + '].Value' }
fields.push(field)
//Add a new metadata column
var column = {
header: header,
dataIndex: header,
sortable: true,
filterable: true,
filter: {
type: 'list'
},
flex: 0.2
}
defaultColumns.push(column);
}
});
model.setFields(fields);
//reload the grid after adding columns
var gridView = Ext.ComponentQuery.query('gridpanel')[0];
gridView.reconfigure(store, defaultColumns);
});
//reload the data after creating new fields
store.load();
I then set the columns of the grid to defaultColumns.
{
xtype: 'grid',
store: 'Projects',
overflowX: 'auto',
autoScroll: true,
features: [filters],
columns: defaultColumns
}

Kendo UI Dropdownlist checked

I have a kendo ui function dropdownlist, and it will call at Grid column editor. My question, by default how to display "Yes" when Add New Record in edit function. Currently it display null when Add New Record.
Demo in Dojo
Here I provide a working demo. Thank You
If I understand correctly you only have to add a default value to the Price in the Model?
"Price": {type: "string", defaultValue: "y" },
I include the whole function, just in case:
$(function() {
$("#grid").kendoGrid({
dataSource: {
data: [
{ Name: "Young John", Price: "y" },
{ Name: "John Doe", Price: "n" },
{ Name: "Old John", Price: "y" }
],
schema: {
model: {
id: "id",
fields: {
"id": { type: "number" },
"Price": {type: "string", defaultValue: "y" },
}
}
}
},
editable: "inline",
toolbar: ["create"],
columns: [{ field: "Name"},
{ field: "Price",
template: "#=(data.Price == 'y' ? 'Yes' : 'No')#",
editor: radioPrice
} ],
edit: function(e) {
if (e.model.isNew()) {
e.model.Price = 'y';
}
}
});
});

Javascript - How to return a partial array from a function?

I would like to insert in the middle of a columns array, many elements based on a parameter returned by the function getSpecificColumns(parameter).
The first one is working cause it is returning a single object, but is there any way to return many elements in the middle of the array?
$scope.getSpecificColumns = function (myParam) {
return { field: "SpecificField1", format: "{0:c}" };
}
$scope.getSpecificColumnsNotWorking = function (myParam) {
return { field: "SpecificField2", format: "{0:c}" },
{ field: "SpecificField3", format: "{0:c}" };
}
$scope.positionMontantNavGridOptions = {
height: 630,
filterable: {
mode: "row"
},
pageable: true,
columns: [
{ field: "Field1", width: "200px" },
{ field: "Field2", title: "Field 2", width: "80px" },
getSpecificColumns(parameter),
{ field: "Field4" }
]
}
If you want to return an array, return an array:
$scope.getSpecificColumnsNotWorking = function (myParam) {
return [{ field: "SpecificField2", format: "{0:c}" },
{ field: "SpecificField3", format: "{0:c}" }];
}
A expression such as:
{ field: "SpecificField2", format: "{0:c}" },{ field: "SpecificField3", format: "{0:c}" };
evaluates to the former of the comma delimeted "sub-expressions", for example:
var a = 1, b = 2;
var c = a, b;
alert(c === a);
and in your original code this directly translates to the first literal object being returned from the function while the later is "discarded".
(By the way, if you're not using the myParam argument you might as well not define it and not pass it in the call)
First return array, then use Array.prototype.concat to flaten it into array.
Is this a suitable solution for your problem?
$scope.getSpecificColumnsNotWorking = function (myParam) {
return [
{ field: "SpecificField2", format: "{0:c}" },
{ field: "SpecificField3", format: "{0:c}" }
];
}
columns: [].concat(
{ field: "Field1", width: "200px" },
{ field: "Field2", title: "Field 2", width: "80px" },
getSpecificColumnsNotWorking (parameter),
{ field: "Field4" });

GridBooleanColumn with data first by 0 and 1 but no true and false

In my db I have a column Actif with values 0 and 1 (false and true)
I tried to use a column. Boolean with my db values 0 and 1 ... but it doesn't work.
{
xtype: 'booleancolumn',
dataIndex: 'Actif',
text: 'MyBooleanColumn',
falseText: 'Non',
trueText: 'Oui'
}
Help me please :)
My Model
Ext.define('ModuleGestion.model.UtilisateursApplicatifs', {
extend: 'Ext.data.Model',
fields: [
{
name: 'Nom'
},
{
name: 'Prenom'
},
{
name: 'Identification'
},
{
name: 'MotDePasse'
},
{
name: 'IUtilisateurApplicatif'
},
{
name: 'FonctionRepertoire'
},
{
name: 'FonctionAnimation'
},
{
name: 'FonctionFormation'
},
{
name: 'FonctionAdministration'
},
{
name: 'Actif'
}
]});
the solution is delete the double quote of the return of the values :
$resultat = json_encode($resultat );
$resultat = str_replace('"Actif":"0"', '"Actif":0', $resultat);
$resultat = str_replace('"Actif":"1"', '"Actif":1', $resultat);
I have similar situation and for work with 0 and 1 from db I use not boolean column. From db I send 0 and 1, in my column renderer I check this and make some conversions. Check my example(here's actioncolumn - it's for show icons in cells). It's one way to decision your situation.
My view:
xtype: 'actioncolumn',
width: 55,
align: 'center',
dataIndex: 'Actif',
menuDisabled: 'true'
text: '',
sortable: false,
fixed: 'true',
renderer: function (value, metadata, record) {
if (value == '0') {
//some code
}
else {
//some code
}
},
getTip: function (value, metadata, record) {
if (value == '0') {
return 'here 0';
} else {
return 'here 1';
}
}
You don't need to change model.
In your example I think you should add type of you'r field in model.
here's example
{ name: 'Actif', type: 'boolean' }

Categories