angularJS -UI-grid cellTooltip for dynamic columns - angularjs

I have a stored procedure that returns dynamic columns and I was able to paint the output with some help on angularJS ui-grid. Now I am trying to add "CellToolTip". Screenshot below is the output of the stored procedure in which columns 25 to 22 are dynamic (which means they can range from 150 to 0 depending on the input given to the stored procedure). The columns that start with "Tgt"are Targets which I don't want to display but show the target value when hovered over the column. I was able to successfully hide the "Tgt-"columns on the webpage with out issue.
Now I need to show them as a CellToolTip when I hover over the dynamic columns 25 to 22 with which I need help. In the screenshot example below when I hover over the cell with value 0.901 that is against column 25 and row "Vat Fill Calc F/P Ratio" attributename I would like to see "0.89". But if I hover over the cell value 0.89 that is against column 25 and row "Vat Batch data F/P" attributename I would like to see "No value" since Tgt-25 column has a NULL for that attributeName.
In my code below within the push function I added "var key = 'Tgt-' + sortedKeysArray[i];
var value = row.entity[key];". When I put break points I get error saying key is undefined. But if I hardcode the key value like "var value = row.entity["Tgt-25"];" then it works fine. I need help with making the hover values dynamic in which I would like to get the target values from their respective target columns. Thanks in advance for the help.
LRWService.getVatMakeRpt('1', '1221209', '100000028', '2020-05-08', '2020-05-08').success(function (data) {
if (data === null || data.VatMakeRptList === null || data.VatMakeRptList.length === 0) {
$scope.error = true;
$scope.errorDescription = "No data found for selected criteria.";
} else {
$scope.gridOptionsVatMakeRpt.paginationPageSizes.push(
data.VatMakeRptList.length
);
var VatMakeRptList = data.VatMakeRptList;
var keysArray = [];
keysArray = Object.keys(VatMakeRptList[0]);
var sortedKeysArray = keysArray.sort().reverse();
$scope.gridOptionsVatMakeRpt.columnDefs.push({ name: 'LineNumber', field: 'LineNumber', width: '20%', visible: true });
$scope.gridOptionsVatMakeRpt.columnDefs.push({ name: 'AttributeName', field: 'AttributeName', width: '20%', visible: true });
for (var i = 0; i < sortedKeysArray.length; i++) {
if (!(sortedKeysArray[i] == "LineNumber" || sortedKeysArray[i] == "AttributeName" || sortedKeysArray[i].includes("Tgt-") == true ))
$scope.gridOptionsVatMakeRpt.columnDefs.push({
name: sortedKeysArray[i], field: sortedKeysArray[i], width: '20%', visible: true, cellTooltip: function (row, col) {
var key = 'Tgt-' + sortedKeysArray[i];
// var value = row.entity["Tgt-25"];
var value = row.entity[key];
if (value != null) {
return value;
} else {
return "No Value";
}
}
});
}
}

All I had to do was move the "Key" value above the if statement.
for (var i = 0; i < sortedKeysArray.length; i++) {
var key = 'Tgt-' + sortedKeysArray[i];
if (!(sortedKeysArray[i] == "LineNumber" || sortedKeysArray[i] == "AttributeName" || sortedKeysArray[i].includes("Tgt-") == true ))
$scope.gridOptionsVatMakeRpt.columnDefs.push({
name: sortedKeysArray[i], field: sortedKeysArray[i], width: '20%', visible: true, cellTooltip: function (row, col) {
// var value = row.entity["Tgt-25"];
var value = row.entity[key];
if (value != null) {
return value;
} else {
return "No Value";
}
}

Related

I want to set checkbox to true based on a condition in ag-grid

I have a button which basically imports some data. This imported data needs to be compared with the data inside already loaded ag-grid and if there is a match, set the cehckbox of that particlar row node to true.
This is the button which checks for the condition:
enableCheck() {
alert('works');
if (this.DataService.isNotBlank(this.rowDataImport)) {
for (let i = 0; i < this.rowDataImport.length; i++) {
if (this.DataService.isNotBlank(this.rowData)) {
for (let j = 0; j < this.rowData.length; j++) {
if (this.DataService.isNotBlank(this.rowData[j].calDate)) {
for (const calDates of this.rowData[j].calDate) {
if (
this.rowDataImport[i].isin === calDates.isin ||
this.rowDataImport[i].portfolioName === calDates.portfolioName ||
this.rowDataImport[i].valuationDate === calDates.valuationDate
)
{
// alert('true')
this.checkValue = true;
} else {
this.checkValue = false;
}
}
}
}
}
}
}
}
The this.checkValue is a flag which will be true if match is found.
public gridColumnDefs = [
{
headerName: 'Portfolio Name',
field: 'portfolioName',
cellRenderer: 'agGroupCellRenderer',
headerCheckboxSelection: true,
headerCheckboxSelectionFilteredOnly: true,
checkboxSelection: true,
pinned: 'left',
filter: true,
cellRendererParams:(params) => {
console.log(params);
if (this.checkValue) {
params.node.selected = true;
}
}
},
]
here I used cellRendererParams. But this will only for on load I guess. What to do if I want to update the ag-grid row from a value outside i.e. from import check as given above?
First of all, you should add id for each row in defaultColDef
this.defaultColDef = {
getRowNodeId: data => data.id,
};
Then you can find this id and set the checkbox to true.
Also, you can find separate field by name.
It is really easy, you should use the next combination
selectRow() {
this.gridApi.forEachNode(node => {
if (node.id == 1 || node.id == 2 || node.data.country == 'Australia') {
node.setSelected(true);
}
});
}
Working example:
https://plnkr.co/edit/ijgg6bXVleOAmNL8
In this example when we click on the button - we set the checkbox to true for two rows with id 1 and 2 and for each field that has country 'Australia'
And in your case, you are using incorrect configuration.
You should you cellRenderer
cellRenderer: params => {
if(params.value === 'Ireland') {
params.node.setSelected(true)
}
return params.value
},
One more example: https://plnkr.co/edit/PcBklnJVT2NsNbm6?preview
I manpulated a bit and did the below which worked like a charm.
this.gridApi.forEachNode(node => {
if (node.data.isin === this.rowDataImport[i].isin &&
node.data.portfolioName === this.rowDataImport[i].portfolioName &&
node.data.valuationDate === this.rowDataImport[i].valuationDate
) {
node.setSelected(true);
}

Validate formly angularjs fields are not the same

I have dynamically added fields on click.
addNewFiled() {
let parent = this;
this.scope.fields.push({
key: 'field-'+parent.scope.fields.length,
type: 'horizontalInput',
templateOptions: {
placeholder :'Enter Field',
label: 'Filed',
required: false
},
validators: {
fieldFormat: function($viewValue, $modelValue, scope) {
let value = $viewValue;
if(value.length != 12){
scope.to.message = "Field should be 12 characters";
return false;
}
return true;
}
}
});
}
What I need is to validate the the value entered is not in another field in the validator, I tried looping through the model but its not efficient, any help is appreciated.
I have encountered this case once, I solved the issue using 2 maps
Basically, you will have 2 maps, one which will contain the index of the field mapped to the value of it, the second map will contain the value of the field mapped to the number of the repetitions of that value
In your validator, you decrement the number of repetitions for the previous value ( after done with other validations) and increase the number of repetitions of the new value and check if it's more than 1 then it's repeated.
In your Dialog define the two maps
private valuesMap: any = [];
private keysArray:any = [];
In your field, you inject a controller to save the index of the current field
controller: function ($scope) {
$scope.index = parent.scope.fields.length-1;
parent.keysArray[$scope.index] = $scope.index;
},
then in your validator
if(value) {
if(angular.isDefined(parent.valuesMap[parent.keysArray[scope.index]])) {
parent.valuesMap[parent.keysArray[scope.index]]= parent.valuesMap[parent.keysArray[scope.index]] -1;
}
parent.keysArray[scope.index] = value;
if(angular.isDefined(parent.valuesMap[value]) && parent.valuesMap[value] > 0) {
parent.valuesMap[value] = parent.valuesMap[value]+1;
scope.to.message = "Value is already entered";
return false;
}
parent.valuesMap[value] = 1;
}
Hope this works with your scenario
You don't need a validator on this, there is already default validation for field length through the minlength and maxlength properties in the templateOptions.
Simply do this:
templateOptions: {
placeholder :'Enter Field',
label: 'Filed',
required: false,
minlength: 12,
maxlength: 12
},

Render Grid Row Without Updating CSS File

I can render individual grid columns using a column renderer like this ;
renderer: function(val, meta) {
if (val === 'i') {
meta.style = "background-color:#86b0f4;";
}else if (val === 'n') {
meta.style = "background-color:#fcd1cc;";
}
return val
},
I would like to use this same idea on grid rows.
Unfortunately the only thing I can come across is something along the lines of :
viewConfig: {
getRowClass: function(record, rowIndex, rowParams, store){
return record.get("partytype") == 6 ? "row-highlight" : "";
}
},
This requires me to update the CSS file which I do not want to do.
Can I directly manipulate the css value on a grid row in extjs?
The meta parameter in the column renderer has a record property too. You could lookup the relevant value there instead of relying on the cell value parameter and then add a reference to the same method for each column in the configuration.
Avoiding code duplication, the renderer method could be declared anywhere but to keep this example concise I've just used an IIFE / inline declaration.
{
// Ext.grid.Panel
// ...
columns: (function(){
function columnRenderer(cellValue, meta){
var value = meta.record.get('value');
if(value === 'i')
meta.style = 'background-color:#86b0f4;';
else if(value === 'n')
meta.style = 'background-color:#fcd1cc;';
return cellValue;
}
return [
{
text: 'Foo',
dataIndex: 'foo',
renderer: columnRenderer
},
{
text: 'Bar',
dataIndex: 'bar',
renderer: columnRenderer
}
];
})()
}
ยป Fiddle

Can a subgrid be exported in angular ui-grid

I'm using the grid from http://ui-grid.info/ in a project. I've created a hierarchical grid, which works nicely, but when I do an export, it only exports the data from the top-level grid.
This is by design and is standard functionality for the grid, so there's no point in me putting up any example code. Any example from http://ui-grid.info/docs/#/tutorial will do.
Is there a way to export the subgrid (preferably both the main grid AND the subgrid together as they appear in the grid)?
Sadly the answer is no.
As you can see here the function getData iterates through all rows and then through all columns, adding to an array of extractedFields the columns to be extracted and aggregating those in an array of extractedRows.
This means that no data, other than what's defined in gridOptions' columnDef will be read, converted and extracted.
By design, subgrid information are stored inside a property of any row entity's subGridOptions but this property is never accessed inside of the exporter feature.
The motivation behind this behaviour is that expandable grid feature is still at an alpha stage, so, supporting this in other features is not a compelling priority.
Furthermore, adding subgrid to a CSV could be quite hard to design, if we wanted to provide a general solution (for example I don't even think it would be compliant to CSV standard if you had different number of columns in the main grid and in subgrids).
That said, ui-grid is an open source project, so, if you have a working design in mind, feel free to open a discussion about it on the project gitHub page or, even better, if you can design a working (and tested) solution and create a pull request, even better!
I managed to get it working, although if I had the time I would do it a bit better than what I've done by actually creating a branch of the code and doing it properly, but given time constraints, what I've got is working nicely.
FYI, here's the way I ended up getting it to do what I wanted:
In my grid options, I turned off the CSV export options in the grid menu (because I've only implemented the changes for PDF).
I made a copy of exporter.js, named it custom.exporter.js and changed my reference to point to the new file.
In custom.exporter.js, I made a copy of the getData function and named it getGridRows. getGridRows is the same as getData, except it just returns the rows object without all the stuff that gets the columns and so on. For now, I'm coding it to work with a known set of columns, so I don't need all that.
I modified the pdfExport function to be as follows:
pdfExport: function (grid, rowTypes, colTypes) {
var self = this;
var exportData = self.getGridRows(grid, rowTypes, colTypes);
var docContent = [];
$(exportData).each(function () {
docContent.push(
{
table: {
headerRows: 1,
widths: [70, 80, 150, 180],
body: [
[{ text: 'Job Raised', bold: true, fillColor: 'lightgray' }, { text: 'Job Number', bold: true, fillColor: 'lightgray' }, { text: 'Client', bold: true, fillColor: 'lightgray' }, { text: 'Job Title', bold: true, fillColor: 'lightgray' }],
[formattedDateTime(this.entity.JobDate,false), this.entity.JobNumber, this.entity.Client, this.entity.JobTitle],
]
}
});
var subGridContentBody = [];
subGridContentBody.push([{ text: 'Defect', bold: true, fillColor: 'lightgray' }, { text: 'Vendor', bold: true, fillColor: 'lightgray' }, { text: 'Status', bold: true, fillColor: 'lightgray' }, { text: 'Sign off', bold: true, fillColor: 'lightgray' }]);
$(this.entity.Defects).each(function () {
subGridContentBody.push([this.DefectName, this.DefectVendor, this.DefectStatus, '']);
});
docContent.push({
table: {
headerRows: 1,
widths: [159, 150, 50, 121],
body: subGridContentBody
}
});
docContent.push({ text: '', margin: 15 });
});
var docDefinition = {
content: docContent
}
if (self.isIE()) {
self.downloadPDF(grid.options.exporterPdfFilename, docDefinition);
} else {
pdfMake.createPdf(docDefinition).open();
}
}
No, there is no direct way to export subgrid. rather you can create youur own json data to generate csv file.
Please check the below code
function jsonToCsvConvertor(JSONData, reportTitle) {
//If JSONData is not an object then JSON.parse will parse the JSON string in an Object
var arrData = typeof JSONData !== 'object' ? JSON.parse(JSONData) : JSONData,
csv = '',
row,
key1,
i,
subGridData;
//Set Report title in first row or line
csv += reportTitle + '\r\n\n';
row = '';
for (key1 in arrData[0]) {
if(key1 !== 'subGridOptions' && key1 !== '$$hashKey'){
row += key1 + ',';
}
}
csv += row + '\r\n';
for (i = 0; i < arrData.length; i++) {
row = '';
subGridData = '';
for (key1 in arrData[i]) {
if(key1 !== 'subGridOptions' && key1 !== '$$hashKey'){
row += '"' + arrData[i][key1] + '",';
}
else if(key1 === 'subGridOptions'){
//csv += row + '\r\n';
subGridData = writeSubGridData(arrData[i][key1].data);
}
}
csv += row + '\r\n';
csv = subGridData ? csv + subGridData + '\r\n' : csv;
}
if (csv === '') {
console.log('Invalid data');
}
return csv;
}
//Generates subgrid Data to exportable form
function writeSubGridData(subgridData){
var j,
key2,
csv = '',
row = '';
for (key2 in subgridData[0]){
if(key2 !== '$$hashKey'){
row += key2 + ',';
}
}
csv = row + '\r\n';
for (j=0; j < subgridData.length ; j++){
row = '';
for(key2 in subgridData[j]){
if(key2 !== '$$hashKey'){
row += '"' + subgridData[j][key2]+ '",';
}
}
csv += row + '\r\n';
}
return csv;
}
jsonToCsvConvertor(exportData, 'New-Report');

filtering in angularjs using or operator

i have a loop of an array Countries,example (this is in a multi select box)
{Clicked : true, Name:USA,ID:1},
{Clicked :false, Name:China,ID:2},
{Clicked : true, Name:India,ID:4}
when an item(Name value) is checked,the clicked value turns to true.So if i know all the values that are true can i loop through the countries array to get those values?
once i got the true values i want to use the OR operator to pass only one id value and not all, example if its 1 || 4 || 2 then 4 should get passed.
what was attempted
$scope.FilterCountries=function(){
var Clicked=true;
for(var i=0;i<=$scope.model.Countries.length;i++)
{
Clicked= $scope.model.Countries.Clicked[i];
var ID= Clicked || $scope.model.Countries.ID[i];
}
}
the above when i select a value,it sends back a different ID ,it adds its own value.
I am still not sure what you want to do exactly but your code seems to be wrong. I put an example together.
If you mean Bitwise operations see here: MDN Bitwise operations
I hope it helps.
$scope = {
model: {
Countries: [{
Clicked: true,
ID: 1
}, {
Clicked: true,
ID: 2
}, {
Clicked: true,
ID: 4
}]
}
};
$scope.FilterCountries = function() {
var result = 0;
for (var i = 0; i < $scope.model.Countries.length; i++) {
if ($scope.model.Countries[i].Clicked === true) {
//Bitwise operation ID: 1 and 2 and 4 would result in 7
result = result | $scope.model.Countries[i].ID;
}
}
return result;
};
document.write($scope.FilterCountries());
Later you can test if a country was checked by using the &-Operator
(7 & 4) === 4; // true
$scope.FilterCountries = function() {
var result = 0;
for (var i = 0; i < $scope.model.Countries.length; i++) {
if ($scope.model.Countries[i].Clicked === true) {
//Bitwise operation ID: 1 and 2 and 4 would result in 7
result = result[i] | $scope.model.Countries[i].ID;
}
}
return result;
};

Resources