3

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!

3 Answers 3

5

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

Sign up to request clarification or add additional context in comments.

4 Comments

The parent hierarchy, may not be a problem, instead one of the parent itself maybe an isolated scope.
Thank you! I would have never figured this out on my own. It is not intuitive to me that bound functions only work when the directive is the direct child of a control sharing the parent scope. I wonder what the correct 'angular' way is of doing this? In normal applications we'd use the observer pattern with event handling. Perhaps that would be the best way to go? Or perhaps a factory? For now I think adding the handleClick function works fine. Thanks!
I forgot to ask - one last question: would the method included above duplicate the function code for every cell? Or is 'handleClick' simply a pointer to $scope.dropdowncombo, meaning that the function $scope.dropdowncombo will not be duplicated for each cell. I'm asking because in my final project there will be hundreds and possibly more of these drop downs in a single grid and I need to consider performance. Thanks!
It's a reference (like a pointer), so no duplication. Also, the reference is only added once to the column definition, to which the cells already refer. If you encounter performance issues, it will certainly not be due to that. GLHF.
4

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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.