<p dir="auto">If I type <code class="notranslate">*for</code>, or any template directive, without an attribute value, it will error with <code class="notranslate">Cannot read property 'split' of null</code>.</p>
<p dir="auto">It should give me a proper error.</p>
<p dir="auto">You might ask, "But Andrew, how can you forget to provide an attribute value?"</p>
<p dir="auto">Well, I forgot my leading quote: <code class="notranslate">&lt;div *for=#item of items"&gt;&lt;/div&gt;</code></p>
<p dir="auto">Quick, can you spot an error? (Currently it fails silently.)</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;ul&gt;
  &lt;li *ng-for=&quot;item in items&quot;&gt;{{item}}&lt;/li&gt;
&lt;/ul&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">li</span> <span class="pl-c1">*ng-for</span>="<span class="pl-s">item in items</span>"<span class="pl-kos">&gt;</span>{{item}}<span class="pl-kos">&lt;/</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">There are two issues:</p>
<ul dir="auto">
<li>It is <code class="notranslate">for of</code> not <code class="notranslate">for in</code></li>
<li>It needs <code class="notranslate">var item</code> or <code class="notranslate">#item</code> instead of <code class="notranslate">item</code></li>
</ul>
<p dir="auto">The current binding expands to</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;ul&gt;
  &lt;template [ng-for]=&quot;item&quot; [ng-for-in]=&quot;items&quot;&gt;
    &lt;li&gt;{{item}}&lt;/li&gt;
  &lt;/template&gt;
&lt;/ul&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">template</span> <span class="pl-c1">[ng-for]</span>="<span class="pl-s">item</span>" <span class="pl-c1">[ng-for-in]</span>="<span class="pl-s">items</span>"<span class="pl-kos">&gt;</span>
    <span class="pl-kos">&lt;</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>{{item}}<span class="pl-kos">&lt;/</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;/</span><span class="pl-ent">template</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">but it should have been:</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;ul&gt;
  &lt;template ng-for #item [ng-for-of]=&quot;items&quot;&gt;
    &lt;li&gt;{{item}}&lt;/li&gt;
  &lt;/template&gt;
&lt;/ul&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">template</span> <span class="pl-c1">ng-for</span> <span class="pl-c1">#item</span> <span class="pl-c1">[ng-for-of]</span>="<span class="pl-s">items</span>"<span class="pl-kos">&gt;</span>
    <span class="pl-kos">&lt;</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>{{item}}<span class="pl-kos">&lt;/</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;/</span><span class="pl-ent">template</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span></pre></div>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> it fails to match <code class="notranslate">[ng-for][ng-for-of]</code> and turns the binding to element property bindings (ie monkey patches the properties on template element) (This should have failed because it should have noticed that the element does not have <code class="notranslate">ngFor</code> or <code class="notranslate">ngForOf</code> and hence should have prevent the monkey patch)</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> it then fails to notice that <code class="notranslate">item</code> is not defined (because we are trying to define it) (This should have failed!)</li>
</ul>
<h1 dir="auto">GOAL</h1>
<ul dir="auto">
<li>Identify typos in the HTML bindings and throw errors to hint to developers.</li>
</ul>
<h1 dir="auto">Strategy</h1>
<p dir="auto">The way to do this properly is to have a schema for which properties are allowed on which DOM elements. Currently we can lazy compute such as schema for DOM elements. But we can not compute them for WebComponents. So the proposal is to WebComponents publish their own schema.</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;div [title]=&quot;exp&quot;&gt;&lt;/div&gt;
&lt;svg&gt;
  &lt;g [x]=&quot;exp&quot;&gt;
