Formatting ExtJS grid column - formatting

I know I can format an ExtJs grid's column by using Ext.Util.Format class.
I want to know how can I apply following format types:
Showing percent symbol for a number without multiplying it by 100. So If the value is 10.34 it should show 10.34% and now 1034%.
If the number is negative it should be shown in red color insde brackets. so -23 should be shown in red color as (23).
Thank you

I would have liked to have some more details :
Do you want to apply both renderings to a single column?
Could you provide a concise code sample of what you have already tried (store/model bound to the grid panel, raw data to feed the store, column configuration(s))?
Anyway, I can give it a try (you should read the doc first).
Renderer 1 :
renderer: function (value) {
return value + '%';
}
Renderer 2 :
renderer: function (value) {
return value < 0
? '<span style="color:red">(' + Math.abs(value) + ')</span>'
: value;
}
Frankenstein's monster :
renderer: function (value) {
return value < 0
? '<span style="color:red">(' + Math.abs(value) + '%)</span>'
: value + '%';
}

Yes, you can achieve through renderer concept, please refer below sample for your queries.
{
text : 'Number (Percentage)',
width : 80,
sortable : true,
renderer : function(val) {
if (val > 0) {
return '<span style="color:green;">' + val + '</span>';
} else if (val < 0) {
return '<span style="color:red;">' + val + '</span>';
}
return val+"%";
},
dataIndex: 'numberChange' // place your dataindex binding here
}
Thanks, Hope this will help you...

You could easily implement a renderer for the columns, and transform the results however you'd like. All you have to do is return the transformed string from the renderer; plus, you have access to the full Ext.data.Record for the grid row (as well as the store, for that matter), so you can also easily do custom renderings based on other data within the record, if needed.

Related

Vue.js: error setting a computed property

