Brian Sullivan
Brian Sullivan

Reputation: 28563

Using '&' notation in a directive used within an ng-repeat

I'm trying to allow a directive with an isolate scope to call a function on it's parent directive's scope. I've read numerous examples of using '&' notation in the directive's scope declaration to do this, but since the directive is used inside an ng-repeat and an ng-switch, scope inheritance seems to be thwarting me. The function doesn't seem to make it to my directive's scope.

I can get to the function by going up the parent chain ($scope.$parent.$parent.$parent.removeElement() works), but that feels gross. Is there a way around this?

Parent Directive:

function dynamicLayoutDirective($compile, $log, bevoLayoutEngine, layoutService) {
    return {
        restrict: 'ECMA',
        replace: true,
        templateUrl: 'templates/dynamicLayout.html',
        scope: {
            layoutSchema: '=',
            layout: '=',
            editMode: '='
        },
        controller: function($scope) {
            $scope.removeElement = function(element) {
                // This is the function I want to call
            }
        }
    }
}

dynamicLayout.html

<div ng-repeat="element in layoutSchema">
    <div ng-switch on="element.type">
        <bevo-input ng-switch-when="TextBoxType" element="element" edit-mode="editMode" remove-element="removeElement"></bevo-input>
        <bevo-datepicker ng-switch-when="DateType" element="element" edit-mode="editMode"></bevo-datepicker>
        <bevo-section ng-switch-when="SectionType" element="element" edit-mode="editMode"></bevo-section>
    </div>
</div>

Child directive:

angular.module('ngBevoInput', []).directive('bevoInput', function() {
    return {
        restrict: 'E',
        templateUrl: 'templates/bevoInput.html',
        scope: {
            element: '=',
            editMode: '=',
            removeElement: '&'
        },
        controller: function($scope) {
            $scope.remove = function() {
                $scope.removeElement()({element: $scope.element});
                // $scope.removeElement() returns undefined here.
                // I can get to the function by doing $scope.$parent.$parent.$parent.removeElement
            }
        }
    }
});

bevoInput.html

<div class="col-md-10 form-inline">
    <input type="text" value="{{element.display}}" ng-hide="editMode" />
    <input type="text" disabled ng-show="editMode" />
    <button ng-show="editMode" ng-click="remove()" />
</div>

Upvotes: 1

Views: 211

Answers (1)

New Dev
New Dev

Reputation: 49590

You have 2 bugs that I can see:

1) You are assigning the callback function incorrectly. You are only passing the function name, but Angular expects an expression that invokes an outer-scope function, so add the parenthesis and pass the element parameter.

<bevo-input remove-element="removeElement(element)"></bevo-input>

2) You are passing {element: $scope.element} to the return value of $scope.removeElement function. Remove the extra parenthesis.

$scope.removeElement({element: $scope.element});

EDIT:

Another issue I discovered has to do with the root element of the template having ng-repeat AND the template has replace: true. I'm not sure of the root cause (could be that the scope is lost), but to solve this, either (1) add another root, or (2) set replace: false.

Upvotes: 1

Related Questions