Search code examples
javascriptangularjssummernote

AngularJS conditionally add directive


I have a form that can be editable. I am trying to set the Summernote plugin when the user clicks a button.

For example, this is the form header, which should get summernote initialized when edit is true, destroyed when edit is false.

<div class="card-header" toggleSummerNote>
  <h2>{{questionnaire.description.title}}</h2>
</div>

How do I make the summernote directive conditional? I tried with this directive, but it does not work. Any suggestions?

app.directive('toggleSummerNote', function ($compile) {
    return {
        restrict: 'A',
        replace: false,
        terminal: true,
        priority: 1000,
        link: function (scope, element, attrs) {
            scope.$watch('edit', function () {
                console.log(scope.edit);
                if (scope.edit) {
                    element.attr("summernote");
                    element.removeAttr("toggle-summer-note"); 
                    $compile(element)(scope);
                }
                else {
                  if (element.hasOwnProperty("summernote")) {
                      element.attr("toggle-summer-note");
                      element.removeAttr("summernote");
                      $compile(element)(scope);
                  }
                }
            });
        }
    };
});

Solution:

Based on Paul's answer below, this is what worked for me:

app.directive('toggleSummerNote', function ($compile) {
    return {
        scope: {
            editing: '='
        },
        compile: function (tElem, tAttrs) {
            return function (scope) {
                scope.$watch('editing', function (newValue, oldValue) {
                    if (newValue !== oldValue) {
                        if (newValue) {
                            tElem.attr('summernote', '');
                            tElem.removeAttr('toggle-summer-note');
                            $compile(tElem)(scope);
                            scope.summernote = true;
                        } else {
                            if (scope.summernote) {
                                tElem.attr('toggle-summer-note', '');
                                tElem.removeAttr('summernote');
                                $compile(tElem)(scope);
                                scope.summernote = false;
                            }
                        }
                    }
                });

            }
        }
    }
});

Solution

  • You could setup a $watch through your directive's compile step, then toggle the summernote attribute there and call $compile on the directive's element to link your summernote directive:

    in your directive definition

    ...
    compile: function(tElem, tAttrs) {
      return function(scope) {
    
        // this avoids looping/other side-effects
        tElem.removeAttr('some-directive', '');
    
        // editting would be the variable that toggles edit mode
        scope.$watch('editting', function(newValue, oldValue) {
          if (newValue !== oldValue) {
            console.log('editting changed', newValue, oldValue);
            if (newValue) {
              tElem.attr('summernote', '');  
            } else {
              tElem.removeAttr('summernote');
            }
    
            $compile(tElem)(scope);
          }
        });
    
      }
    }
    

    Here's an example in plnkr, I stubbed out a second directive so you can tell when it's linking/getting removed:

    http://plnkr.co/edit/r3mt6h8EocYKfDDr2vkR?p=preview