Error when passing filter parameter in Uigrid with cell nav - angularjs

I have a editable Uigrid with ui-grid-cellnav directive to enable edit on focus. I also have a filter to display value instead of id in the dropdown.
<div ui-grid="gridOptions" ui-grid-edit ui-grid-cellnav class="grid"></div>
JS
$scope.gridOptions.columnDefs = [
{ name:'name', width:100 },
{ name:'age', width:100},
{ name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
cellFilter: "griddropdown:this", editDropdownIdLabel:'id',
editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
{ id: 1, gender: 'male' },
{ id: 2, gender: 'female' }
] }
];
An error occurs whenever the dropdown value is modified. It seems the filter parameter is passed as a string instead of actual object, but not sure why. Works ok if I remove the cellnav directive.
Plnkr
Thanks in advance!

Interesting, I played with it a little bit and it looks like you are getting the desired results, just that occasionally ui-grid likes to pass a string as a parameter instead of the object.
If you add a check for a string in your filter it looks like you will still be getting the desired results, that's if I am understanding properly:
String check to add:
if (typeof context !== 'string') {}
Full Filter:
.filter('griddropdown', function() {
return function (input, context) {
if (typeof context !== 'string') {
var map = context.col.colDef.editDropdownOptionsArray;
var idField = context.col.colDef.editDropdownIdLabel;
var valueField = context.col.colDef.editDropdownValueLabel;
var initial = context.row.entity[context.col.field];
if (typeof map !== "undefined") {
for (var i = 0; i < map.length; i++) {
if (map[i][idField] == input) {
return map[i][valueField];
}
}
} else if (initial) {
return initial;
}
}
return input;
};
});

Related

Altering the class values or styles of cells in ui-grid

