Angular ui-grid editDropdownOptionsArray depending on current row - angularjs

I want to have a different dropdown array for each row of my ui-grid. Therefore I need to access the current row. I had something like this in mind but I don't know how to access the current row within columnDefs. Is there an easy way to achieve this?
columnDefs: [
{ name: "id", field: "id"},
{ name: "firends", field: "friends", editableCellTemplate: 'ui-grid/dropdownEditor', editDropdownOptionsArray: findFriendsForId(row.id)
]
var findFriendsForId = function(id) {
// find friends and return them as array
}

Ok I figured it out by myself. There is a function called
editDropdownOptionsFunction.
Here is an example of it.

Related

AngularJS ui-grid re-using a custom filter

I have a basic grid with a couple of columns that are ranges, i.e. 10 - 50, 0 - 9, etc. and I've written a custom filter on one of the columnDefs;
filter: {
condition: function(searchTerm, cellValue) { ... }
}
The filter works perfectly, but I'd like to strip it out and re-use it, only I can't figure out how.
I've tried defining it in the controller as function rangeFilter(...) and vm.rangeFilter = rangeFilter and then assigning it to the condition as grid.appScope.filterRange(searchTerm, cellValue) but that doesn't work.
I'm not really sure how else I'd do it, I haven't been able to find anything in the documentation or by googling for it.
Here's a plunkr of it in action; http://next.plnkr.co/edit/mbtXzfWqBg8FIALu
As you did, move the function out of the column definitions.
function rangeFilter() {
...
}
And in the column definitions pass a reference to the function in both.
vm.gridOptions = {
...
columnDefs: [
// default
{ field: 'name' },
{ field: 'range', cellFilter: 'range', filter: {condition: rangefilter}},
// I want to reuse the same filter as 'range' for this column somehow...
{ field: 'anotherRange', cellFilter: 'range', filter: {condition: rangefilter}}
],
...
};
Plunker

Angular UI Grid Multiple Columns Editable At The Same Time

I am using Angular UI Grid and I want to know if it is possible to make multiple fields, on multiple rows 'appear' editable at the same time. From a user perspective it is impossible to tell at a glance which fields are editable. The best I have been able to get is the setting 'enableCellEditOnFocus', but this still only allows edit when a user specifically clicks on a cell.
$scope.gridOptions.columnDefs = [
{ name: 'age', enableCellEditOnFocus:true }
];
After some searching and that helpful suggestion by Austin I found a decent solution.
$scope.gridOptions = {
data: self.myData,
columnDefs: [{ field: 'firstName', cellTemplate: '<div class="ui-grid-cell-contents"><input type="text" ng-model="MODEL_COL_FIELD" /></div>' }]
};

Dropdown opening issue inside of ui-grid

I get a new row on dropdown Click and am using enableCellEditOnFocus and when I try to open the dropdown it is not opening and alternate dropdowns are working properly. To avoid confusion I altered the code and I am showing that bit of code that is giving me the error and here is my plunker.
This is my ui-grid object
$scope.gridOptions = {
enableCellEditOnFocus: true
};
$scope.gridOptions.columnDefs = [
{ name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
{ id: 1, gender: 'male' },
{ id: 2, gender: 'female' }
] } ];
I add new row by using this code:
$scope.addNewRow = function () {
$scope.gridOptions.data.push({
"gender": "male"});
};
//adding new row inside of uigrid
$scope.newRow = function (row, columnIndex) {
tempIndexSave = "";
tempIndexSave = _.indexOf($scope.gridOptions.data, row);
var length = $scope.gridOptions.data.length;
if (length - 1 == tempIndexSave) {
$scope.addNewRow();
}
};
The problem is due to these lines where you can see there's a hack for screen readers.
This hack may bring issues similar to yours because it depends on beginCellEdit and afterCellEdit events to be fired evenly and with a fixed pattern:
beginCellEdit
afterCellEdit
beginCellEdit
afterCellEdit
beginCellEdit
...
Adding a new row while already editing a row breaks this pattern since, for the new created row, you are missing a beginCellEdit, so the preventMouseDown function will always fire, preventing user interaction.
I put up a workaround, but I don't advise you using this if you want to keep compatibility with screen readers (see comments before the lines in the file I linked to), because the workaround might break the hack.
The workaround consists of raising a fake beginCellEdit while adding the row, as you can see in this updated plunkr.
...
if (length - 1 == tempIndexSave) {
$scope.addNewRow();
$scope.gridApi.edit.raise.beginCellEdit();
}
...

How to set date collection as a data source in AngularJs UI grid?

