Cannot understand the renderer of field ExtJS6.2 - javascript

I'm quite new in ExtJS and JS both.
I have an Ext.Grid and the column that should display the month and year e.g. "august 2019".
By adding a new column the month should decrement, so the result should be:
1st add: august 2019
2nd add: july 2019
3d add: june 2019
...
I also have a widget for choosing data by only month and a year from here:
EXTJS 5 - Date picker year and month only
Maybe I should provide a bit more code or can you advice what I should learn ?
dataIndex: 'picker',
...
renderer: function (value, cell, record) {
if (!value && record.get('year') && record.get('month')) {
value = new Date(record.get('year'), record.get('month') - 1);
record.set('picker', value);
}
return Ext.Date.format(value, 'M, Y');
Now months are incrementing,instead of decrementing.

The renderer function in ExtJS is merely a function that, for the given column, is called for every row in the grid. The output of this function is used to render the text inside that particular cell of the grid.
If what you want to do is allow to dynamically add columns to the grid, with the new columns having the value of month "decremented by 1" compared to the previous month, what you have to do is to build a renderer that has some specific additional parameter attached to it, which you can do for example by using JavaScript's bind method. Every time you add the column, you'll create an instance of such renderer passing a different value.
The following StackOverflow post will give you a hint on how to make columns dynamic:
How to dynamically add columns for Grid ExtJs
As for the renderer function and its usage, it goes more or less as follows:
function customRenderer(value, cell, record) {
var result = value - this.index;
return value + " - " + this.index + ' = ' + result;
}
var columns = [];
for(var i = 0; i < 10; i++) {
var column = {};
column.dataIndex = 'column' + i;
column.text = 'Column ' + i;
column.renderer = customRenderer.bind({ index: i, column: column });
}
reconfigureExtJSColumnsPseudoFunction(columns);
The above code, which you will of course have to tune based on your needs, takes the customRenderer function and changes its scope, thus allowing you to provide it with additional context. Each iteration in the for loop will create a new "version" of that function running in a different scope (through the bind method) thus ensuring that each column will receive a different value for the index property, allowing you to dynamically change the amount you will then subtract based on the column index itself.

Related

Office.js iterate single cells in a single column in a table

I have a control panel within an excel sheet as part of my addin this is built when the addin starts.
I would like to make sure all my code references the the sheet are relative references so if a user adds a column to the control pannel or moves it. The addin still works.
For example If I want to Read information:
// This reads a list of tickers to than query my back end for data.
let BBTickerRange=sheet.tables.getItem("ControlPanel").columns.getItem("Symbol Ticker");
BBTickerRange.load(["values", "columns", "items"])
// IF the lookup misses I have code like
BloombergTableOne.columns.items[i + 1].name = ("#TK" + i + " " + BBTickerRange.values[i][0]);
BloombergTableOne.columns.getItemAt(i + 1).getHeaderRowRange().format.fill.color = "#DD5D74";
BloombergTableOne.columns.getItemAt(i + 1).getDataBodyRange().clear();
// But for Changing a specific value within the control panel I am still using code like
var SymStartDate = sheet.getRange("D12:D12").getOffsetRange(i, 0);
var SymEndDate = sheet.getRange("E12:E12").getOffsetRange(i, 0);
I would like to have this to look at a specific column in the sheet and than iterate over the rows rater than having to do a generic reference and an offset.
Is there a way to iterate to change single values within a column without writing the entire .getDataBodyRange
// Potential Solution for anyone looking for a workaround.
let SymStartDateCol= sheet.tables.getItem("ControlPanel").columns.getItem("Start Date").getHeaderRowRange().load(["address"]);
//SymStartDateCol.load(["values", "columns", "items", "address"])
let SymEndDateCol= sheet.tables.getItem("ControlPanel").columns.getItem("End Date").getHeaderRowRange().load(["address"]);
return context.sync()
.then(async (Symbol) => {
var SymStartDate = sheet.getRange(SymStartDateCol.address).getOffsetRange(i+1, 0);
var SymEndDate = sheet.getRange(SymEndDateCol.address).getOffsetRange(i+1, 0);

Mix clickable row and unclickable row on slickgrid

For my columns definition.
var columns = [
{id: "label", name: "point", formatter:this.clickableFormatter,field: "point",width: 150},
then I add clickhander for it.
chart.addClickHandler(){
}
Also I use clickableFormatter for this.
clickableFormatter(row,cell,value,columnDef,dataContext){
return "<span style='cursor:pointer;'>" + value + "</span>";
}
From these code. my table rows are clickable and I can show the user where is clickable by changing pointer.
However now I want to make one row unclickable.
(for example total row)
Is it possible to prevent click event for one low??
And is it possible to use another formatter for one row?
I gave the data from for loop and add total seperately.
for (var k = 0 ; k < data.length ;k++){
var temp = new Array();
temp['id'] = data[k]['id'];
temp['point'] = data[k]['point'];
ret.push(temp);
}
ret.push({
'id' : "total",
"point" : pointTotal,
});
In your formatter, you have access to the value of the cell, so if value==='total', just return an empty string.
Also FYI, I don't think you need the for loop in your code (you could just leave it out entirely), unless you're using it to calculate the total, but you don't seem to be doing that.
If you think that you need it for creating the array objects, you're misunderstanding arrays in javascript, what you're actually setting is object properties, and it would be usual to initialise with var temp = { }; rather than as Array.
It may not make sense at first, but everything in javascript is an object, including arrays and functions. So you can add object properties to anything.
somevar[numericVal] = x; // set array element, somevar must be type Array
somevar['stringVal'] = x; // set object property 'stringVal'
somevar.stringVal = x; // identical to above line, different way of specifying

Separate data from text file using Javascript

I'm working on creating an analytics page that uses data stored in a text file. The text file is used for my highcharts graph and is separated like so:
November 7th 6AM,19.8
November 7th 6PM,19.8
November 8th 6AM,20.4
November 8th 6PM,14.6
November 9th 6AM,15.9
November 9th 6PM,15.1
November 10th 6AM,16.4
November 10th 6PM,16.4
I'm looking to separate that data into 12 calendar panes that will display overall discrepancies for each month. For example, if a date had the value 16, and then it dropped to 10 the next reading, to take a cumulative sum for how many times that happened for the month.
How do I make sure that it reads from the text file in proper order and that it checks to see if the next value went below 10 and tallies that somewhere?
Yo can use jQuery to separate the file data into array.
$(document).ready(function() {
//fetch text file
$.get('text.txt', function(data) {
//split on new lines
var lines = data.split('\n');
for(var i=0;i<lines.length;i++) {
// use lines[i] the way you want
}
});
});
Then you can use this to get sub-strings:
var a = s.indexOf(',');
var b = s.substring(a,4);
This way you can separate the data and use it as desired.
You need to
Fetch the data file
One usually does this with AJAX (XMLHttpRequest)
Separate your datapoints
Your data seems to be neat enough that you can, for every line in the file, get the name of the month with line.split(" ")[0] and the value with line.split(",")[1]. Splitting a text to lines can usually be as easy as text.split("\n").
Iterate over results
For every month-value pair you now have, compare the name of the months. If it is a match and the value has changed by x, increment a value in your books, e.g. discrepancies[monthName]++. Save the name-value pair and continue.
Example:
// Get the data
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) { // If the request is complete with status code "OK"
handleImportantData(req.responseText);
}
};
// Define the request to be using the method GET to an URL asynchronously.
req.open("GET", "important_data.txt", true);
req.send();
function handleImportantData(data) {
var treshold = 5.0;
var months = {};
var discrepancies = {};
// Separate data points.
var lines = data.split("\n");
lines.forEach(function(line) {
// The || 0.0 part sets the value to zero if our data is malformed.
// We parse the value as a float to prevent it being saved as a string,
// which would make arithmetic operations on it not work as expected.
months[line.split(" ")[0]] = parseFloat(line.split(",")[1]) || 0.0;
});
// Find discrepancies.
var previous = {
name: "",
value: 0.0
};
for (var name in months) {
// If not already there, initialize the data point with ternary operation including NOP.
discrepancies[name] ? {} : discrepancies[name] = 0.0;
// If we're still talking about the same month as before and the value
// has changed for more than our treshold, save it as a discrepancy.
if name === previous.name && Math.abs(previous.value - months[name]) > treshold {
discrepancies[name] ++;
}
previous = {
name: name,
value: months[name]
}; // Set this as the previous value.
}
// Here we have ready discrepancy data stored in the variable discrepancies.
}

Google Spreadsheet: Changing cell colours if one or multiple text variables exist

I'm a newbie hacking together a script to change the background colour of specifics cells based upon text entry in a master column.
Basically where multiple country codes 'xx', 'xx' exist in row B for example, how can I, in a simpler way, highlight those fields in the corresponding rows which relate to those country codes? Currently it functions where a single locale is included in row a but not with multiples.
I have this working but only for one variable at a time (Example text is: AU) .
I need this get this to work for multiple text variables. (Example text is: "AR, AU, BEfr")
Column B: - Locale column
Column I: - AR column
Column J: - AU column
Column K: - BEfr column
Column L: - BEnl column
Column M: - BR column
etc....
My current code below. Certainly the long way to do this I imagine. I have named ranges selected called "Locales" for the locale column and "Checklist" for all the checkboxes.
Help is much appreciated.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('R186');
var values1Rule1 = s.getRange('Locales').getValues();
var range3Rule1 = s.getRange('AU');
var acro1 = 'AR', acro2 = 'AU', acro3 = 'BEfr', acro4 = 'BEnl', acro5 = 'BR';
var color1 = '#ADD8E6';
for (var row in values1Rule1) {
for (var col in values1Rule1[row]) {
if (values1Rule1[row][col] == acro1) s.getRange(s.getRange('AR').offset(row, col, 1, 1).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] == acro2) s.getRange(s.getRange('AU').offset(row, col, 1, 1).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] == acro3) s.getRange(s.getRange('BEfr').offset(row, col, 1, 1).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] == acro4) s.getRange(s.getRange('BEnl').offset(row, col, 1, 1).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] == acro5) s.getRange(s.getRange('BR').offset(row, col, 1, 1).getA1Notation()).setBackgroundColor(color1);
else s.getRange(s.getRange('locales').offset(row, 0, 1, 58).getA1Notation()).setBackgroundColor('white').setFontColor('black'); }
}};
This may be something addressed in new Google Sheets with Format, Conditional formatting..., Custom formula is:
=$B1=I$1
say applied to Range I:M:
or may just be I am misunderstanding.

