Rani Radcliff
Rani Radcliff

Reputation: 5076

Call function in Directive when Parent Scope Variable Changes

I need to call a function in my directive when the value of variable in the parent controller changes. I tried adding a watch (I'm obviously doing it wrong) because nothing happens when the value changes. Here is the directive:

    angular.module('ssq.shared').directive('checkboxPicklist', function() {
    return {
        restrict: 'E',
        templateUrl: '/Scripts/app/Shared/directives/checkboxPicklist.html',
        replace: true,
        scope: {
            itemId: '=',
            list: '=',
            nameProp: '=',
            title: '@',
            searchPlaceholder: '@',
            callbackFn: '&',
            callMore: '&',
            clear: '='
        },

        link: function (scope, element, attrs) {
            scope.query = '';
            var parent = scope.$parent;
            var clear = parent.clear;
            scope.$watch(clear, function () {
                if (clear == true) {
                    this.clearAll();
                }
            })
            var child = element.find('.dropdown-menu');
            child.on({
                'click': function (e) {
                    e.stopPropagation();
                }
            });


            var selectedItemFn = function (item) {
                return item.selected;
            };

            scope.getSelectedCount = function () {
                return _.filter(scope.list, selectedItemFn).length;
            };
            scope.loadMore = function () {
                scope.callMore();
            };

            scope.allSelected = function(list) {
                var newValue = !scope.allNeedsMet(list);
                _.each(list, function(item) {
                    item.selected = newValue;
                    scope.callbackFn({ object: item });
                });
            };

            scope.allNeedsMet = function(list) {

                var needsMet = _.reduce(list, function(memo, item) {
                    return memo + (item.selected ? 1 : 0);
                }, 0);
                if (!list) {
                    return (needsMet === 0);
                }
                return (needsMet === list.length);
            };

            function clearAll() {
                _.each(list, function (item) {
                    item.selected = false;
                })
            }
        }

    };
});

Here is where I am trying to watch the variable:

            var parent = scope.$parent;
            var clear = parent.clear;
            scope.$watch(clear, function () {
                if (clear == true) {
                    this.clearAll();
                }
            })

Here is the function in my parent controller that changes the value of "clear"

    $scope.clearFilters = function (clear) {

    $scope.clear = true;

    $scope.form.selected.services = [];
    $scope.form.picked.areas = [];
    $scope.form.certified.verifications = [];
    $scope.form.subscribed.subscriptions = [];
    $scope.form.OperatorBusinessUnitID = null;
    $scope.form.OperatorBusinessUnitID = null;
};

I tried setting an attribute called "clearFilter" and assigning the variable to it, but the watch still doesn't trigger:

            scope.$watch(attrs.clearFilter, function (value) {
                if (value == true) {
                    this.clearAll();
                }
            });

                            <checkbox-picklist data-item-id="'servicesPicklist'"
                                           data-search-placeholder="Search Services"
                                           data-list="services"
                                           data-title="Service(s)"
                                           data-name-prop="'vchDescription'"
                                           data-callback-fn="addService(object)"
                                           call-more="loadMoreServices()"
                                           clear-filter="clear">

                        </checkbox-picklist>

I'm not really sure if I am calling the function correctly. scope.$parent above does get the initial value of the variable from the parent scope, but once it changes, it never updates.

EDIT:What I have discovered is the normal scope.$watch('clear', function...) is not working it seems because the directive is in "ssq.shared" module which is injected in my my Main Module "myModule" (see below), so even though the page the directive is on uses my 'GeneralSearchCtrl', I cannot get the watch to work on the variable located in 'GeneralSearchCtrl'. If I use scope.$parent.clear I can see the value of the variable, but I cannot seem to set a watch on it.

My module injection code:

var app = angular.module('myModule', ['ui.bootstrap', 'checklist-model', 'ssq.shared', 'ngAnimate', 'ngTouch', 'ui.grid', 'ui.grid.pagination', 'ui.grid.selection', 'ui.grid.exporter', 'ui.grid.autoResize', 'ui.router', 'cgBusy', 'ui.mask', 'ngFileUpload', 'ngSanitize']);

The page where the directive lives uses:

<div ng-app="myModule" ng-controller="GeneralSearchCtrl">

I am unable to get a watch on the variable located in GeneralSearchCtrl.

Any assistance is greatly appreciated!!!!

Upvotes: 2

Views: 1070

Answers (3)

Rani Radcliff
Rani Radcliff

Reputation: 5076

As it turns out, the problem was that the directive had scope:{...} in its definition which stopped the "normal" scope.$watch('clear', function...) from working. I had to add clear: '=' to the scope list like so:

            replace: true,
        scope: {
            itemId: '=',
            list: '=',
            nameProp: '=',
            title: '@',
            searchPlaceholder: '@',
            callbackFn: '&',
            callMore: '&',
            clear: '='
        },

Then clear="clear" to the directive like so:

                            <checkbox-picklist data-item-id="'servicesPicklist'"
                                           data-search-placeholder="Search Services"
                                           data-list="services"
                                           data-title="Service(s)"
                                           data-name-prop="'vchDescription'"
                                           data-callback-fn="addService(object)"
                                           call-more="loadMoreServices()"
                                           clear="clear">

                        </checkbox-picklist>

Then in the directive I had to add the watch like this for it work:

                scope.$watch('$parent.clear', function (newValue, oldValue) {
                if (newValue == true) {
                 clearAll();
                alert('it works!');
                }
            })

I really hope this helps someone else as this was difficult for me to figure out. Happy coding!

Upvotes: 0

gyc
gyc

Reputation: 4360

scope.$watch(clear, function () {
  if (clear == true) {
    this.clearAll();
  }
})

This.clearAll() doesn't exist in the scope of your $watch function. Simply calling clearAll() should work better.

The signature of the watch function is not correct.

scope.$watch('clear', function (new, old) {}

Upvotes: 1

Sajeetharan
Sajeetharan

Reputation: 222722

Add a watch for the $scope value and call the function,

scope.$watch('clear', function(newValue, oldValue) {
if (newValue) {
  this.clearAll();
}
});

Upvotes: 1

Related Questions