1

I'm aware of security implications related to my request, but I need to allow a special super admin group of users an ability to create and evaluate angular html contained within variable on current $scope

Here is an example plunk:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" ng-init="variable = 3; content = '{{ variable }}'">
    <div>
      The value of $scope.variable === "{{ variable }}"
    </div>
    <div>
      The value of $scope.content === "{{ content }}"
    </div>
    <br>
    <div>
    The value of $scope.content is <b>ng-model</b>'ed via the following textarea:<br>
    </div>

    <textarea rows="3" ng-model="content"></textarea>

    <div style="border: 1px solid black">
      Instead of rendering the value of the $scope.content field which is currently equal to "{{ content }}" I need to render compiled and evaluated value which should be equal to "{{ variable }}"
    </div>
  </body>

</html>

Any suggestions?

Thank you in advance!

1
  • <body ng-controller="MainCtrl" ng-init="variable = 3; content = variable"> Commented Mar 22, 2015 at 1:03

1 Answer 1

1

You can make a directive that uses the $compile service to do this for you.

Here is what I came up with, and a fork of your Plunkr to show that it works.

app.directive('compile', function($compile) {
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      var prevScope;
      scope.$watch(attrs.compile, function(newVal, oldVal) {
        // create a span (an inline element) so we have an actual DOM node to
        // set the innerHTML of.
        var newElem = document.createElement('span');
        newElem.innerHTML = newVal;
        // clean up first
        if (prevScope) {
          prevScope.$destroy();
          prevScope = null;
        }
        // clear out the contents of this element
        elem.empty();
        // and replace it with the raw (uncompiled) node
        elem[0].appendChild(newElem);
        // now the node is in the DOM so we can compile it
        // but we want to use a try..catch because the user
        // might be in the middle of typing a new expression,
        // but the syntax right now is not valid so the
        // expression parser will throw an error.
        try {
          // compile the node in the DOM with a child of the existing scope
          prevScope = scope.$new();
          $compile(newElem)(prevScope);
        } catch (e) { /* don't need to do anything here */ }
      });
    }
  }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Btw. the code creates a memory leak when compile changes, here I've added another question: stackoverflow.com/questions/29190471/…
@Lu4 Well spotted, sir! I fixed it in that other question, and for future readers of this answer, you should know that I edited my answer here to include the fixed version as well.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.