Directive does not run link function when attribute changes value
Asked Answered
A

1

1

I have created a directive for encapsulating qTip2 library into my angular application (as described in another SO question) . I have a dictionary with different configurations for qTip and depending on the value I pass on the attribute cv-tooltip the appropriate configuration is passed in the .qtip call in the link function. This works fine for directives that are set in html (eg. shows a qtip on the right and cv-tooltip="left" on the left).

Problem arises when I change the value of the attribute from cv-tooltip="right" to cv-tooltip="left" from another directive, the tooltip directive link function does not re-run when the value changes and thus the qTip is not updated with the correct configuration.

qtip directive looks like this:

    mainApp.directive('cvTooltip', function () {
        var optionDictionary = {
            'right': {
                position: {
                    my: 'center left',
                    at: 'right center'
                },
                style: {
                    tip: {
                        corner: 'left center',
                        height: 10
                    }
                }
            },
            'left': {
                position: {
                    my: 'center right',
                    at: 'left center'
                },
                style: {
                    tip: {
                        corner: 'right center',
                        height: 10
                    }
                }
            }
        };


        return {
            restrict: 'A',
            scope: {
                positionType: '=cvTooltip'
            },
            link: function (scope, element, attrs) {

                var options = {
                    style: {
                        tip: {
                            width: 13
                        }
                    },
                    position: {
                        target: element
                    }
                };
                var defaults = optionDictionary[scope.positionType];
                $.extend(options, defaults);
                element.qtip('destroy');
                element.qtip(options);

            }
        }
    }
);

Other directive looks like:

    mainApp.directive('cvErrorOnBlur', ['$compile', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        replace: true,
        link: function (scope, element, attributes, controller) {
            element.bind("blur", function () {
                if (controller.$dirty && controller.$invalid) {
                    element.addClass('error');
                    element.attr('cv-tooltip', 'left');

                } else {
                    element.removeClass('error');
                    element.attr('cv-tooltip', 'right');

                }
            });
        }
    }
}]);

In html I use it like

 <input type="text" cv-tooltip="right" cv-error-on-blur />
Aficionado answered 5/12, 2013 at 11:52 Comment(4)
Link function runs only once.Are left and right variables on parent controllerVelamen
i guess right and left is static string in directive definitionHamish
Then the isolated scope definition properties should point to a controller variableVelamen
@Velamen As Ajay said, left and right are static strings that are passed to the directive (ie they are hardcoded in most cases). The exception is validation when they are altered by the seconds directive.Aficionado
C
1

You would have to use $observe or $watch to monitor changes to the attribute, but the value of the attribute would have to be interpolated ({{}})

Example:

<input type="text" cv-tooltip="{{right}}" cv-error-on-blur />

attrs.$observe('cvTooltip', function(newValue, oldValue) {

});

Could you just rewrite it into a single directive?

mainApp.directive('cvTooltip', function () {
    var optionDictionary = {
        'right': {
            position: {
                my: 'center left',
                at: 'right center'
            },
            style: {
                tip: {
                    corner: 'left center',
                    height: 10
                }
            }
        },
        'left': {
            position: {
                my: 'center right',
                at: 'left center'
            },
            style: {
                tip: {
                    corner: 'right center',
                    height: 10
                }
            }
        }
    };


    return {
        restrict: 'A',
        require:"^ngController",
        link: function (scope, element, attrs, controller) {
            var initialValue = attrs.cvTooltip;
            console.log(initialValue);
            var options = {
                style: {
                    tip: {
                        width: 13
                    }
                },
                position: {
                    target: element
                }
            };
            if (controller.$dirty && controller.$invalid) {
                element.addClass('error');
                var defaults = optionDictionary['left'];
                $.extend(options, defaults);
                element.qtip('destroy');
                element.qtip(options);

            } else {
                element.removeClass('error');
                var defaults = optionDictionary['right'];
                $.extend(options, defaults);
                element.qtip('destroy');
                element.qtip(options);
            }
        }
    }
Cathiecathleen answered 5/12, 2013 at 16:37 Comment(1)
I ended up in writing it in a single directive. I do not consider it to be optimum, but I don't have the experience with ng to do anything better right now.Aficionado

© 2022 - 2024 — McMap. All rights reserved.