Search code examples
javascriptangularjsangularjs-directiveangularjs-compileangularjs-ng-if

Directive under ng-if doesn't get recompiled when inserted in DOM


Here's an example which demonstrates the problem described in the title: https://plnkr.co/edit/Xn1qgYftc5YHMsrGj0sh?p=preview

Directive code:

.directive('translate', function($compile) {
  return {
    compile: function(element) {
      var html = element.html().split('<br plural="">');
      return function(scope, element, attrs) {
        function c(h) {
          element.html(h);
          $compile(element.contents())(scope);
        }
        if (attrs.translate != '') {
          scope.$watch(function() {
            return scope.$eval(attrs.translate)
          }, function(val, oldval) {
            if (val == oldval && html[2] !== undefined) return;
            var p = html[2];
            html[2] = gettext(html[0], html[1], attrs.add !== undefined ? val + attrs.add : attrs.subtract !== undefined ? val - attrs.subtract : val);
            if (p != html[2]) c(html[2]);
          });
        } else c(gettext(html[0]));
      }
    }
  }
})

So the problem is when I toggle back directive to show with ng-if - it probably doesn't get fully reseted with recompilation(?) and therefore it causes misbehavior.
How can I track when directive is inserted and removed from DOM? If there's a way then I could solve this with an indicator. But there must be some better way, right?


Solution

  • Solved it like this:

    .directive('translate', function($compile) {
      return {
        compile: function(element, attrs) {
          if (attrs.translate == '') {
            element.html(gettext(element.html()));
            return;
          }
          attrs.html = element.html().split('<br plural="">');
          return {
            post: function (scope, element, attrs) {
              delete attrs.html[2];
              scope.$watch(function () {
                return scope.$eval(attrs.translate);
              }, function (val) {
                var p = attrs.html[2];
                attrs.html[2] = gettext(attrs.html[0], attrs.html[1], attrs.add !== undefined ? val + attrs.add : attrs.subtract !== undefined ? val - attrs.subtract : val);
                if (p == attrs.html[2]) return;
                element.html(attrs.html[2]);
                $compile(element.contents())(scope);
              });
            }
          }
        }
      }
    })
    

    Live example

    I think I've optimized it well enough, but feel free to correct the code.