I have several unique cases inside ui-grid where the cells of certain table contents need additional class, or even style rules assigned, so the appearance for these cells stands out compared to others. Looking through the official ui-grid documentation I found that it could be done with cellTemplate, but I couldn't get any consistent results. What is the best approach here?
Below are the code changes I have attempted before, with the intent being to change the class name based on the returned value from a filter call made
//Define Grid Headings
$scope.scheduledPatientAppointments = [
{
field: 'appointment_date',
displayName: 'Appointment Date'
},
{
field: 'doctor_name',
displayName: 'Doctor Name'
},
{
field: 'procedure_type_eng',
displayName: 'Medical Procedure Type'
},
{
field: 'appointment_status_eng',
displayName: 'Appointment Status'
},
{
field: 'docs_received',
displayName: 'Related Documents',
cellTemplate: '<div class="ui-grid-cell-contents" ng-click="grid.appScope.loadDocumentsModal(\'{{row.entity.id}}\')">{{grid.getCellValue(row, col) | hasDocuments}}</div>',
cellFilter: 'hasDocuments',
cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
if (grid.getCellValue(row, col).toLowerCase() === 'missing') {
return 'missing';
} else if (grid.getCellValue(row, col).toLowerCase() === 'received') {
return 'received';
} else {
return 'undefined';
}
}
}
];
// Define Grid Options
$scope.PatientAppointmentsGrid = {
selectionRowHeaderWidth: 25,
enableHorizontalScrollbar: false,
rowHeight: 35,
enableSorting: true,
columnDefs: $scope.columnsPatient,
data: [],
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
}
};
//Behavior for patient page load
$scope.appointmentsProvider = patientsService.patientFactory.getAppointmentsForPatient($stateParams.id).then(
function successCallback(response) {
var preFetchData = response.data.data;
angular.forEach(preFetchData, function (value, key) {documentsService.documentsFactory.getDocumentsByAppointmentId(value.id).then(
function successCallback(response2) {
if (response2.data.length >= 1) {
//Append value state to the preFetchData object (count size)
var totalFiles = response2.data.length;
preFetchData[key].docs_received = totalFiles;
} else {
preFetchData[key].docs_received = 0;
}
}, function errorCallback(response2) {
console.debug("Error", response2);
});
});
$scope.PatientAppointmentsGrid.data = preFetchData;
},
function errorCallback(response) {
console.debug("Error", response);
});
The contents from the "Related Documents" are initally set to Missing (the original rest call returns nothing, and the filter call sets it to that. However, a later call actually loads associated documents per row, and I believe the inactivity of the grid on this particular call is what is causing no class to get set here.
Thoughts on the best approach here?
adding custom class with cellTemplate:
columnDefs: [
{
name:'firstName',
field: 'first-name',
// adding custom class
cellTemplate: "<div class=\"ui-grid-cell-contents custom-class\" title=\"TOOLTIP\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
},
{ name:'1stFriend', field: 'friends[0]' },
{ name:'city', field: 'address.city'},
{ name:'getZip', field: 'getZip()', enableCellEdit:false}
],
.......
there are plenty of predefined customizable templates defined with $templateCache at the bottom of https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.2.9/ui-grid.js
adding custom style:
.......
onRegisterApi: function(gridApi){
//set gridApi on scope
$scope.gridApi = gridApi;
// adding custom style
gridApi.grid.registerStyleComputation({
func: function () {
return [
'.custom-class { ',
' color: red; ',
' font-weight: bold; ',
'} ',
'.ui-grid-row:nth-child(1) .custom-class { ',
' color: blue; ',
'} '
].join('\n');
}
});
}
plunker: http://plnkr.co/edit/YbnYoWLlEYzwmjuKOFa0?p=preview

Search text from cell template not working in ui-grid

I have defined a conditional cell template for one of the column. Its displaying the data correctly but I am not able to search for the text in the cell template.
Here is my plunkr:
https://plnkr.co/edit/TDX5jtPord1hkzCVaw3L?p=preview
var template1 = '<div class="">' +
'<div class="" ng-if="COL_FIELD > 30">Greater </div> ' +
'<div class="" ng-if="COL_FIELD < 30"> Lesser </div> ' +
'</div>';
In the template I have put the condition that.. if COL_FIELD > 30 then then write Greater.. or else write Lesser. And now I should be able to search for the Greater or Lesser in Number column.
A solution could be to add a property on your data like :
$http.get('data.json').success(function(data) {
data.map(function(item) {
item.greaterLesser = item.amount > 30 ? 'Greater' : 'Lesser';
});
$scope.gridOptions.data = data;
});
and then instead of using the amount with a template, just bind on this property.
$scope.gridOptions = {
enableFiltering: true,
columnDefs: [{
field: 'name',
width: 70
}, {
field: 'greaterLesser',
name: 'Number',
width: 90,
}, {
field: 'amount',
name: 'Currency',
cellFilter: 'currencyFilter:this',
}]
};
Here is the updated plunker
Edit
If you want to use the template, you could implement the search function yourself. You can add the filter option to your field and implement the condition function. Something like:
filter: {
condition: function(searchTerm, cellValue) {
var value = cellValue > 30 ? 'greater' : 'lesser';
var result = value.search(searchTerm.toLowerCase());
return result > -1;
}
}
Here I used the search function but you could use match or some other function.
Here is a demo plunker
I used the below code to make search work
field: 'EmpId',
displayName: 'Employee Type',
cellTemplate: '<div style="cursor:pointer" class="ui-grid-cell-contents">{{grid.appScope.GetEmployeeType(row)}}</div>',
filter: {
condition: function (searchTerm, cellValue,row,column) {
var value = $scope.GetEmployeeType(row);//same function that you use to display value in cell Template
return (value.toLocaleLowerCase().indexOf(searchTerm.toLocaleLowerCase())>-1);
}
}

dynamically load formly typeahead options

I am using Angular Formly, and try to build a form with a Select field which allows to pick the state of a country.
The second field is a typeahead field, which allows to enter valid area names belonging to this state.
However, I am failing to dynamically change the typeahead options array.
I have taken the Typeahead type definition from the Formly Examples, and works fine with a static array of options:
formlyConfig.setType({
name: 'typeahead',
template: '<input type="text" ng-model="model[options.key]" ' +
'uib-typeahead="item for item in to.options | filter:$viewValue | limitTo:8" ' +
'class="form-control">',
wrapper: ['bootstrapLabel', 'bootstrapHasError'],
});
This is my form definition:
$scope.selectZoneFormFields = [
{
key: 'stateid',
type: 'select',
templateOptions:{
label: Constants.DIVPOL,
valueProp: 'id',
labelProp: 'nombre',
options: StatesManager.get()
}
},
{
key: 'zoneName',
type: 'typeahead',
templateOptions: {
label: 'Zona',
options: $scope.zoneNames
}
}
];
Then, I watch changes in stateid and refresh $scope.zoneNames:
$scope.$watch('geo.stateid', function(newValue, oldValue) {
if (newValue === undefined || newValue.length !== 2 || newValue === oldValue )
return;
console.log(' !!! STATE change detected: ' + oldValue + '-->' + newValue);
refreshZones(newValue);
});
The problem is that the options for the typeahead field remain those which are loaded at the beginning (initial value of $scope.zoneNames)
I have tried to use a controller inside formly field definition, but with no success.
Ideas?
{
key: 'zoneName',
type: 'typeahead',
templateOptions: {
label: 'Zona',
options: []
},
expressionProperties: {
'templateOptions.options': function($viewValue, $modelValue, $scope){
$scope.to.options = []; //set to an empty array
if($scope.model.stateid) { //if the state has been selected
$scope.to.options = //whatever code you use to get the zones
return $scope.to.options; //return the options
}
}
}
}

Angular UI Grid - Filter on display values within registerRowsProcessor

We have a requirement to filter the contents of a grid using values/inputs that are not embedded into the UI Grid Column headers. The filtering must occur on the values that are displayed or in other word have been "filtered" for presentment. I have been able to successfully filter on values that don't have a cellFilter specified by specifying a filter method using the registerRowsProcessor.
$scope.externalFilterImpl = ( renderableRows ) => {
if($scope.externalFilterValues.name.length>0)
{
// Case insensitive matching
var matcher = new RegExp($scope.externalFilterValues.name, "i");
renderableRows.forEach( function( row ) {
var match = false;
debugger;
if ( row.entity["id"].match(matcher) ){
//var value = $scope.gridApi.grid.getCellDisplayValue(row, "id");
//if ( value.match(matcher) ){
match = true;
}
if ( !match ){
row.visible = false;
}
});
}
return renderableRows;
};
The code expects to filter on the display value (filtered value) for the column with the columnDef field property of "id". The columnDef for "id" appears as follows:
{
field: "id",
cellClass: "cellContent",
displayName: $translate.instant('tableHeading.item'),
enableColumnMenu: false,
enableHiding: false,
suppressRemoveSort: true,
filter: {
placeholder: "Enter a name search"
},
cellFilter: 'translateIds:"itemIds"',
filterCellFiltered:true,
sortCellFiltered:true,
sort: {
direction: uiGridConstants.ASC,
priority: 0,
},
cellTemplate: `<div class="ui-grid-cell-contents">
{{COL_FIELD CUSTOM_FILTERS}}
</div>`
}
Any assistance would be greatly appreciated.

A formPanels textfield value should be a href link

this is my textfield in my formpanel:
{
xtype: 'textfield',
fieldLabel: 'Homepage',
name: 'homepage',
tabIndex: 4,
padding: '10'
}
I want the loaded value which is displayed to be a clickable link.
EDIT:
because webpages without "http://" at the beginning won't display in the new tab, i changed the solution a little bit like this:
listeners: {
render: function (field) {
this.getEl().on('click', function (e, t, eOpts) {
var url = e.target.value;
if (url != '') {
if (url.indexOf("http://") != -1) {
var win = window.open(url, '_blank');
} else {
var win = window.open('http://' + url, '_blank');
}
win.focus();
}
}
}
}
There is no way you can achieve what you desire.For 'link' you have to
use another component may be a label with a link.But with some trick you can make the value in a textfield appear as a link.For that you can do something like this:
{
xtype: 'textfield',
name: 'name',
id:'link',
fieldStyle: 'color: blue; text-decoration:underline; cursor:pointer',
listeners: {
render: function (field) {
this.getEl().on('click', function (e, t, eOpts) {
console.log(e);
//here you need to do some hack around to restrict changing href,only on click of input in the textfield.Could not achieve that,but tried to give some idea.
var url = e.target.value;
if(url != ''){
window.location="";
}
});
}
}
}
Hope this helps you :-)
To do this you can use the render function as follows:
{
xtype : 'displayfield',
id: 'yourId',
name:'yourName',
fieldLabel: 'This is the label',
renderer: function(data, field) {
return ''+data+''
}
}
It may not be the most elegant solution but it works :)

Resources