-
Notifications
You must be signed in to change notification settings - Fork 27.2k
Description
Quick, can you spot an error? (Currently it fails silently.)
<ul>
<li *ng-for="item in items">{{item}}</li>
</ul>There are two issues:
- It is
for ofnotfor in - It needs
var itemor#iteminstead ofitem
The current binding expands to
<ul>
<template [ng-for]="item" [ng-for-in]="items">
<li>{{item}}</li>
</template>
</ul>but it should have been:
<ul>
<template ng-for #item [ng-for-of]="items">
<li>{{item}}</li>
</template>
</ul>- it fails to match
[ng-for][ng-for-of]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 havengFororngForOfand hence should have prevent the monkey patch) - it then fails to notice that
itemis not defined (because we are trying to define it) (This should have failed!)
GOAL
- Identify typos in the HTML bindings and throw errors to hint to developers.
Strategy
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.
<div [title]="exp"></div>
<svg>
<g [x]="exp">
<svg>We can lazy compute that title is a property of div (by noticing that title is a property of the div element). This can be done in Compiler during the compilation step. The result would be something like:
var schema = {
'div': { 'title': 'title' },
'svg:g': { 'x': '@x' }
}
The above would tell us that it is OK to bind to title to internal property name title on a div. (We need this as some properties don't properly rename see { 'inner-html': 'innerHTML', 'readonly': 'readOnly', 'tabindex': 'tabIndex'} )
We could also tell that g is instance of SVGElement and in that case we bind to the x attribute rather then the default x properties.
But this does not work with WebComponents because during the compilation the element is in template tag and is not active, as a result we can not query its properties.
<google-youtube [video-id]="exp">there is no way for Angular to know if videoId is a valid, as a result we need to configure this:
@View({
webComponents: {
'google-youtube': {'!extends': 'div', 'video-id': 'videoId'}
}
})NOTE: !extends is used to say that all mappings from the div should be included.
By adding this schema definition Angular will be able to correctly resolve web-component assignments.
Resolution Rules
<div [foo]="exp" bar="literal">foo(property binding)- Is in schema => then assign
fooproperty to element - is in schema and is a directive => assign to
fooproperty and to the directive - is not in schema but it has a directive => assign to directive only
- is not in schema and does not have a directive => Throw an error
- Is in schema => then assign
bar(just a literal)- Is in schema => no-op (we leave the property as is)
- is in schema and is a directive => assign the literal one-time to the directive
- is not in schema but it has a directive => assign the literal one-time to the directive
- is not in schema and does not have a directive => 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.)
Error handling.
With the above rules the example will produce these errors:
<ul>
<li *ng-for="item in items">{{item}}</li>
</ul><ul>
<template [ng-for]="item" [ng-for-in]="items">
<li>{{item}}</li>
</template>
</ul>Can not bind 'item' to 'ng-for' because 'ng-for' is not a property of [TemplateElement, NgFor].Can not binditemsto 'ng-for-in' because 'ng-for' is not property of [TemplateElement, NgFor].