I need to display only a Date Collection object as a data source in my UI Grid.
Do I need to define a field under ColumnDefs in this case? Also, I need to include a column to delete that particular row, in this case Delete the current Date object.
How can I accomplish this? Below is my code
editor.mySeasonBreaks = {
data: "editor.mySeasons",
columnDefs:
[{ field: "????", visible: true, displayName: "Season Break" },
{
name: 'delete',
displayName: "",
cellTemplate: "<button ng-click="editor.delete(row.entity)" />"
}]
};
In the above code, editor.mySeasons is just a date array object.
Thanks in advance
You could create an object-array with your dates and define the columns as needed. This way you got more control and its easy to adjust/expand.
Now for your row-deletion I created a Plunkr thats showcases a possible solution.
As you suggest you need to add a cellTemplate that references your delete-function
cellTemplate: "<button ng-click=\"grid.appScope.delete(row)\">DELETE ROW</button>"
To access that function, you need to add it to your gridDefinition and ther property is called appScopeProvider
Possible setup would be
appScopeProvider: {
delete : function(row) {
editor.mySeasons.forEach(function(entry, index){
if(entry.myDate === row.entity.myDate) {
editor.mySeasons.splice(index, 1);
}
});
},
}
This is not recommended scenario, but you can use something like this:
$scope.myData=['2015-22-07', '2017-10-08', '2020-17-02'];
$scope.gridOptions = {
data: 'myData',
columnDefs: [
{
displayName: 'Date Array',
cellTemplate: '<div class="ngCellText ng-class="col.colIndex()">{{row.entity}}</div>'
}
]
};
You can test it here.
There are issues with sorting and probably something else.
It's better IMO to translate your array of dates to array of objects:
var res = [];
myData.forEach(function(el){
res.push({date: el});
});
Then specify column as usual:
{ field: 'date', visible: true, displayName: 'Season Break' }

ui-grid dropdown editor with complex json object

I am using the angular-ui-grid to make an editable grid and have looked over the tutorial here:
http://ui-grid.info/docs/#/tutorial/201_editable
Unlike the example where the options are simple structures like gender male/female, I am trying to bind a complex JSON object in my model. All of the examples I have found are binding to a simple String or Integer object.
Here is an example on Plunker (this code was first taken from the tutorial and then slightly modified to show the problem I am facing):
The core of it is in the columnDef config for the data grid.
{
name: 'product',
field: 'product.name',
enableCellEdit: true,
editType: 'dropdown',
editDropdownOptionsArray: $scope.products,
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'name',
editDropdownValueLabel: 'name'
}
I have tried changing the values for field and editDropdownIdLabel to a variety of options to no avail. If you look at the 3 console.log lines 51-53 in the sample code you will see that as you change the product selected the name changes but the ID stays the same. I want to be able to pass the whole product object to the backend when ultimately saving changes made in this grid.
I had a quite similar issue and I found a solution which worked for me:
https://github.com/angular-ui/ng-grid/issues/2808
mltroutt's comment on Feb 20 - a generic filter.
based on that, in your pluncker I tried that in the following way:
your product column should be look like this:
name: 'product',
field: 'product.id',
cellFilter: "griddropdown:editDropdownOptionsArray:editDropdownIdLabel:editDropdownValueLabel:row.entity.product.name",
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'id',
editDropdownValueLabel: 'name',
editDropdownOptionsArray: $scope.products
then after your controller, you have to insert a filter like this:
.filter('griddropdown', function () {
return function (input, map, idField, valueField, initial) {
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;
};
})
This can be solved by using the same product objects in your data array and the editDropdownOptionsArray array and getting the whole product structure placed into your data structure when a new one is selected. First, in the columnDef change the field to just product instead of product.name, change the editDropdownIdLabel to ref (explained in the next step), and add a cellTemplate as shown.
field: 'product',
editDropdownIdLabel: 'ref',
cellTemplate: '<div>{{row.entity.product.name}}</div>'
Second, create a self-referencing field ref inside each product so that you can return that instead of just id when a selection is made. Also, replace the product inside your data with a reference to the actual product object.
let prods = {};
angular.forEach($scope.products, (product) => {
prods[product.id] = product; // hash for products by id
product.ref = product; // self reference
});
angular.forEach(data, (person) => {
person.product = prods[person.product.id];
});
Now, when an item is selected everything is kept in sync. Also, you are (arguably) actually using the grid and select tools as intended and not creating filters, watchers, etc., etc. to try to fix things up.
Now, if ui-grid had an option (like maybe the default) where the object in the options array would be returned instead of requiring a field of the object to be returned this would be a lot easier and would not create circular data structures. Maybe editDropdownIdLabel: '' or 'self' or null? Or, maybe somebody knows of a better way to get the reference.
Plunker here: http://plnkr.co/edit/wjtuwgvZYIxWpkenJS7a?p=preview and a simpler version based on the gender field example from #bagavathi - http://plnkr.co/edit/JJduek?p=preview
This solution does assume that your product data really is the same and can be shared but is probably a typical use case.
Try this
$scope.gridOptions = {
enableSorting: false,
enableCellEditOnFocus: false,
data: data,
columnDefs: [
{
name: 'product',
field: 'productName',
enableCellEdit: true,
editType: 'dropdown',
editDropdownOptionsArray: $scope.products,
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'name',
editDropdownValueLabel: 'name'
}
],
onRegisterApi: function (gridApi) {
//set gridApi on scope
$scope.gridApi = gridApi;
gridApi.edit.on.afterCellEdit($scope, function (rowEntity, colDef, newValue, oldValue) {
if (colDef.name === 'product') {
for (var i = 0; i < $scope.products.length; i++) {
var prod = $scope.products[i];
if (prod.name === newValue) {
rowEntity.product = prod;
break;
}
}
calculateBOption(rowEntity);
}
});
}
}

Resources