Calling prettyPrint() dynamically in AngularJS ruins binding

4.8k Views Asked by At

I'm trying to prettify some text that is generated dynamically.

<div ng-app="Knob" ng-controller="myCtrl">
    <pre class="prettyprint">{{text}}</pre>
</div>

var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
   $scope.text = "hello world";
})

App.directive('prettyprint', function() {
    return {
        restrict: 'C',
        link: function postLink(scope, element, attrs) {
              prettyPrint();
        }
    };
});

The output:

hello worldtext}}

Any ideas why?

http://jsfiddle.net/yAv4f/62/

6

There are 6 best solutions below

9
On

Hard to say, what does prettyPrint() should return ?

It seems quite strange that you don't give any arguments to prettyPrint...

By the way, I think an angular filter would be a better fit for your need instead of a directive.

[EDIT]

This one is working "dynamically" using filter :

html :

<div ng-app="Knob" ng-controller="myCtrl">
    <!--<input ng-model="text" type="text"/>-->
    <pre ng-bind-html-unsafe="text|pretty"></pre>
</div>

js :

var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
    setTimeout(function() {
        $scope.text = "class Voila {};";
        $scope.$apply();
    }, 0);
});

App.filter('pretty', function(){
    return function(text) {
        return prettyPrintOne(text);
    }
})

You can see it at

http://jsfiddle.net/cSXpV/1/

You can uncomment the input to change directly the text that will be prettyfied

Note that this version is for Angular 1.1.1 (the version you choosed in your initial jsfiddle), for Angular 1.2.*, you have to use ng-bind-html and the ngSanitize module

Last point : now that it is dynamically prettyfied, the setTimeOut and $scope.$apply can be removed (info for readers)

[/EDIT]

0
On

Please try using ng-bind-html.

<div ng-app="Knob" ng-controller="myCtrl">
    <pre class="prettyprint" ng-bind-html="text"></pre>
</div>


app.directive('prettyprint', function() {
    return {
        restrict: 'C',
        link: function postLink(scope, element, attrs) {
          element.html(prettyPrintOne(element.html(),'',true));
        }
    };
});
0
On

I don't know why, but I find out if you delay 300ms to execute the prettyprint function, it works well. see below:

var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
   $scope.text = "hello world";
})

App.directive('prettyprint', function() {
    return {
        restrict: 'C',
        link: function postLink(scope, element, attrs) {
              setTimeout(prettyPrint,300);
        }
    };
});
0
On

My directive. It s waiting for $viewContentLoaded to be sure the template var({{}}) in it have already been computed by angular. should be used in a <pre>

.directive('prettyprint', function() {
  return {
    restrict: 'C',
    link: function postLink(scope, element) {
      scope.$on('$viewContentLoaded', function(){
        element.html(prettyPrintOne(element.html(),'',true));
      });
    }
  };
});
0
On

this is a late reply and im sure that you have solved the problem. However there may be some other people stumbling upon this thread with the same problem. I solved this using and adapted version of google-code prettify, which can be found here: https://github.com/angular/code.angularjs.org/tree/master/1.3.0-beta.3/docs/components/google-code-prettify-1.0.1 Simply follow the instructions on that page.

Now, prettifyPrint() can be called globally.

(function(){
    $('pre').addClass('prettyprint');
    prettyPrint();
})();

I placed this at the bottom of my dynamic template

1
On

It can be achieved by a small directive. Find the answer here AngularJs how to call prettyprint?

I would like to make a small addition to the directive by @carlosmantilla

You can achieve the same thing without creating the scope variable. I have added this correction on github

This should work properly I assume.

http://jsfiddle.net/yAv4f/143/

var App = angular.module('Knob', []);
App.controller('myCtrl', function($scope) {
    $scope.text = "function f1(){int a;}";
})

function replaceText(str)
{
    var str1 = String(str);
    return str1.replace(/\n/g,"<br/>");
}

app.directive('prettyprint', function() {
    return {
        restrict: 'C',
        link: function postLink(scope, element, attrs) {
              element.html(prettyPrintOne(replaceText(element.html()),'',true));
        }
    };
});