cssangularjstextareacodemirrorui-codemirror

Flick from a textarea to a ui-codemirror frame


I want to make an editor of files. By the following code (JSBin), we list all the file names on the left hand, and their body on the right hand. I use ui-codemirror to style the body of the files.

However, when we click on the file names and switch from one to another, from time to time, we could see the quick flick from a textarea to a codemirror frame, which is not a good experience for an editor.

Does anyone have a solution to avoid the flick? Addtionally, is it a good direction to make an editor by angularJS and ui-codemirror?

<html ng-app="flapperNews">
<head>
  <link rel="stylesheet" href="https://codemirror.net/lib/codemirror.css">
  <script src="https://code.jquery.com/jquery.min.js"></script>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
  <script src="https://codemirror.net/lib/codemirror.js"></script>
  <script src="https://codemirror.net/mode/xml/xml.js"></script>
  <script src="https://codemirror.net/mode/htmlmixed/htmlmixed.js"></script>
  <script src="https://codemirror.net/mode/javascript/javascript.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.11.0/ui-bootstrap-tpls.js"></script>

  <script>
    var app = angular.module('flapperNews', ['ui', 'ui.router']);

    app.config(['$stateProvider', function ($stateProvider) {
      $stateProvider
        .state('file', {
          template: '<textarea ui-codemirror="editorOptionsHTML" ng-model="file.body"></textarea>',
          controller: 'FileCtrl',
          params: { name: null }
        })
    }]);

    app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
      $scope.files = [
        { name: "index.html", body: "<html><body>index.html</body></html>" },
        { name: "index.js", body: "the body of index.js" },
        { name: "test.html", body: "the body of test.html" }];
    }]);

    app.controller('FileCtrl', ['$scope', '$stateParams', function ($scope, $stateParams) {
      $scope.file = $scope.files.find(function (file) { return file.name === $stateParams.name });
      $scope.editorOptionsHTML = { mode: 'text/html', lineNumbers: true, matchBrackets: true };
    }]);
  </script>
</head>

<body ng-controller="MainCtrl">
  <div class="row">
    <div class="col-sm-3 col-md-3 col-xl-3 col-lg-3">
      <div ng-repeat="file in files track by $index">
        <a ui-sref="file({name: file.name})">{{file.name}}</a>
      </div>
    </div>
    <div class="col-sm-9 col-md-9 col-xl-9 col-lg-9">
      <ui-view></ui-view>
    </div>
  </div>
</body>

</html>

Solution

  • Every time you click on the link, it is creating new editor, which is an expense operation.

    The best approach is to create one editor and load the content on every click.
    

    so I removed the ui-router linking (ui-sref) and related controllers

    <script>
     var app = angular.module('flapperNews', ['ui', 'ui.router']);
    
      app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
       $scope.files = [
        { name: "index.html", body: "<html><body>index.html</body></html>" },
        { name: "index.js", body: "the body of index.js" },
        { name: "test.html", body: "the body of test.html" }];
    
       $scope.editorOptionsHTML = { mode: 'text/html', lineNumbers: true, matchBrackets: true };
    
    
      // for every click event it will load the content
       $scope.go=function(file){
         $scope.file=file;
       }
      }]);
    

    and the body

    <body ng-controller="MainCtrl">
      <div class="row">
        <div class="col-sm-3 col-md-3 col-xl-3 col-lg-3">
          <div ng-repeat="file in files track by $index">
            <a ng-click="go(file)">{{file.name}}</a>
          </div>
        </div>
        <div class="col-sm-9 col-md-9 col-xl-9 col-lg-9">
          <textarea ui-codemirror="editorOptionsHTML" ng-model="file.body"></textarea>
        </div>
      </div>
    </body>
    

    Example : JSBin