Display Custom Boolean Value in Angular ui-grid - javascript

Ok, I'm new to angular and angular ui-grid.
I'm using angularjs(v1.4) with angular-ui-grid(v3.0.7).
I have defined a grid as below
seec.gridOptions = {};
seec.gridOptions.rowEditWaitInterval = -1;
seec.gridOptions.onRegisterApi = function (gridApi) {
$scope.gridApi = gridApi;
gridApi.rowEdit.on.saveRow($scope, $scope.saveRow);
};
seec.gridOptions.columnDefs = [
{name: 'pouch', displayName: 'Pouch', enableCellEdit: false, enableHiding: false, width: 250},
{name: 'content', displayName: 'Content', enableHiding: false, width: 150},
{
name: 'units',
displayName: 'Number of Items',
type: 'number',
enableHiding: false,
width: 150
},
{name: 'active', displayName: 'Status', type: 'boolean', enableHiding: false, width: 150}
];
The controller basically makes a http call and feeds data to the grid.
if (response.status === 200) {
seec.gridOptions.data = angular.copy(seec.data);
}
Currently, the last item in the grid is being displayed as either 'true' or 'false' based on the boolean field value., and when I double click on the field a checkbox appears.
So, I need to display true as 'active' and false as 'inactive'.
Is there any way of doing this with angular ui-grid?

There certainly is! One approach could be to use a cellTemplate and map your rowvalues to something different.
I created a Plunkr showcasing a possible setup.
There are two steps to take. First add a cellTemplate to your column:
cellTemplate: "<div ng-bind='grid.appScope.mapValue(row)'></div>"
Note: Instead of ng-bind you could also use "<div>{{grid.appScope.mapValue(row)}}</div>", if you are more familiar with that.
Second step is to define your mapping function, for example:
appScopeProvider: {
mapValue: function(row) {
// console.log(row);
return row.entity.active ? 'active' : 'inactive';
},
}

#CMR thanks for including the Plunkr. As I was looking at it I checked, and in this case it seems overkill to have the mapValue function.
This worked for me:
cellTemplate: "<div class='ui-grid-cell-contents'>{{row.entity.active ? 'active' : 'inactive'}}</div>"
(I added the class in there to match the other cells). I will say that this still smells a little hacky to me.
This question leads to using a function as the field itself: In ui-grid, I want to use a function for the colDef's field property. How can I pass in another function as a parameter to it?
I'd still like to see an answer with the logic directly in the columnDefs.

You can use angular filter specifying in your columnDef for a column cellFilters : 'yourfiltername:args'.
args can be a variable or a value, in that case pay attention to use right quoting. if args is a string cellFilters : 'yourfiltername:"active"'
Your filter can be directly a function or a filter name. Here a plunkr

Related

Angular with Kendo, Using Grid Values Asynchronously