in the following code (jsbin available here) I have two input elements, a range and a text, bound together via a computed property.
var vm = new Vue({
el: '#main-container',
data: {
sliderValue: 100,
},
computed: {
actualValue: {
get: function() {
if (this.sliderValue <= 100) {
return this.sliderValue;
} else {
return Math.round(this.sliderValue * 12.5 - 1150);
}
},
/* set won't work for val > 100*/
set: function(val) {
if (val <= 100) {
this.sliderValue = val;
} else {
this.sliderValue = Math.round((val + 1150)/12.5);
}
}
}
},
methods: {
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="main-container">
<input type="range" v-model="sliderValue" min=1 max=132>
<input type="text" v-model="actualValue">
<p>Slider: {{sliderValue}}</p>
<p>Actual: {{actualValue}}</p>
</div>
The range goes from 1 to 132, and its range is mapped [1..500] in the text input, with a simple transformation (basically it's a linear mapping with two different slopes for [1..100] and [101..132]) using the actualValue computed property.
Getting actualValue works as expected: dragging the slider correctly updates the input text with appropriate values in the range [1..500].
I'm not able to find a way to set actualValue, though. I'd like to be able to type a value in the text input, and make the slider's thumb update accordingly to the inverse transformation (val + 1150)/12.5.
It works as long as the typed number is in the range [1..100], but it "explodes" for numbers >100, e.g. 101 makes the sliderValue jump at 80892 and actualValue is then re-calculated as 1010000. As far as I understand, it's a looping-feedback scenario.
I've tried also alternative approaches (watch; v-on:change in the text input; using a third variable) to no avail.
Thanks in advance for any suggestion!
It's an amazing puzzle, and challenged me for a long time!
Look at the screenshot below. Your sliderValue and actualValue are strings, not integers. When you set actualValue as 101, you are actually setting it as a string value of "101"
Now, your sliderValue = ((actualValue + 1150)/12.5)
"101" + 1150 = "1011150" (another string!, try it in the developer console)
That messes up your entire calculation. Now you know how to fix it :-)
And you need to get that Vue devtools from here: https://github.com/vuejs/vue-devtools
EDIT: Response to comment #3
Here is the modified jsBin: http://jsbin.com/mahejozeye/1/edit?html,js,output
The only difference is introduction of two console.log statements in your map2 function. This helps you identify if your non-linear mapping function is working correctly or not. If you keep your developer console open, you will see what is happening in this function.
Case 1: When you set the value radius = 25 using the text box, your sliderRadius gets set to 111.55518394648828 and your radius again gets re-calculated as 25. So it comes around in a full circle and everything is stable here.
Case 2: When you set the value radius = 55, your sliderRadius gets set to 173.03607214428857 through your non-linear map2() function, which resets radius to 51.29869180420927
Clearly there is a circular dependency issue. Your sliderRadius and radius are very much dependent on each other and therefore radius is unable to take the value between 51 and 58.
You need to evaluate why it happens, as it has a lot to do with the non-linear mapping function that you have defined. The moment radius can take stable values at 55 (through the map2 function), then your current problem will be resolved.
The simplest fix is to set your input type to number:
<input type="number" v-model="actualValue">
or you can convert your value to an integer with something like:
set: function(val) {
var intVal = parseInt(val, 10);
if (!isNaN(intVal)) {
if (intVal <= 100) {
this.sliderValue = Math.max(1, intVal);
} else {
this.sliderValue = Math.min(132, Math.round((intVal + 1150) / 12.5));
}
}
}

DataTables convert incoming epoch date to dd/mm/yyyy

I am using an AJAX call with datatables to populate a table. The format of the incoming data is:
{
"name": "John Doe",
"date":1244231200500
}
I can see that date formatting is discussed here: https://datatables.net/blog/2014-12-18 but there's no clear instructions for epoch data conversion.
What I want to do is put something (like within the example at the datatables site) like:
$.fn.dataTable.moment('epoch');
...but I don't see an option. What's the best approach here?
If you include moment.js you can sort this out quite easily using moment within a render function of your columns option array. Something like this should work:
{
"data":"date",
"render": function(data){
return moment.unix(data).format("DD/MM/YYYY")
}
}
Hope that helps.
You could create your own formatting function:
function ISODateString(d) {
function pad(n) { return n < 10 ? '0' + n : n }
return pad(d.getDate()) + '/' + pad(d.getMonth() + 1) + '/' + d.getFullYear();
}
And call it in datatables render:
"render": function(data){
var d = new Date(parseInt(data.substr(6), 0));
return ISODateString(d);
}

How to keep page length where there is fewer results?

When searching through a table or navigating to the last page of the table there may be fewer results that the pageLength setting, so table shinks in height. I would like to prevent that by filling missing rows with empty rows. How can I do that?
You can use the bScrollCollapse property along with sScrollY.
As documentation say:
When vertical (y) scrolling is enabled, DataTables will force the
height of the table's viewport to the given height at all times
(useful for layout). However, this can look odd when filtering data
down to a small data set, and the footer is left "floating" further
down. This parameter (when enabled) will cause DataTables to collapse
the table's viewport down when the result set will fit within the
given Y height.
You can use it like this:
var table = $('#example').dataTable({
"sScrollY": "400",
"bScrollCollapse": false
});
An example of this is here http://live.datatables.net/ukiyek/115/edit#javascript,html
UPDATE:
You can also set the table height to 100% so that the whole area to be filled:
var table = $('#example').dataTable({
"sScrollY": "400",
"bScrollCollapse": false,
"fnDrawCallback": function() {
$(this).attr("height","100%");
}
});
Example here
UPDATE 2:
Found exactly what you are looking for in this thread http://www.datatables.net/forums/discussion/4112/possible-to-keep-datatable-height-static-even-when-filtering
Have a look at this example which adds empty rows at the end.
Adding rows seems like an easier and more generic solution than styling fixed scrolling area (as in MavRoSCy solution n.1).
So, here's what works for me.
$(document).ready(function () {
var table = $('#example').dataTable({});
table.api().on('draw', function () {
var info = table.api().page.info(),
rowsOnPage = info.end - info.start,
missingRowsOnPage = info.length - rowsOnPage;
if (missingRowsOnPage > 0) {
for (var i = 0; i < missingRowsOnPage; i++) {
table.find('tbody').append(buildEmptyRow(6));
}
}
});
});
function buildEmptyRow(columnsCount) {
return '<tr class="empty">' + Array(columnsCount + 1).join('<td><div> </div></td>') + '</tr>';
}
Fiddle: http://live.datatables.net/ruviwabu/1/edit

How to restrict typing hyphen into extjs numberfield?

Currently extjs numberfield is allowing '-' hyphen otherthan numbers into the field. how to restrict that from typing? if i give custom vtype validation it is checking only after i submit that.
use autoStripChars and remove hyphen from allowed in initComponent. corrected code below.
autoStripChars: true,
initComponent: function() {
var me = this,
allowed;
me.callParent();
me.setMinValue(me.minValue);
me.setMaxValue(me.maxValue);
// Build regexes for masking and stripping based on the configured options
if (me.disableKeyFilter !== true) {
allowed = me.baseChars + '';
if (me.allowDecimals) {
allowed += me.decimalSeparator;
}
/* removed code
if (me.minValue < 0) {
allowed += '-';
}
*/
allowed = Ext.String.escapeRegex(allowed);
me.maskRe = new RegExp('[' + allowed + ']');
if (me.autoStripChars) {
me.stripCharsRe = new RegExp('[^' + allowed + ']', 'gi');
}
}
}
You need to create custom VType. VType validation is called after any change in the textfield and you have ability to configure what characters are allowed to be entered:
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.form.field.VTypes
Take a look at xxxMask property.
You could also use a regular Textfield with a maskRe config.
maskRe: /[0-9]/
Similar to #lagnat's reply which is a whitelist you can blacklist characters using stripCharsRe config.
stripCharsRe: /-/
If you are wanting to restrict negative values.
minValue: 0
{
minValue: 0,
autoStripChars: true,
allowExponential: false
}

Conditionally adjust visible columns in Rally Cardboard UI

So I want to allow the user to conditionally turn columns on/off in a Cardboard app I built. I have two problems.
I tried using the 'columns' attribute in the config but I can't seem to find a default value for it that would allow ALL columns to display(All check boxes checked) based on the attribute, ie. the default behavior if I don't include 'columns' in the config object at all (tried null, [] but that displays NO columns).
So that gets to my second problem, if there is no default value is there a simple way to only change that value in the config object or do I have to encapsulate the entire variable in 'if-else' statements?
Finally if I have to manually build the string I need to parse the values of an existing custom attribute (a drop list) we have on the portfolio object. I can't seem to get the rally.forEach loop syntax right. Does someone have a simple example?
Thanks
Dax - Autodesk
I found a example in the online SDK from Rally that I could modify to answer the second part (This assumes a custom attribute on Portfolio item called "ADSK Kanban State" and will output values to console) :
var showAttributeValues = function(results) {
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
console.log("Attribute Value : " + results[property][i]);
}
}
};
var queryConfig = [];
queryConfig[0] = {
type: 'Portfolio Item',
key : 'eKanbanState',
attribute: 'ADSK Kanban State'
};
rallyDataSource.findAll(queryConfig, showAttributeValues);
rally.forEach loops over each key in the first argument and will execute the function passed as the second argument each time.
It will work with either objects or arrays.
For an array:
var array = [1];
rally.forEach(array, function(value, i) {
//value = 1
//i = 0
});
For an object:
var obj = {
foo: 'bar'
};
rally.forEach(obj, function(value, key) {
//value = 'bar'
//key = 'foo'
});
I think that the code to dynamically build a config using the "results" collection created by your query above and passed to your sample showAttributeValues callback, is going to look a lot like the example of dynamically building a set of Table columns as shown in:
Rally App SDK: Is there a way to have variable columns for table?
I'm envisioning something like the following:
// Dynamically build column config array for cardboard config
var columnsArray = new Array();
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
columnsArray.push("'" + results[property][i] + "'");
}
}
var cardboardConfig = {
{
attribute: 'eKanbanState',
columns: columnsArray,
// .. rest of config here
}
// .. (re)-construct cardboard...
Sounds like you're building a neat board. You'll have to provide the board with the list of columns to show each time (destroying the old board and creating a new one).
Example config:
{
attribute: 'ScheduleState'
columns: [
'In-Progress',
'Completed'
]
}