Search code examples
angularjsoptimizationangularjs-compile

Angular: How do I compile once then destroy all watches?


Due to performance issue, I would like to be able to simply compile a template piece once, then completely remove all watches etc from it, simply use the final template for display purpose only.

I tried with $compile but as soon as I use $destroy on scope then everything including the parsed content is reversed back to default.

Note: this is regarding Angularjs 1.5, not Angular 2

-----Edit 1------

@Stepan Kasyanenko suggested I can use one-way binding. I'm actually using it but with some issues:

  1. I have thousands of form rows I need to display and angularjs cannot handle this amount of watches, so I decided to cheat by printing a display version of these rows only. Whenever the user clicks on a row to edit then I swap it out with a real editable model. For these display only rows I'm using one-way binding.

  2. It would be great if I can skip the one-way binding as well since it still creates some performance issue though much less than ngModel, that's why I asked the question.

  3. With one-way binding, it seems like for some reason, even with the same code on the different sites behavior is flaky. Sometimes the live model is updated with 1 long text when the user types something, but the display version only get the 1st text (probably because of the way one-way binding should works. The only solution I can think of is to re-compile the display row at this time?


Solution

  • You can use one-way binding.

    For example jsfiddle:

    angular.module('ExampleApp', [])
      .controller('ExampleController', function($scope) {
        $scope.oneWay = "one";
        $scope.twoWay = "two";
      });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
    <div ng-app="ExampleApp">
      <div ng-controller="ExampleController">
        <div> One way
          <input ng-model="oneWay"> {{::oneWay}}
        </div>
        <div> Two way
          <input ng-model="twoWay"> {{twoWay}}
        </div>
      </div>
    </div>

    UPDATE

    I did some comparisons for drawing large amounts of data.

    Example on jsfiddle

    • AngularJs v1.4.8. With one-way binding. 100k records - 7 sec on script, 7 second on render.
    • jQuery v2.2.3. 100k records - 8 sec on script, 6 second on render. Results may be better. It is necessary to pass a separate examination.
    • Native JS. 100k records - 0.3 sec on script, 6 second on render.

    As you can see the fastest way - the Native JS.

    angular.module('ExampleApp', [])
      .controller('ExampleController', function() {
        var vm = this;
        vm.countRow = 100000;
        vm.arrayAngular = [];
        vm.startGenerateAngular = function() {
          vm.arrayAngular = [];
          for (var i = 0; i < vm.countRow; i++) {
            vm.arrayAngular.push(i);
          }
        }
      });
    
    function startGenerateJQuery() {
      var count = $("#countRow").val() * 1;
      var $content = $("#contentJQuery");
      $content.html("");
      for (var i = 0; i < count; i++) {
        var divParent = $('<div>');
        var divChild = $('<div>');
        divChild.text(i);
        divParent.append(divChild);
        $content.append(divParent);
      }
    }
    
    function startGenerateNative() {
      var count = $("#countRow").val() * 1;
      var content = document.querySelector("#contentNative");
      content.innerHTML = "";
      for (var i = 0; i < count; i++) {
        var divParent = document.createElement('div');
        var divChild = document.createElement('div');
        divChild.innerText = i;
        divParent.appendChild(divChild);
        content.appendChild(divParent);
      }
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
    
    <div ng-app="ExampleApp">
      <div ng-controller="ExampleController as vm">
        <input id="countRow" ng-model="vm.countRow">
        <div>Generate angular: 100k records - 7 sec on script, 7 second on render
          <br>
          <input type="button" ng-click="vm.startGenerateAngular()" value="Go">
        </div>
        <div>Generate jQuery: 100k records - 8 sec on script, 6 second on render
          <br>
          <input type="button" onclick="startGenerateJQuery()" value="Go">
        </div>
        <div>Generate Native: 100k records - 0.3 sec on script, 6 second on render
          <br>
          <input type="button" onclick="startGenerateNative()" value="Go">
        </div>
        <div ng-repeat="item in vm.arrayAngular">
          <div>{{::item}}</div>
        </div>
        <div id="contentJQuery">
        </div>
        <div id="contentNative">
        </div>
      </div>
    </div>