JavaScript Reformatting JSON arrays

I am relatively new to the JSON notation, and have run into an issue when attempting to reformat. The current format contained in the database needs to be modified to a new format for importation into a project timeline graph.
Here is the current JSON format:
[
{
"name":"5-HP-N/A-N/A-F8",
"node":{
"name":"5",
"id":14
},
"timeline":{
"epc":null,
"m1":null,
"m2":null,
"m3":1554087600000,
"m4":1593572400000,
"m5":1625108400000,
"m6":1641006000000,
"m7":1656644400000
},
"fab":{
"name":"F8",
"id":1
}
},
However, in order to display in the graph, I need the following format:
{
'start': new Date(value from epc, or first non-null milestone),
'end': new Date(value from m1 or first non-null milestone), // end is optional
'content': 'label from start Date milestone'
'group' : ' value from name field above 5-HP'
'classname' : ' value from start Date milestone'
});
I am trying to write a function in order to accomplish this. Only epc, m1, or m2 may have the value of null, but the condition must be checked for to determine if an event range should be created and where it should end. What would be the best way to reformat this json data (preferrably from an external json sheet)?
Edit: Thanks for all the help I see how this is working now! I believe I didn't explain very well the first time though, I actually need multiple class items per "group".
The end result is that these will display inline on a timeline graph 'group' line, and so I am trying to figure out how to create multiple new objects per array element shown above.
So technically, the first one will have start date = m3, and end date = m4. Then, the next object would have the same group as the first (5-HP...), the start date = m4, end date = m5...etc. This would continue until m7 (always an end date but never a start date) is reached.
This is why the loop is not so simple, as many conditions to check.
see a working fiddle here: http://jsfiddle.net/K37Fa/
your input-data seems to be an array, so i build a loop around that. if not just see this fiddle where the input data is a simple object: http://jsfiddle.net/K37Fa/1/
var i
, result = [],
, current
, propCounter
, content = [ { "name":"5-HP-N/A-N/A-F8", "node":{ "name":"5", "id":14 }, "timeline":{ "epc":null, "m1":null, "m2":null, "m3":1554087600000, "m4":1593572400000, "m5":1625108400000, "m6":1641006000000, "m7":1656644400000 }, "fab":{ "name":"F8", "id":1 } }],
// get the milestone in a function
getMileStone = function(obj) {
propCounter = 1;
for(propCounter = 1; propCounter <= 7; propCounter++) {
// if m1, m2 and so on exists, return that value
if(obj.timeline["m" + propCounter]) {
return {key: "m" + propCounter, value: obj.timeline["m" + propCounter]};
}
}
};
// loop over content array (seems like you have an array of objects)
for(i=0;i< content.length;i++) {
current = content[i];
firstMileStone = getMileStone(current);
result.push({
'start': new Date(current.epc || firstMileStone.value),
'end': new Date(current.m1 || firstMileStone.value),
'content': firstMileStone.key,
'group' : current.name,
'classname' : firstMileStone.value
});
}
EDIT:
getMileStone is just a helper-function, so you could just call it with whatever you want. e.g. current[i+1]:
secondMileStone = getMileStone(current[i + 1])
you should just check, if you are not already at the last element of your array. if so current[i+1] is undefined, and the helperfunction should return undefined.
you could then use as fallback the firstMileStone:
secondMileStone = getMileStone(current[i + 1]) || firstMileStone;
see the updated fiddle (including check in the getMileStone-Helperfunction): http://jsfiddle.net/K37Fa/6/

Categories

Resources