Row Numbers for backgrid - backgrid

How to assign row numbers to rows of a backgrid without defining this as one of the columns?
I want to assign row numbers starting from 1; with or without text in header

You can do that slightly inefficiently now like so:
var RowNumberCell = Backgrid.StringCell.extend({
render: function () {
return this.model.collection.indexOf(this.model) + 1;
}
});
var columns = [{
name: "",
cell: RowNumberCell,
editable: false,
sortable: false
},
...
];

I had to make a slight edit to Y.H Wong's answer, as I kept getting the following error.
'Node': parameter 1 is not of type 'Node'
By using the following code, I was able to get the desired behaviour, albeit using the same slightly inefficient method.
// Row Number Cell.
var RowNumberCell = Backgrid.StringCell.extend({
render: function () {
const number = this.model.collection.indexOf(this.model) + 1;
this.$el.text(number);
return this;
}
});

Related

Is it possible to get / return Highcharts Axis values?

I would like to be able to use the values printed on Highcharts x and y axes when the chart renders in another part of my app, so for example an array of number from 0 to n.
I am using highcharts-react-official - I can't find any documentation on methods that return the values as they are printed exactly on the screen.
Is this possible?
Update
With this code I can return an array of numbers that represent the tick values on the y axis:
const options: Highcharts.Options = {
yAxis: {
labels: {
formatter(): string {
console.log('YAXIS', Object.keys(this.axis.ticks)
}
}
}
}
Although the array includes a negative number which I cannot see in the chart axis itself.
The same trick does not work for the x axis.
Is there a cleaner approach do getting the correct result?
Update 2
Following the solution below I finally got what I was looking for:
This does not work as you would expect:
const res = this.yAxis
.map((axis) => axis.ticks)
.map((axisTicks) => Highcharts.objectEach(axisTicks, (tick) => tick.label.textStr));
console.log(res); // undefined;
However this does:
const yAxisVals: string[][] = [];
const axisTicks = this.yAxis.map((axis) => axis.ticks);
axisTicks.forEach((item, idx) => {
yAxisVals[idx] = [];
Highcharts.objectEach(item, (tick) => yAxisVals[idx].push(tick.label.textStr));
});
console.log(yAxisVals);
You can use render event and get the values by Axis.tickPositions property:
chart: {
events: {
render: function() {
var xAxisTickPositions = this.xAxis[0].tickPositions,
yAxisTickPositions = this.yAxis[0].tickPositions;
console.log(xAxisTickPositions, yAxisTickPositions);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4960/
API Reference:
https://api.highcharts.com/highmaps/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.Axis#tickPositions

Angular table sorting

I need to sort table items by clicking table header. My column values number as string. So sorting is not applying as I wish. I know I should convert my string into float. I need comma separator and double point precision as well. I tried to do parseFloat but that's not working.
Example. I want to sort "123,456.00", "345", "-34.00", "7.78" kind of strings. I shared jsfiddle link to explain my scenario.
http://jsfiddle.net/k4seL1yx/1/
function SortableTableCtrl() {
var scope = this;
scope.head = {
a: "Poured",
b: "Sold",
c: "Loss"
};
scope.body = [{"ID":"September-2016", "Product":"September-2016", "Poured":"111759.07", "Sold":"107660.97", "Loss":"-4098.10", "Variance":"-3.67", "startDate":"2016-09-01", "endDate":"2016-09-22"}, {"ID":"November-2015", "Product":"November-2015", "Poured":"53690.25", "Sold":"52953.60", "Loss":"-736.65", "Variance":"-1.37", "startDate":"2015-11-20", "endDate":"2015-11-30"}, {"ID":"May-2016", "Product":"May-2016", "Poured":"156401.65", "Sold":"151192.51", "Loss":"-5209.14", "Variance":"-3.33", "startDate":"2016-05-03", "endDate":"2016-05-31"}, {"ID":"March-2016", "Product":"March-2016", "Poured":"49260.22", "Sold":"49399.14", "Loss":"138.92", "Variance":"0.28", "startDate":"2016-03-01", "endDate":"2016-03-09"}, {"ID":"June-2016", "Product":"June-2016", "Poured":"162126.88", "Sold":"161718.62", "Loss":"-408.26", "Variance":"-0.25", "startDate":"2016-06-01", "endDate":"2016-06-30"}, {"ID":"July-2016", "Product":"July-2016", "Poured":"160185.68", "Sold":"154882.40", "Loss":"-5303.28", "Variance":"-3.31", "startDate":"2016-07-01", "endDate":"2016-07-31"}, {"ID":"January-2016", "Product":"January-2016", "Poured":"355509.26", "Sold":"179696.72", "Loss":"-175812.54", "Variance":"-49.45", "startDate":"2016-01-01", "endDate":"2016-01-31"}, {"ID":"February-2016", "Product":"February-2016", "Poured":"150980.73", "Sold":"146248.72", "Loss":"-4732.01", "Variance":"-3.13", "startDate":"2016-02-01", "endDate":"2016-02-29"}, {"ID":"December-2015", "Product":"December-2015", "Poured":"167843.42", "Sold":"163732.95", "Loss":"-4110.47", "Variance":"-2.45", "startDate":"2015-12-01", "endDate":"2015-12-31"}, {"ID":"August-2016", "Product":"August-2016", "Poured":"168853.51", "Sold":"160024.84", "Loss":"-8828.67", "Variance":"-5.23", "startDate":"2016-08-01", "endDate":"2016-08-31"}]
scope.sort = {
column: 'b',
descending: false
};
scope.selectedCls = function(column) {
return column == scope.sort.column && 'sort-' + scope.sort.descending;
};
scope.changeSorting = function(column) {
var sort = scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
};
}
I found a solution for my question. Actually I am very focused on convert "poured, sold, loss" from string to float. But why I should not create a new column as clone of this and the format of that is float. parseFloat done the magic. So I can use Poured value for table show and use pouredClone value for sorting on the behind.
//Initially I got the above scope.body only. To perform sorting I modified scope.body as like below
scope.body.forEach(function(value) {
value.pouredClone = parseFloat(value.Poured)
value.soldClone = parseFloat(value.Sold)
value.lossClone = parseFloat(value.Loss)
value.varianceClone = parseFloat(value.Variance)
});
Here is the link of fiddle with solution.
http://jsfiddle.net/q7mcu6fx/1/

ng-grid column size problems. And ng-if issue

I am having problems with my grid column widths in ng-grid. My issue is that I don't know ahead of time what the columns will be (they are retrieved from a service call at the same time as the values. My Json object has two properties in it. An array of strings for column names and then a 2d array for values. currently the columns do not size to fit the column headers. I understand the columns will resize to fit the row data but what if no results are returned. then you have a mess. I tried making it so I did not have to set grid options until I had my data but then get an undefined error. I saw another post where the solution for that was to use ng-if in the div tag so the grid does not load until you want it to. that did not work either as the grid still tried to load before the if statement was satisfied. Below is my code. any thoughts? also,my ng-if was like this: ng-if="contentAvailable". Also adding a screen shot. My expectations would be for a horizontal scrollbar to show up.
app.controller('mainController',function($scope,dataFactory){
$scope.contentAvailable = false;
$scope.gridOptions = {
columnDefs: 'columns',
showGroupPanel: true
};
$scope.url = 'http://example.com';
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function (str) {
return this.indexOf(str) == 0;
};
}
$scope.Fetch = function () {
dataFactory.Fetch($scope.url,$scope.config).success(function (blah) {
var result = $scope.transformJsonDataSet(blah);
})
.error(function (error) {
$scope.result = error;
});
};
$scope.transformJsonDataSet = function (ds) {
var tmp = angular.fromJson(ds);
var fieldNames = tmp.FieldNames;
var fieldValues = tmp.FieldValues;
var columns = [];
for (var i = 1; i < fieldNames.length; i++) {
if (fieldNames[i].startsWith('DECODE_') == false) {
columns.push({ field: fieldNames[i], displayName: fieldNames[i], cellClass: 'headerStyle'});
}
}
$scope.columns = columns;
$scope.contentAvailable = true;
return ds;
};
});
app.factory('dataFactory', ['$http', function ($http) {
var dataFactory = {};
dataFactory.Fetch = function (url,config) {
return $http.get(url,config);
};
return dataFactory;
}]);
There's no $scope.columns declared in your controller?
Try defining a $scope.columns variable and assign it an empty variable:
app.controller('mainController',function($scope,dataFactory){
$scope.contentAvailable = false;
$scope.columns = [];
$scope.gridOptions = {
columnDefs: 'columns',
showGroupPanel: true
};
/* */

ExtJS - Drag column header to other grid

I need keep the default feature of reordering columns and add
possibility drop the column in a second grid, building in the last a list
with the columns of first grid.
I hope has been clear.
I solved the issue extending DropZone. This implementation receive as constructor param the target grid, and this, be in the rbar (docked control) of source grid. The key is set ddGroup to "header-dd-zone-" plus id from source grid. I hope this is useful.
Ext.define('Crud.FilterDropZone', {
extend: 'Ext.dd.DropZone'
, constructor: function() {}
, init: function (grid) {
var me = this;
if (grid.rendered) {
me.grid = grid;
me.ddGroup = 'header-dd-zone-' + grid.up('grid').id;
grid.getView().on({
render: function(v) {
me.view = v;
Crud.FilterDropZone.superclass.constructor.call(me, me.view.el);
},
single: true
});
} else {
grid.on('render', me.init, me, {single: true});
}
}
, getTargetFromEvent: function (e) {
return {};
}
, onNodeDrop: function (nodeData, source, e, data) {
var header = data.header
, store = Ext.getCmp(e.target.id).getStore();
//store.add(new store.RecordType({ property: header.text, value: '', reference: header.dataIndex}));
store.add([[header.text, '', header.dataIndex]]);
}
});

DisplayField - How to format for date?

I need to display a read only view of data. I've chosen the DisplayField component to do this. My problem is that I would like an easy way to call BasicForm.setValues(values) and have a date string automagically render correctly in one of the displayFields. I haven't found anything that will do this for me (e.g. a renderer function), and am about to just format the date string manually prior to calling setValues(values). Is there some slick way to do this?
Thanks!
Ok if you are using a direct form load then you need to listen for the form's BasicForm 'actioncomplete' event. When this event fires the handler is supplied two arguments. The first is the BasicForm and the second argument is an Ext.form.Action object. We are specifically looking for an Ext.form.Action.Load object. From here we get access to the action's result.data object and we can massage the data values before this handler returns and the values are loaded into the form.
function fmtDate(sf, rec) {
if ( rec[sf] ) {
var dt = new Date(); dt.setTime(rec[sf] * 1000); return dt.format('l j F Y');
}
};
myForm.getForm().on({
actioncomplete: function(form, action) {
if (action.type === 'load') {
if (action.result.success) {
var data = action.result.data;
data.someFormattedDate = fmtDate('myDateTS', data);
} else {
//handle an error here
}
}
}
});
Now all you need in your form is a displayField named 'someFormattedDate' and Bob's your uncle (Aussie slang for it's all good). You can also achieve exactly the same thing by providing a 'success:' function to your myForm.getForm().load() call. See the ExtJS docs for Ext.form.Action.Load.
Cheers, t00bs.
I ended up subclassing displayField. That seems to work best, but I wish there was an out-of-the-box fix for something as basic as displaying a formatted date. This is my first pass at it, so it is just an example.
FormattableDisplayField = Ext.extend(Ext.form.DisplayField, {
constructor:function(config) {
var config = config || {};
Ext.applyIf(config, {
dateFormat:'c',
type:null,
displayFormat:'M d, Y'
});
FormattableDisplayField.superclass.constructor.call(this, config);
},
setValue: function(value) {
if (! this.type) {
FormattableDisplayField.superclass.setValue(value);
}
else if (this.type == 'date') {
var parsedDate = Date.parseDate(value, this.dateFormat);
if (Ext.isDate(parsedDate)) {
this.setRawValue(parsedDate.format(this.displayFormat));
}
else {
this.setRawValue(value);
}
}
else if (this.formatter) {
var formattedValue = this.formatter(value);
this.setRawValue(formattedValue);
}
}
});Ext.reg('formattabledisplayfield', FormattableDisplayField);
I came across this same problem because I like to pass my dates around as Unix timestamps and I had a requirement to display them using various formats depending on context. Here's how I did it.
If you are loading the data via a store then you can use the convert function provided by Ext.data.Field. For example:
var fields = [
{name: 'sysTestedDateObj', mapping: 'sysTestedDateTS', type: 'date', dateFormat: 'timestamp'},
/** Converted Fields **/
{name: 'sysTestedDate', convert: function(v, rec){
return fmtDate('sysTestedDateTS', rec);
}},
{name: 'targetChangeStartDate', convert: function(v, rec){
return fmtDate('targetChangeStartDateTS', rec);
}},
{name: 'createDateTime', convert: function(v, rec){
return fmtDateTime('createDateTS', rec);
}},
{name: 'modifyDateTime', convert: function(v, rec){
return fmtDateTime('modifyDateTS', rec);
}},
];
var store = new Ext.data.JsonStore({
...
fields: fields
});
Here's some conversion functions:
function fmtDate(sf, rec) {
if ( rec[sf] ) {
var dt = new Date(); dt.setTime(rec[sf] * 1000); return dt.format('l j F Y');
}
};
function fmtDateShort(sf, rec) {
if ( rec[sf] ) {
var dt = new Date(); dt.setTime(rec[sf] * 1000); return dt.format('D j M Y');
}
};
function fmtDateTime(sf, rec) {
if ( rec[sf] ) {
var dt = new Date(); dt.setTime(rec[sf] * 1000); return dt.format('l j F Y h:i a');
}
};
function fmtDateTimeShort(sf, rec) {
if ( rec[sf] ) {
var dt = new Date(); dt.setTime(rec[sf] * 1000); return dt.format('D j M Y h:i a');
}
};
Where sf is the source field we are deriving the formatted date string from.
Note the following, it's important. The convert() function is presented with a copy of the data record as read by the reader (this is in the ExtJS docs). This means you can't use any mapped fields in your conversions. In the fields array above I have a field defined as,
{name: 'sysTestedDateObj', mapping: 'sysTestedDateTS', type: 'date', dateFormat: 'timestamp'}
So I'm creating the sysTestedDateObj date object from the sysTestedDateTS field and I've told the reader that I want it to give me a date object derived from an object containing a Unix timestamp. This is a nice object to have for later on but it won't be part of the data record passed to our conversion function.
Also note that a conversion function can reference fields in the record that are not defined for use by the store. In the example above I an using the field sysTestedDateTS in a conversion function because I know the server is supplying it in it's JSON response, yet because I haven't defined it in the fields array it won't be available via the store to the consuming component.
http://dev.sencha.com/deploy/dev/docs/?class=Ext.util.Format
I think dateRenderer is the renderer function that you are looking for?
Ext.form.field.Display.html#cfg-renderer
A function to transform the raw value for display in the field.
Ext.Date.html#method-format
Formats a date given the supplied format string.
var data = {
"OrderNo": "2017071200000246",
"Createtime": "2017/7/12 13:16:42"
}; // your read only data; or use bind store
var form = Ext.create({
xtype: 'form',
defaultType: 'displayfield',
defaults: {
labelWidth: 120,
labelSeparator: ':'
},
items: [
{ fieldLabel: 'Order Number', value: data.OrderNo },
{ fieldLabel: 'Create Time', value: data.Createtime,
renderer: function (value, field) {
var date = new Date(value);
var newVal = Ext.Date.format(date, 'Y-m-d H:i:s');
return newVal;
}
}
]
});

Resources