Angular Directive refresh on parameter change

JavascriptAngularjsAngularjs DirectiveAngularjs Scope

Javascript Problem Overview


I have an angular directive which is initialized like so:

<conversation style="height:300px" type="convo" type-id="{{some_prop}}"></conversation>

I'd like it to be smart enough to refresh the directive when $scope.some_prop changes, as that implies it should show completely different content.

I have tested it as it is and nothing happens, the linking function doesn't even get called when $scope.some_prop changes. Is there a way to make this happen ?

Javascript Solutions


Solution 1 - Javascript

Link function only gets called once, so it would not directly do what you are expecting. You need to use angular $watch to watch a model variable.

This watch needs to be setup in the link function.

If you use isolated scope for directive then the scope would be

scope :{typeId:'@' }

In your link function then you add a watch like

link: function(scope, element, attrs) {
    scope.$watch("typeId",function(newValue,oldValue) {
        //This gets called when data changes.
    });
 }

If you are not using isolated scope use watch on some_prop

Solution 2 - Javascript

What you're trying to do is to monitor the property of attribute in directive. You can watch the property of attribute changes using $observe() as follows:

angular.module('myApp').directive('conversation', function() {
  return {
    restrict: 'E',
    replace: true,
    compile: function(tElement, attr) {
      attr.$observe('typeId', function(data) {
            console.log("Updated data ", data);
      }, true);

    }
  };
});

Keep in mind that I used the 'compile' function in the directive here because you haven't mentioned if you have any models and whether this is performance sensitive.

If you have models, you need to change the 'compile' function to 'link' or use 'controller' and to monitor the property of a model changes, you should use $watch(), and take of the angular {{}} brackets from the property, example:

<conversation style="height:300px" type="convo" type-id="some_prop"></conversation>

And in the directive:

angular.module('myApp').directive('conversation', function() {
  return {
    scope: {
      typeId: '=',
    },
    link: function(scope, elm, attr) {

      scope.$watch('typeId', function(newValue, oldValue) {
          if (newValue !== oldValue) {
            // You actions here
            console.log("I got the new value! ", newValue);
          }
      }, true);

    }
  };
});

Solution 3 - Javascript

I hope this will help reloading/refreshing directive on value from parent scope

<html>
        
        <head>
            <!-- version 1.4.5 -->
            <script src="angular.js"></script>
        </head>
        
        <body ng-app="app" ng-controller="Ctrl">
           
            <my-test reload-on="update"></my-test><br>
            <button ng-click="update = update+1;">update {{update}}</button>
        </body>
        <script>
            var app = angular.module('app', [])
            app.controller('Ctrl', function($scope) {
               
                $scope.update = 0;
            });
            app.directive('myTest', function() {
                return {
                    restrict: 'AE',
                    scope: {
                        reloadOn: '='
                    },
                    controller: function($scope) {
                        $scope.$watch('reloadOn', function(newVal, oldVal) {
                            //  all directive code here
                            console.log("Reloaded successfully......" + $scope.reloadOn);
                        });
                    },
                    template: '<span>  {{reloadOn}} </span>'
                }
            });
        </script>
        
        
   </html>

Solution 4 - Javascript

angular.module('app').directive('conversation', function() {
    return {
        restrict: 'E',
        link: function ($scope, $elm, $attr) {
            $scope.$watch("some_prop", function (newValue, oldValue) {
                  var typeId = $attr.type-id;
                  // Your logic.
            });
        }
    };
}

Solution 5 - Javascript

If You're under AngularJS 1.5.3 or newer, You should consider to move to components instead of directives. Those works very similar to directives but with some very useful additional feautures, such as $onChanges(changesObj), one of the lifecycle hook, that will be called whenever one-way bindings are updated.

app.component('conversation ', {
    bindings: {
    type: '@',
    typeId: '='
    },
    controller: function() {
        this.$onChanges = function(changes) {
            // check if your specific property has changed
            // that because $onChanges is fired whenever each property is changed from you parent ctrl
            if(!!changes.typeId){
                refreshYourComponent();
            }
        };
    },
    templateUrl: 'conversation .html'
});

Here's the https://docs.angularjs.org/guide/component" >docs for deepen into components.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLuke SapanView Question on Stackoverflow
Solution 1 - JavascriptChandermaniView Answer on Stackoverflow
Solution 2 - Javascriptj8ioView Answer on Stackoverflow
Solution 3 - JavascriptAbdulView Answer on Stackoverflow
Solution 4 - JavascriptGelioView Answer on Stackoverflow
Solution 5 - Javascriptvoodoo_patchView Answer on Stackoverflow