0
votes

I'm writing a directive that wraps an input field and adds some standard functionality I want across the app. I'm transcluding the input element into my directive template to add ng-focus and other attributes to the input field before transcluding it into the wrapper directive. Right now, the template is loading correctly, but the scope methods are not firing the registered event handlers. My code thus far:

The Transcluded Directive

editInput.$inject = ['$parse'];
function transcludedDir($parse) {
    return {
        require: ['^wrapperDir', 'ngModel'],
        restrict: 'A',
        template: function(tElem, tAttrs) {
            tElem.attr('ng-key-enter', 'onInputSave()');
            return tElem;
        },
        link: function($scope, element, attrs, ctrls){
           ctrls[0].setNgModel(ctrls[1]);
            ctrls[0].modelSetter(function(value){
                $parse(atrs['ngModel'])($scope, value);
            });
            $scope.onInputSave = ctrls[0].save;
        }
    };
}

The Wrapper Directive (pushes in some buttons, delegates a save function, etc)

   wrapperDir.$inject = ['$q'];
    function wrapperDir($q) {
        return {
            transclude: true,
            restrict: 'E',
            scope: {
                onSave: '&'
            },
            templateUrl: 'template.tpl.html',
            controller: function($scope){
                var modelCtrl;
                var initialValue;
                var updateValue;
                this.setNgModel = function(ngModel){
                    modelCtrl = ngModel;
                    initialValue = modelCtrl.$modelValue;
                };
                this.modelSetter = function(setterFunction){
                    updateValue = setterFunction;
                };
                this.save = $scope.save = function save(){
                    var currentValue = modelCtrl.$modelValue;
                    var result = $scope.onSave({
                        currentValue: currentValue,
                        initialValue: initialValue
                    });
                    $q.when(result).then(function(res) {
                        initialValue = currentValue;
                    });
                };
                return this;
            }
        };
    }

The wrapper dir template and sample usage. The Wrapper Directive template is simple enough, and I just decorate the input with transcluded-dir to ensure that the transclusion link hooks up the special attributes, etc. Usage would look something like this:

<!-- template.tpl.html -->
<div>
    <!-- Input is jammed in here via transclusion -->
    <div ng-transclude></div>
    <div><!-- actions i want to append (buttons, etc) --></div>
</div>

<!-- Sample usage -->
<wrapper-dir on-save="mySaveFn()">
    <input transcluded-dir type='text' ng-mode="my_little_teapot"
</wrapper-dir>

ng-key-enter performs an action on enter in an input field, but the onInputSave method in the transcluded scope is never firing. Any ideas? Thanks in advance if you made it this far.

1

1 Answers

0
votes

I found an acceptable workaround that utilizes the following syntax in the transcluded controller:

editInput.$inject = ['$parse'];
function transcludedDir($parse) {
    return {
        require: ['^wrapperDir', 'ngModel'],
        restrict: 'A',
        link: function($scope, element, attrs, ctrls){
           ctrls[0].setNgModel(ctrls[1]);
           ctrls[0].modelSetter(function(value){
               $parse(atrs['ngModel'])($scope, value);
           });

           element.bind('keypress', function(event) {
               if (element.which == 13) {
                   ctrls[0].save(event);
               }
           )};
    };
}

I had limited success adding ng-click and ng-change as attributes during the link function and recompiling the element, but saw strange behavior on the model for certain events. With standard javascript events, the transclusion is working smoothly.

// This worked for some directives, but was inconsistent
element.attr('ng-key-enter', clickToEdit.save);
element.removeAttr('transcluded-dir');
element.removeAttr('data-transcluded-dir');
$compile(element)($scope);