While forever on rows in AngularJs Grid - angularjs

I'm using AngularJS's grid and in a column I call a function to return some html.
When debugging this function I noticed it is called infinitely.
I changed the function to only console.log("test") and "test" is printed like crazy.
I'm new to AngularJS and I'm working in this project of my company.
This is the column definition:
{
field: "statusId", width: '8%', enableSorting: true, displayName: "", enableHiding: false, enableFiltering: false,
cellTemplate: "<div class='ui-grid-cell-contents' ng-bind-html='grid.appScope.getIcon(row.entity.statusId)'></div>"
}
And the function:
$scope.getIcon = function (statusId) {
console.log("getIcon");
};
I don't know what code you guys need to help. Let me know in the comments.

It's seems a bug, see: Multiple grid.appScope calls when used in cellTemplate
To overcome this, you can use directives.

Related

AngularJs - ag-grid rowData using "controller as" syntax

[Update] This Plunker does what I want, but :
it uses ui-grid, rather than ag-grid.
it injects the grid into the module, rather than just the single controller which uses it.
I presume that these changes would be straightforward & will try to work them into my code when I get home in about 14 hours time.
If anyone wants to fork that Plunk and make those changes, I will award a bounty, as this is a good basic start point demo for others wanting to do the same, so that a Plunker would be of general help.
I am tantalizingly close, but
Cannot read property 'setRowData' of undefined (caused by "<ui-view class="ng-scope ng-binding">")"TypeError: Cannot read property 'setRowData' of undefined
I am using "controller as" syntax, hence the Self; (Self = this;). That is working fine, my problem is when I try to set the rowData for an ag-grid in the templateURL of a ui-router state.
It's much to big to post, but here's the relevant stuff:
<div id="currentCandidatesGridDiv"
ag-grid="Search_result_controller.currentCandidatesGrid"
class="ag-theme-balham red_border"
style="height: 30%; width:90%">
</div>
// lookup the container we want the Grid to use
const currentCandidatesGridDiv = document.querySelector('#currentCandidatesGridDiv');
// create the grid passing in the div to use together with the columns & data we want to use
new agGrid.Grid(currentCandidatesGridDiv, Self.currentCandidatesGrid);
Self.currentCandidatesGrid =
{
columnDefs: [
{ headerName: "Candidate", field: "candidate_name", sortable: true },
{ headerName: "Skills", field: "skills", sortable: true },
{ headerName: "Start date", field: "start_date", sortable: true }
],
rowData: [],
pagination: true,
paginationAutoPageSize: true,
};
Was I correct to rowData: [], or ought I to have rowData: <someVariable>?
Then I calculate the row data into an array, Self.currentCandidatesGridRowData.
When I try to Self.currentCandidatesGrid.api.setRowData(Self.currentCandidatesGridRowData); I get error showing above.
I searched, but cannot find a working Plunker using the controller as syntax.
[Dupers] 1) the "dupe" question does not have an answer, so is of no use to me
2) my question is specifically about using Self.xxxGrid.api.setRowData(Self.xxxGridRowData); with the `controller as syntax. Pleas ere-open. Thnaks
DEMO of ag-Grid with AngularJS using "controller As" syntax
When the ag-Grid script loads, it does not register with AngularJS 1.x. This is because AngularJS 1.x is an optional part of ag-Grid and you need to tell ag-Grid you want to use it:
agGrid.initialiseAgGridWithAngular1(angular);
angular.module("example", ["agGrid"])
For more information, see
Ag-Grid Documentation - Basic AngularJS 1.x Example
The DEMO on PLNKR
agGrid.initialiseAgGridWithAngular1(angular);
angular.module("example", ["agGrid"])
.controller("exampleCtrl", function() {
var columnDefs = [
{headerName: "Make", field: "make"},
{headerName: "Model", field: "model"},
{headerName: "Price", field: "price"}
];
var rowData = [
{make: "Toyota", model: "Celica", price: 35000},
{make: "Ford", model: "Mondeo", price: 32000},
{make: "Porsche", model: "Boxter", price: 72000}
];
this.gridOptions = {
columnDefs: columnDefs,
rowData: rowData
};
})
html, body {
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
html {
position: absolute;
top: 0;
left: 0;
padding: 0;
overflow: auto;
}
body {
padding: 1rem;
overflow: auto;
}
<script src="//unpkg.com/angular/angular.js"></script>
<script src='//unpkg.com/#ag-grid-community/all-modules/dist/ag-grid-community.min.js'>
</script>
<body ng-app="example" ng-controller="exampleCtrl as $ctrl"
style="height: 100%">
<div ag-grid="$ctrl.gridOptions" class="ag-theme-balham"
style="height: 100%;">
</div>
</body>
Was I correct to rowData: [], or ought I to have rowData: <someVariable>?
You can even ignore this property in gridOptions, but the difference is that:
if you will define rowData as an empty array - grid will render handle it as 'No rows to show', but if you will not define it, grid will show 'Loading...' - which is more correct, with a delayed request case.
Besides, you can handle overlay logic by yourself for more details check here.
Now, as I said in comments
Cannot read property 'setRowData' of undefined
this issue could be caused by using the wrong reference.
First, take a look and check this answer with ag-grid developer comment also.
Secondly, about an issue itself:
.controller('yourController', [function() {
var Self = this; // here's your controller reference
// then you will have columns and rowData (probably)
// but the most important part is here
Self.currentCandidatesGrid = {
... // anything that you need
onGridReady: gridReady // major point for future api reference
}
function gridReady(params){
Self.gridApi = params.api;
Self.columnsApi = params.columnsApi;
}
}]);
And after gridReady you would be able to use grid API methods via Self.gridApi
Demo

Howto bind a Angular ui-select result to ui-grid/ng-grid

i want to bind a ui-select result into a ui-grid...
$scope.gridOptions = {
enableSorting: true,
showFooter: true,
columnDefs: [
{ field: 'name', name: 'Name' },
],
data: 'multipleDemo.selected',
onRegisterApi: function( gridApi ) {
$scope.gridApi = gridApi;
}
};
$scope.selectItem = function (item, model) {
$scope.gridApi.core.notifyDataChange( $scope.gridApi.grid, uiGridConstants.dataChange.EDIT );
};
My Jade Template is like this:
ui-select(theme='bootstrap', multiple='', ng-model='multipleDemo.selected', ng-disabled='disabled', close-on-select='false', on-select='selectItem()')
ui-select-match(placeholder='select something...') {{$item.name}}
ui-select-choices(repeat='f in data | filter: $select.search')
div(ng-bind-html='f.name | highlight: $select.search')
#grid.grid(ui-grid="gridOptions")
EDIT
i solved the problem. (my ng-controller was only around the gird, and not around the select...)
Would you mind posting a plunker or fiddle with your code? Hard to visual it and I'm working with something similar. Cheers!
EDIT: Behold StackOverflow'ers, an OP who answers his own question with a working solution. A truly rare and majestic beast to witness. From his comment: http://embed.plnkr.co/d37YrfRjE7YZPgwCncBE/preview

AngularJS ui-grid issue with directive in cellTemplate

I have hit a head scratcher! It seems like a fairly simple issue... I am using the ui-grid angular control and I'm attempting to use a custom directive in the cellTemplate. I can succesfully get it in there, but the problem is I am not able to bind correctly to the directive. I can bind properties but not functions from the parent. When I try to access a parent function which has been bound I get an object not defined error.
As far as I know I setup binding and cell template correctly:
//in columndefs:
{
name: 'item', displayName: 'Status',
width: 200, cellTemplate: '<dropdowncss item="row.entity[col.field]" do-drop="dropdowncombo"></dropdowncss>'
},
//directive declaration:
app.directive('dropdowncss', function () {
return {
restrict: 'E',
scope:
{
item: '=',
doDrop: '&'
},
controller: 'DropDownCSSCtrl',
templateUrl: 'dropdowncss.html'
};
When you click on one of the colored drop downs it should alert 'success'
Please see the simple plunker here:
http://plnkr.co/edit/HuuxxgV1GoWzfWlUvafw?p=preview
Any help would be appreciated. Thanks!
So from the scope that the cellTemplate gets compiled, you are many miles deep in scopes and your function dropdowncombo does not exist. That is why you get undefined. From that scope, Your dropdowncombo function is actually $parent.$parent.$parent.$parent.$parent.$parent.dropdowncombo. Now I would never suggest you use that so you should engineer an alternate way to pass you scoped function from that cell template.
To view your plunker working, change line 20 of app.js to
width: 200, cellTemplate: '<dropdowncss item="row.entity[col.field]" do-drop="$parent.$parent.$parent.$parent.$parent.$parent.dropdowncombo"></dropdowncss>'
I would make the edit for you, but it's just too embarrassing to have that many $parents even in this modern age of acceptance.
So there are a few ways to fix this but here's my take. Save the function from your scope that you want to execute in the column definition and then call that using col.colDef.func
Updated column definition in app.js is as follows:
{
name: 'item', displayName: 'Status',
handleClick: $scope.dropdowncombo,
width: 200,
cellTemplate: '<dropdowncss item="row.entity[col.field]" do-drop="col.colDef.handleClick"></dropdowncss>'
}
Here's an edited working plunker
This question is Old but I have a better approach -
you can use grid.appScope to access current $scope.
so change you line 20 in app.js to -
width: 200, cellTemplate: '<dropdowncss item="row.entity[col.field]" do-drop="grid.appScope.dropdowncombo"></dropdowncss>'
working Plunker is here -
http://plnkr.co/edit/5LiETuG2PEOJhvEcFypF?p=preview
In case anyone else was curious I also found the method using events. $emit can be used to broadcast an event up the whole parent scope hierarchy. So the following worked:
Adding this to the parent scope:
$scope.$on('EventDropDown', function () {
alert('passed up the event successfully');
});
And calling it from the directive like this:
<div class="divDropDown" ng-click="$emit('EventDropDown')">
That passed it up to the parent scope correctly. In contrast to $emit, $broadcast sends events down the scope hierarchy (not applicable in this scenario). There is no other hooking up things other than the event name. That makes it kind of convenient.

Cell template in ng-grid

I am using cell template property of ng-grid. I am defining one function in the directive. Within the same directive I am defining my grid-options. Here is the code:
data: 'mydata',
columnDefs: [
{field:'Timeout', displayName:'Delay', cellTemplate: '<a href=""
ng-click= "Report(Alert,Key,1000,1,1);"><div class=\"ngCellText\">{{row.getProperty(col.field)}}</div></a>'}
]
and function Report is also defined within same directive.
ng-click is working whenever it gets clicked. The function is getting called but whatever the input variable I am passing (Alert and Key) is not passing to the function whereas the rest three parameters 1000,1,1 are getting passed.
Alert is the hard-coded string what I wants to pass.
Key is one of the array of integer values in 'mydata'.
I checked by using alert for these 2 specific values in function and it is showing UNDEFINED.
Please help in calling the function correctly. Thanks in advance.
Do you want something like this:
$scope.Report=function(msg,key,v1,v2,v3){
//use v1, v2, v3 for whatever you like
alert(msg+':'+key);
};
$scope.gridOptions = {
data: 'myData',
columnDefs: [
{
field: 'name',
displayName: 'Delay',
cellTemplate: '<div class=\"ngCellText\">{{row.getProperty(col.field)}}</div>'
}, {
field: 'age'
}
]
};
Note that the hardcoded string (msg) must be put in escaped quotes. I used age as example for a key. Since its a numeric value in this example, you don't need the quotes.
Here is a Plunker

Dynamic enableCellEdit

I am trying to figure out how to dynamically set enableCellEdit on a cell based on information in the row. For example, something like:
$scope.gridOpts = {
data: 'mydata',
columnDefs: [{field: 'sometimesIEdit', enableCellEdit:row.isEditable}]
}
Clearly row is not available in this context. Maybe enableCellEdit is evaluated purely at the column level and not the cell level making what I want to do impossible - I'm not sure.
I know that as a work around I can use editableCellTemplate with ng-if to show plain text, but I would rather the cell never go editable at all.
For me, the only solution that worked is using cellEditableCondition as a function:
cellEditableCondition: function ($scope) { return $scope.row.entity.isEditable }
This is pretty old but figured I'd attempt to answer anyway. I had this exact same problem and solved it using the editableCellTemplate for that column. This is the template I used is something like this:
var editableCellTemplate = '<div class="email" ng-edit-cell-if="isFocused && '
+ 'row.entity.canEdit">'
+ '<input ng-class="\'colt\' + col.index" ng-input="COL_FIELD" '
+ 'ng-model="COL_FIELD" />'
+ '</div>'
+ '<div ng-edit-cell-if="isFocused">'
+ '<div class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text>'
+ '{{COL_FIELD}}</span></div>'
+ '</div>'
+ '</div>';
So only if the row entity has canEdit equal to true can that cell be edited.
Another solution is to decorate one of ng-grid`s directives.
In this case 'ngCellHasFocusDirective'.
The basic logic is preventing event`s from firing if a condition is not met.
Using this method you can control cell edit for a cell when another cell in the row was changed.
I`m note sure if the "CellTemplate" solution will work when another cell in the row is edited and the result of this edit should disable cell editing for another cell in the row.
This is because a cell change activate a $digest on the cell $scope, I dont believe the $digest is fired on the row $scope.
In this gist link below I wrote a decorator for the 'ngCellHasFocus' directive which fires a function defined in "columnDef', the function returns TRUE or FALSE, editable or not.
An exapmle included.
GIST: https://gist.github.com/shlomiassaf/7485c61ecb464f261194
Old question, but as we need to maintain an app still using ng-grid (>=2.0.9), I thought I'd answer.
As it says in the docs (https://github.com/angular-ui/ui-grid/wiki/Defining-columns), you may specify a cellEditableCondition: boolean, either on the columnDef or in the Options object.
It also requires enableCellEdit: 'expression'.
Example is extracted from the link above
$scope.gridOptions = {
data: myDataSource,
enableCellSelection: true,
enableCellEditOnFocus: true,
cellEditableCondition: 'row.entity.editable',
columnDefs: [
{ field: 'firstName', displayName: 'First Name', width: "*", resizable: false, enableCellEdit: false},
{ field: 'lastName', displayName: 'First Name', width: "20%"},
{ field: 'address', displayName: 'Last Name', width: "*" ,
cellEditableCondition: 'row.entity.editable && !row.entity.isAddressDefined()'},
{ field: 'age', cellClass: 'ageCell', headerCellClass: 'ageHeader', width: "**"}]
};

Resources