&lt;svg&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">[title]</span>="<span class="pl-s">exp</span>"<span class="pl-kos">&gt;</span><span class="pl-kos">&lt;/</span><span class="pl-ent">div</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;</span><span class="pl-ent">svg</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">g</span> <span class="pl-c1">[x]</span>="<span class="pl-s">exp</span>"<span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;</span><span class="pl-ent">svg</span><span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">We can lazy compute that <code class="notranslate">title</code> is a property of <code class="notranslate">div</code> (by noticing that <code class="notranslate">title</code> is a property of the <code class="notranslate">div</code> element). This can be done in Compiler during the compilation step. The result would be something like:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="var schema = {
  'div': { 'title': 'title' },
  'svg:g': { 'x': '@x' }
}"><pre class="notranslate"><code class="notranslate">var schema = {
  'div': { 'title': 'title' },
  'svg:g': { 'x': '@x' }
}
</code></pre></div>
<p dir="auto">The above would tell us that it is OK to bind to <code class="notranslate">title</code> to internal property name <code class="notranslate">title</code> on a <code class="notranslate">div</code>. (We need this as some properties don't properly rename see <code class="notranslate">{ 'inner-html': 'innerHTML', 'readonly': 'readOnly', 'tabindex': 'tabIndex'}</code> )</p>
<p dir="auto">We could also tell that <code class="notranslate">g</code> is instance of <code class="notranslate">SVGElement</code> and in that case we bind to the <code class="notranslate">x</code> attribute rather then the default <code class="notranslate">x</code> properties.</p>
<p dir="auto">But this does not work with WebComponents because during the compilation the element is in <code class="notranslate">template</code> tag and is not active, as a result we can not query its properties.</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;google-youtube [video-id]=&quot;exp&quot;&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">google-youtube</span> <span class="pl-c1">[video-id]</span>="<span class="pl-s">exp</span>"<span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">there is no way for Angular to know if <code class="notranslate">videoId</code> is a valid, as a result we need to configure this:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@View({
  webComponents: {
    'google-youtube': {'!extends': 'div', 'video-id': 'videoId'}
  }
})"><pre class="notranslate">@<span class="pl-v">View</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">webComponents</span>: <span class="pl-kos">{</span>
    <span class="pl-s">'google-youtube'</span>: <span class="pl-kos">{</span><span class="pl-s">'!extends'</span>: <span class="pl-s">'div'</span><span class="pl-kos">,</span> <span class="pl-s">'video-id'</span>: <span class="pl-s">'videoId'</span><span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">NOTE: <code class="notranslate">!extends</code> is used to say that all mappings from the <code class="notranslate">div</code> should be included.</p>
<p dir="auto">By adding this schema definition Angular will be able to correctly resolve web-component assignments.</p>
<h1 dir="auto">Resolution Rules</h1>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;div [foo]=&quot;exp&quot; bar=&quot;literal&quot;&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">[foo]</span>="<span class="pl-s">exp</span>" <span class="pl-c1">bar</span>="<span class="pl-s">literal</span>"<span class="pl-kos">&gt;</span></pre></div>
<ol dir="auto">
<li><code class="notranslate">foo</code> (property binding)
<ul dir="auto">
<li>Is in schema =&gt; then assign <code class="notranslate">foo</code> property to element</li>
<li>is in schema and is a directive =&gt; assign to <code class="notranslate">foo</code> property and to the directive</li>
<li>is not in schema but it has a directive =&gt; assign to directive only</li>
<li>is not in schema and does not have a directive =&gt; Throw an error</li>
</ul>
</li>
<li><code class="notranslate">bar</code> (just a literal)
<ul dir="auto">
<li>Is in schema =&gt; no-op (we leave the property as is)</li>
<li>is in schema and is a directive =&gt; assign the literal one-time to the directive</li>
<li>is not in schema but it has a directive =&gt; assign the literal one-time to the directive</li>
<li>is not in schema and does not have a directive =&gt; Throw an error. (Implication is that if a component wants to use attributes for CSS which are not part of DOM, they will have to be declared ahead of time in the schema.)</li>
</ul>
</li>
</ol>
<h1 dir="auto">Error handling.</h1>
<p dir="auto">With the above rules the example will produce these errors:</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;ul&gt;
  &lt;li *ng-for=&quot;item in items&quot;&gt;{{item}}&lt;/li&gt;
&lt;/ul&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">li</span> <span class="pl-c1">*ng-for</span>="<span class="pl-s">item in items</span>"<span class="pl-kos">&gt;</span>{{item}}<span class="pl-kos">&lt;/</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span></pre></div>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;ul&gt;
  &lt;template [ng-for]=&quot;item&quot; [ng-for-in]=&quot;items&quot;&gt;
    &lt;li&gt;{{item}}&lt;/li&gt;
  &lt;/template&gt;
&lt;/ul&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">template</span> <span class="pl-c1">[ng-for]</span>="<span class="pl-s">item</span>" <span class="pl-c1">[ng-for-in]</span>="<span class="pl-s">items</span>"<span class="pl-kos">&gt;</span>
    <span class="pl-kos">&lt;</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>{{item}}<span class="pl-kos">&lt;/</span><span class="pl-ent">li</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;/</span><span class="pl-ent">template</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">ul</span><span class="pl-kos">&gt;</span></pre></div>
<ul dir="auto">
<li><code class="notranslate">Can not bind 'item' to 'ng-for' because 'ng-for' is not a property of [TemplateElement, NgFor].</code></li>
<li><code class="notranslate">Can not bind</code>items<code class="notranslate">to 'ng-for-in' because 'ng-for' is not property of [TemplateElement, NgFor].</code></li>
</ul>