Ok I'm pretty sure I know exactly what I need to do here but I'm not sure how to do it. Basically I have a grid that I want to make a key column bind to an array of key/values, which I've done before with kendo (not using Angular) and I know that when I'm creating my key/value array asynchronously then that needs to complete before I can get them show-up with kendo, which I have done using promises before.
So here I have the same issue only angular is also involved. I need to fetch and format an array of data into the format in which a kendo grid column can digest it, so no problem here is my controller code:
var realm = kendo.data.Model.define({
id: 'realmID',
fields: {
realmID: { editable: false, nullable: true }
realmType: { type: 'string', validation: { required: true } }
}
})
var ds1 = kendoHelpers.dataSourceFactory('realms', realm, 'realmID')
var realmType = kendo.data.Model.define({
id: 'realmTypeID',
fields: {
realmTypeID: { editable: false, nullable: true },
name: { type: 'string', validation: { required: true } }
}
})
var ds2 = kendoHelpers.dataSourceFactory('realms/types', realmType, 'realmTypeID')
$scope.mainGridOptions = {
dataSource: ds1,
editable: true,
navigatable: true,
autoBind:false,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmID', title: 'ID' }
{ field: 'realmTypeID', title: 'Realm Type', editor: realmTypesDDL, values: $scope.realmTypeValues },
{ command: "destroy" }
]
}
$scope.secondGridOptions = {
dataSource: ds2,
editable: true,
navigatable: true,
toolbar: [
{ name: "create" },
{ name: 'save' },
{ name: 'cancel' }
],
columns: [
{ field: 'realmTypeID', title: 'ID' },
{ field: 'name', title: 'Name' }
{ command: "destroy" }
]
}
ds2.fetch(function () {
$scope.realmTypeValues = [{ text: 'Test', value: "24bc2e62-f761-4e70-804c-bc36fdeced3d" }];
//this.data().map(function (v, i) {
// $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
//});
//$scope.mainGridOptions.ds1.read()
});
function realmTypesDDL(container, options) {
$('<input />')
.appendTo(container)
.kendoDropDownList({
dataSource: ds2,
dataTextField: 'name',
dataValueField: 'realmTypeID'
});
}
I made this dataSourceFatory helper method above to return me a basic CRUD kendo dataSource that uses transport and also injects an authorization header which is working fine so don't get hung up on that, ultimately I'm going to be using this data in another grid as well as for reference values for the main grid, but I've hard coded some values that I can use to test with in the ds2.fetch callback.
My HTML is pretty plain:
<div>
<h2>Realms</h2>
<kendo-grid options="mainGridOptions"></kendo-grid>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
</div>
This all works fine and well except I am only seeing the GUID of the realmTypeID in the grid, I click it and the editor is populated correctly so that's good but I want the text value to be displayed instead of the GUID. I'm sure the issue is that the array of values is empty whenever angular is binding to the grid options. My questions are:
How do I either delay this bind operation or manually rebind it after the fetch call?
Is there a better way to handle a situation like this? I try not to expend finite resources for no reason (IE making server calls when unnecessary)
Note: When I move the creation of the text/value array to happen before the grid options, I get the desired behavior I am after
EDIT A work around is to not use the directive to create the grid and instead defer the grid creation until the callback of whatever data your column is dependent on, I was hoping for a more elegant solution but this is better than nothing. So your HTML becomes something like
<h2>Realms</h2>
<div id="realms"></div>
<h2>Realm Types</h2>
<kendo-grid options="secondGridOptions"></kendo-grid>
Then you can create the grid in the fetch callback for example:
ds2.fetch(function () {this.data().map(function (v, i) {
$scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID})
});
$('#realms').kendoGrid($scope.mainGridOptions);
$scope.mainGridOptions.dataSource.fetch()
});
But this doesn't feel very angularish so I'm really hoping for a better solution!
Ok...well I think I hacked this enough and without another suggestion I'm going to go forward with this approach. I'm just going to move the binding logic to the requestEnd event of the second grid so that the values array can be populated right before the binding even. I'm also reworking the values array in this method. It is a bit weird though, I think there is some kendo black magic going on with this array because I can't just set it to a new empty array without it breaking completely...which is why I'm poping everything out prior to repopulating the array. That way when something is deleted or edited in the second grid, the DDL in the first grid is updated in the callback.
function requestEnd(e) {
for (var i = $scope.realmTypeValues.length; i >= 0; i--) $scope.realmTypeValues.pop();
var data;
if (e.type == "read")
data = e.response;
else
data = e.sender.data();
data.map(function (v, i) { $scope.realmTypeValues.push({ text: v.name, value: v.realmTypeID }); });
if ($('#realms').data('kendoGrid') == undefined) {
$('#realms').kendoGrid($scope.mainGridOptions);
}
else
$('#realms').data('kendoGrid').columns[4].values = $scope.realmTypeValues;
}
ds2.bind('requestEnd', requestEnd);
So I'm going to accept my own answer unless anyone has a better approach!

Kendo Grid : Default value 1 in cell in inline edit mode, how to change it?

