1

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?

mr1031011
  • 3,574
  • 5
  • 42
  • 59
  • Possible duplicate of [AngularJS: Is there a better way to achieve this than the one specified?](http://stackoverflow.com/questions/29015493/angularjs-is-there-a-better-way-to-achieve-this-than-the-one-specified) – Paul Sweatte May 19 '17 at 16:16

1 Answers1

1

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>
Stepan Kasyanenko
  • 3,176
  • 1
  • 15
  • 23
  • I actually tried one-way binding but I run into this issue: I have a separate form to edit this same model, and when I'm done with editing I would like this new information to showup here as well. However, I find this behavior doesnt always work as expected, sometime say I type a long text, only the first character of the text is updated back here. I will updated my main question with more details regarding this. – mr1031011 Jun 16 '16 at 04:47
  • Duh. Thanks for pointing out the obvious. But seriously, thank you. You are absolutely right, why use Angularjs templating at all here when I can use pure js? I didn't use pure js, I'm already using lodash so I use lodash template to make parsing variables a bit easier. But the performance gain is still enormous :). Love it. Thanks again. – mr1031011 Jun 16 '16 at 18:43
  • 1
    One more thing to note, hope it helps someone else: I was also experiencing bad performance because when I re-compile the template I get memory leak. Solution was found on this page: http://roubenmeschian.com/rubo/?p=51 – mr1031011 Jun 16 '16 at 18:45
  • great benchmark, I've forked to add my library, https://jsfiddle.net/S_YOU/op5m227e/ – YOU Jul 03 '16 at 16:02