1

How to watch variable from directive in controller AngularJS?

I have a component with controller and directive

In my directive I'm listening for scroll and returning true if element is in view or false if it is not.

I want to be able to accesss my boolChangeClass variable in the controller so that I can call my function only if it is true.

My question is how can I access boolChangeClass in controller?

 'use strict'; angular.module('myModule') .component('myComponent', { template: ` <div class="component" inview ng-class="{min: boolChangeClass}"> </div> `, controller: function ($scope) { let $ctrl = this; let func = () => {console.log('my function')} $scope.$watch('boolChangeClass', func); } }) .directive('inview', ($window) => { return function(scope, element, attrs) { angular.element($window).bind("scroll", function() { let rect = element[0].getBoundingClientRect(); scope.boolChangeClass = rect.bottom > 0 && rect.right > 0 && rect.left < (window.innerWidth || document.documentElement.clientWidth) && rect.top < (window.innerHeight || document.documentElement.clientHeight) scope.$apply(); }); }; }) 

1 Answer 1

1

tl;dr;

To send variable to parent controller from a directive that uses scope:false:

<div on-scroll="$ctrl.fn($event)"></div> 
scope.$apply( () => { scope.$eval(attrs.onScroll, {$event: event}); }); 

Answer

Instead of setting the class with ng-class, have the directive set the class:

<div class="component" inview-class="min" ̶n̶g̶-̶c̶l̶a̶s̶s̶=̶"̶{̶m̶i̶n̶:̶ ̶b̶o̶o̶l̶C̶h̶a̶n̶g̶e̶C̶l̶a̶s̶s̶}̶" > </div> 
app.directive('inviewClass', ($window) => { return function(scope, elem, attrs) { angular.element($window).on("scroll", function(event) { let rect = elem[0].getBoundingClientRect(); let boolChangeClass = rect.bottom > 0 && rect.right > 0 && rect.left < (window.innerWidth || document.documentElement.clientWidth) && rect.top < (window.innerHeight || document.documentElement.clientHeight); let className = attrs.inviewClass; boolChangeClass ? elem.addClass(className) : elem.removeClass(className); }); }; }) 

This avoids involving the AngularJS digest cycle, modifying $scope, and adding a watcher.


Update

And what should I do in my controller? Check if class exists and then call he method?

Use an attribute to specify the function to be called on a scroll event:

<div class="component" inview-class="min" on-scroll="$ctrl.fn($event)" > </div> 
app.directive('inviewClass', ($window) => { return function(scope, elem, attrs) { angular.element($window).on("scroll", function(event) { let rect = elem[0].getBoundingClientRect(); let boolChangeClass = rect.bottom > 0 && rect.right > 0 && rect.left < (window.innerWidth || document.documentElement.clientWidth) && rect.top < (window.innerHeight || document.documentElement.clientHeight); let className = attrs.inviewClass; boolChangeClass ? elem.addClass(className) : elem.removeClass(className); // event.inview = {}; event.inview[className] = boolChangeClass; scope.$apply( () => { scope.$eval(attrs.onScroll, {$event: event}); }); }); }; }) 

On each scroll event, the directive will evaluate the on-scroll attribute as an AngularJS expression using $event as a local.


Update #2

But what if I want to call method in controller on scroll but only once when my variable is true? I tried to use one-time binding but it doesn't really work.

It would be wiser to have the controller filter the events:

<div class="component" inview-class="min" on-scroll="$ctrl.fn($event)" > </div> 
var minOnce; this.fn = (event) => { if (minOnce || !event.inview.min) return; //ELSE minOnce = true; // // ... }; 

This way the directive is more versatile and testing is easier.

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

2 Comments

Ok. And what should I do in my controller? Check if class exists and then call he method?
Thanks. It works great. But what if I want to call method in controller on scroll but only once when my variable is true? I tried to use one-time binding but it doesn't really work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.