title: Generic Angular Components - Optional Bindings
body: <p>I want to create a bunch of generic component (angular 1.5) with multiple optional binding that would be used inside multiple applications. </p>
  
  <p>I am afraid it will create a lot of unnecessary watchers for an application that doesn't use the most of optional bindings.</p>
  
  <p>Example:</p>
  
  <p><strong><em>Component declaration:</em></strong> </p>
  
  <pre><code>let dateRangeComponent = {
      bindings: {
          label: '@',
          name1: '@',
          name2: '@',
          model1: '&gt;?',
          model2: '&gt;?',
          extra1: '&gt;?'
      },
      template: `&lt;div ng-if="$ctrl.model1&gt;stuff&lt;/div&gt;
                 &lt;div ng-if="$ctrl.model2&gt;stuff&lt;/div&gt;
                 &lt;div ng-if="$ctrl.extra1&gt;stuff&lt;/div&gt;`
  };
  </code></pre>
  
  <p><strong><em>Component use example:</em></strong> </p>
  
  <pre><code>&lt;date-rage-component label="Pretty Date" name1="Start" name2="end"/&gt;
  </code></pre>
  
  <p>My question is if it is possible to automatically unwatch all the stuff related with the unused optional bindings, knowing they are undefined at compile time?</p>
  
  <p>For instance, imagine I want to use a component in my application where it doesn't need any of the optional Binding, angular would create a lot of unnecessary watchers to keep the ng-if updated, when we know they will always be false.</p>
  
  <p>Am I doing an early performance optimization when not needed or misunderstanding any concept?</p>
  
  <p>I though in creating a costum wrapper directive to take advantage of the lazy transclude compilation in angular 1.5</p>
  
  <p>Something like this (pseudo-code, not tested):</p>
  
  <pre><code>&lt;optional-binding-once ng-if="::attrs.model1"&gt;
    &lt;div ng-if="attrs.model1"&gt;
        stuff
    &lt;/div&gt;
  &lt;/optional-binding-once&gt;
  </code></pre>
  
  <p>In this way I think the code inside optional-binding-once would only be compiled if ng-if is true, thus reducing one watcher if a binding is not defined.</p>
  
  <h1><strong>(EDIT) Some Conclusions after some tests and research</strong></h1>
  
  <p>Well I guess there isn't a trivial solution to reduce the number of watchers inside a component when there are optional bindings not filled.</p>
  
  <p>I runned some tests through the $digest phase of angular, to check if the increased number of this kind of watchers is really problem.</p>
  
  <p>Here are my results:</p>
  
  <p>The tests where against a worst case scenario having 888 components with 4 optional bindings.</p>
  
  <p><strong>Chrome - <em>Without</em> optional bindings ( 888 component, total watchers 889)</strong></p>
  
  <ul>
  <li>Total Watchers: 889</li>
  <li>Last Digest Cycle time: 0.9950000000026193</li>
  <li>Average time for the last 1004 digest cycles: 1.0544920318724353 ms</li>
  <li>starting dom loading (400ms)</li>
  </ul>
  
  <p><strong>Chrome - <em>With</em> optional bindings ( 888 component, 4 optional bindings, total watchers 4441)</strong></p>
  
  <ul>
  <li>Total Watchers:4441</li>
  <li>Last Digest Cycle time: 1.1549999999988358</li>
  <li>Average time for the last 1001 digest cycles: 1.6851748251747816 ms</li>
  <li>starting dom loading (600ms)</li>
  </ul>
  
  <p><strong>Safari - <em>Without</em> optional bindings ( 888 component, total watchers 889)</strong></p>
  
  <ul>
  <li>Total Watchers: 889</li>
  <li>Last Digest Cycle time: 1.0849999999991269</li>
  <li>Average time for the last 530 digest cycles: 1.211632075471664 ms</li>
  </ul>
  
  <p><strong>Safari - <em>With</em> optional bindings ( 888 component, 4 optional bindings, total watchers 4441)</strong></p>
  
  <ul>
  <li>Total Watchers: 4441</li>
  <li>Last Digest Cycle time: 1.7450000000026193</li>
  <li>Average time for the last 588 digest cycles: 2.1167176870748237 ms</li>
  </ul>
  
  <p><strong>Conclusions:</strong></p>
  
  <p>In a worst case scenario the $digest time will be increased by 1ms. I don't think this rise will be a bottleneck for my application performance. This kind of watchers will fail in the first $digest condition ( value = get(current)) !== (last = watch.last) &amp;&amp; etc ...), thus having a small impact in the processing time, because they never change or get the angular context dirty!</p>