I have following config foo column in grid:
field:
actionName: {
editable: true,
nullable: true,
defaultValue: {"name" : "TEST123"},
type: "object"
},
Column:
{
field :"actionName",
title : $translate.instant('ACTIONNAME'),
width: "200px",
editor: GlobalHelperService.getActionNamesListForAutocomplete,
template: '#: data.actionName.name #',
filterable: { cell: { operator:"contains"
}
}
},
Which works almost fine, but if i clicked on cell item i always got following value (see. image below), instead of the text defined in template attribute.
How can i solve it please?
Many thanks for any advice.
It might not be the cleanest way, but you could use the edit event like I do in this blog post.
$("#grid").kendoGrid({
edit: onEdit
});
function onEdit(editEvent) {
// Ignore edits of existing rows.
if(!editEvent.model.isNew()) { return; }
editEvent.model.set("actionName", {name: "TEST123"});
}
Although as I note in that post, setting the default value with .set() might not work in this case, and you might need to edit the text in the edit box directly:
editEvent.container
.find("[name=actionName]")
.val("TEST123")
.trigger("change");

Filter by multiple boolean properties in angular js smart-table

I have the following situation:
A list of indicators, each of them having the properties name, description, essential and differential.
$scope.indicators = [
{ name: 'indicator1' , description: 'blah1', essential: true, differential: false },
{ name: 'indicator2' , description: 'blah2', essential: false, differential: true },
{ name: 'indicator3' , description: 'blah3', essential: true, differential: true },
{ name: 'indicator4' , description: 'blah4', essential: false, differential: false }
]
I'd like to be able to filter with a select the following combinations:
"All", "Essential", "Differential", "Essential and Differential", "Neither Essential nor Differential"
I have tried using ng-model in the select associated with the ng-repeat with | filter, but that ruined the pagination.
I couldn't think of way of using the st-search directive since I'm filtering two properties combined.
Does anyone have a suggestion?
Follows the plunker with the sample code: http://plnkr.co/edit/t9kwNUjyJ15CbLFFbnHb
Thanks!!
The search are cumulative, so if you call the controller api search with multiple you will be able to add the predicates.
Just make sure to reset the sortPredicate object whenever the value changes.
this plunker shows how to write a plugin with your requirements (although I don't understand what all would be in this context
.directive('customSearch',function(){
return {
restrict:'E',
require:'^stTable',
templateUrl:'template.html',
scope:true,
link:function(scope, element, attr, ctrl){
var tableState=ctrl.tableState();
scope.$watch('filterValue',function(value){
if(value){
//reset
tableState.search.predicateObject ={};
if(value==='essential'){
ctrl.search('true', 'essential');
} else if(value === 'differential'){
ctrl.search('true', 'differential')
} else if(value === 'both'){
ctrl.search('true','essential');
ctrl.search('true', 'differential');
} else if(value === 'neither'){
ctrl.search('false','essential');
ctrl.search('false', 'differential');
}
}
})
}
};});
This is how I would do it.
In your controller define an Array with the possible options and the filter for each option, like this:
$scope.options = [
{value:'All', filter:{}},
{value:'Essential', filter:{essential:true}},
{value:'Differential', filter:{differential:true}},
{value:'Essential and Differential', filter:{differential:true, essential:true}},
{value:'Neither Essential nor Differential', filter:{differential:false, essential:false}}
];
Then in your html declare your select using this array, like this:
<select ng-model='diffEssFilter' ng-options='option.value for option in options'>
</select>
And then in your ng-repeat use the filter that would be stored in diffEssFilter, like this:
<tr ng-repeat="indicator in indicators | filter:diffEssFilter.filter">
That's it.
Working example

How to use a promise inside an object literal

In angular-translate version 2.0 the $translate service no longer returns the actual translation but a promise. I can see that is a good idea because there could be some asynchronous loading going on. But it confuses me how to use the service properly in my case, because I used the $translate service inside an object literal, like this
$scope.myDefs = [
...
{
field: 'supplier',
displayName: $translate('Supplier'),
cellTemplate: "<div class=\"ngCellText\">...</div>"
},
...
{
field: 'supplierSize',
displayName: $translate('Size'),
width: 100,
cellClass: "center"
}
...
];
Question: How do I use a promise inside an object literal?
It is supposed to (according to the documentation) be used like this:
$translate('HEADLINE').then(function (headline) {
$scope.headline = headline;
});
If you know that there's no asynchronous stuff going on, you can use $translate.instant() which behaves exactly like $translate() in 1.x.
You'd need to have a direct reference. Or a helper function that has closure over the reference. Like:
$scope.myDefs = [
...
createArrayObject({
field: 'supplier',
displayName: $translate('Supplier'),
cellTemplate: "<div class=\"ngCellText\">...</div>"
}),
createArrayObject(.....
]
and elsewhere
function createArrayObject(obj){
obj.displayName.then(function(data){
obj.displayName = data;
});
return obj;
}
Update
as Brian suggested below, Its always a good idea to write generic code you can use all over.
var forEach = angular.forEach,
isFunction = angular.isFunction;
function resolveProperties(obj){
forEach(obj,function(val,key){
if(isFunction(val.then)){
val.then(function(data){
obj[key] = data;
});
}
});
}
So you can use it like...
[
resolveProperties({
myPropertyToResolve: promiseReturningFunction()
}),
....
]
If you re using ui-grid, solution is to add headerCellFilter: 'translate' to columnsDefs (means myDefs) and displayName must have translation key.
Here is,
$scope.myDefs = [
{
field: 'supplier',
displayName: "Supplier",
cellTemplate: "<div class=\"ngCellText\">...</div>",
headerCellFilter: 'translate'
},
{
field: 'supplierSize',
displayName: "Size",
width: 100,
cellClass: "center",
headerCellFilter: 'translate'
}
];
Another idea is to loop through your literal and replace all the promises with values. However I don't know what happens if you call then, when a promise has already been resolved.
angular.forEach($scope.myDefs, function(element){
element.displayName.then(function(result){
element.displayName= result;
})
})

ExtJS 4, customize boolean column value of Ext.grid.Panel

Good day, i have a grid with boolean column:
var grid = Ext.create('Ext.grid.Panel', {
...
columns: [{
dataIndex: 'visibleForUser',
text: 'Visible',
editor: {
xtype: 'checkboxfield',
inputValue: 1 // <-- this option has no effect
}
},
...
Grid's store is remote via JSON proxy. When i save or update row, the resulting JSON
look like:
{... visibleForUser: false, ... }
As you see, ExtJS serializes checkbox value as true or false JSON terms.
I need to customize this and serialize to, say, 1 and 0, any suggestion how to accomplish this ? Thank you.
I've just changed my checkboxes system-wide to always act/respond to 0 and 1:
Ext.onReady(function(){
// Set the values of checkboxes to 1 (true) or 0 (false),
// so they work with json and SQL's BOOL field type
Ext.override(Ext.form.field.Checkbox, {
inputValue: '1',
uncheckedValue: '0'
});
});
But you can just add this configs per checkbox.
Ext JS 4.1.1 has a new serialize config on record fields. When a writer is preparing the record data, the serialize method is called to produce the output value instead of just taking the actual field value. So you could do something like this:
fields: [{
name: "visibleForUser",
type: "boolean",
serialize: function(v){
return v ? 1 : 0;
}
/* other fields */
}]
I try to avoid overriding default component behavior whenever possible. As I mentioned, this only works in 4.1.1 (it was introduced in 4.1.0 but I believe it was broken). So if you're using an earlier version, one of the other answers would suit you better.
You can try to override getValue
Ext.define('Ext.form.field.Checkbox', {
override : 'Ext.form.field.Checkbox',
getValue: function () {
return this.checked ? 1 : 0;
}
});

Categories

Resources