Apply CodeMirror to a ng-model-bound textarea

2.6k views Asked by At

I am coding a very very basic playground. For some reason, I need to embed the html panel inside an AngularJS app.

In this version, I put a JQuery change listener to the CSS panel, and applied CodeMirror to the textarea. And it worked.

I felt uncomfortable about having a JQuery event listener inside an AngularJS app, so I decided to bind the CSS panel to the AngularJS app, and made this version. But now, the problem is the CodeMirror code (that I comment below) does not work anymore:

HTML:

<body>
  <div ng-app="myApp" ng-controller="myCtrl">
    HTML:<br>
    <textarea rows=10 cols=40 ng-model="area1">html body area</textarea>
    <br>CSS:<br>
    <textarea id="css" rows=10 cols=40 ng-model="css"></textarea>
  </div>
  Output:
  <section id="output">
    <iframe></iframe>
  </section>
</body>

JavaScript:

var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope) {
    $scope.area1 = "<body>default</body>";  
    $scope.$watch('area1', function (json) {
      render();
    }, true);

    $scope.css="body {color: red}";
    $scope.$watch('css', function (json) {
      // CodeMirror does not work anymore
      // var cm_opt = { mode: 'css', gutter: true, lineNumbers: false };
      // var css_box = document.getElementById("css");
      // var css_editor = CodeMirror.fromTextArea(css_box, cm_opt);
      render();
    }, true);

    function render () {
      var source = "<html><head><style>" + $scope.css + "</style></head>" + 
                   $scope.area1 +"</html>";

      var iframe = document.querySelector('#output iframe'),
          iframe_doc = iframe.contentDocument;

      iframe_doc.open();
      iframe_doc.write(source);
      iframe_doc.close();
    }
 });

Does anyone know how to make CodeMirror work here?

Additionally, is it really a bad idea to use JQuery event listeners inside an AngularJS app? What's the best structure to code this playground that uses AngularJS + CodeMirror?

Edit 1: I found this thread, then I made a codeMirror directive, it does not work well. DevTools shows me an error TypeError: textarea.getAttribute is not a function at CodeMirror.fromTextArea(...).

3

There are 3 answers

1
Suresh B On BEST ANSWER

Here I added Demo For Code mirror in angularjs. I hope it will help you...

Here Demo

0
Sebri Zouhaier On
1
Ovidiu Dolha On

Response to solve the 2nd attempt of OP

In the directive's link function you are using the elem param as a pure HTML element (which is expected by codemirror), but angular provides it as a JQLite wrapped element - so basically you just need to get the HTML element from it and provide it to codemirror, then it will work:

var editor = CodeMirror.fromTextArea(elm[0], cm_opt);

(note elem[0] instead of elem)

In AngularJS it is not a bad practice to use directives to wrap JQuery-based logic to make components that rely on other technologies like code-mirror. In some cases you might do this yourself, but can also use already-built third party libraries as mentioned in the other answers.

Whatever you do, make sure you encapsulate non-angular logic well, by making use of directives and services.

Hope this helps.