Skip to content

Have a schema for bindings, and report error on miss-typed bindings. #2014

Closed

Description

@mhevery

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 of not for in
  • It needs var item or #item instead of item

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 have ngFor or ngForOf and hence should have prevent the monkey patch)
  • it then fails to notice that item is 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">
  1. foo (property binding)
    • Is in schema => then assign foo property to element
    • is in schema and is a directive => assign to foo property 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
  2. 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].

Activity

  1. added this to the milestone on May 19, 2015
  2. ewinslow commented on May 20, 2015

    @ewinslow

    Thanks for working on this, Misko! This is really the first developer-happiness-related issue I noticed when I tried out the dev preview, so glad to see it is being addressed and thought about. I like the idea of being able to declare schemas. Do we also need to be able to declare exposed events for the same reasons given?

    There are a few more magic symbols introduced here which makes me a bit nervous. Can we try to avoid adding more symbols to the API? I'm speaking here of @ for "bind to attribute" and !extends. Symbols are asking to become "Angular WAT" material for sure...

    I'd also love to encourage more user-centered error messaging, if at all possible. The current error messages are better than nothing, but otherwise meaningless to me as a humble developer (you might also have some typos? If so, that's not helping either). What I'm looking for is something more straightforward like:

    You wrote *ng-for="item in items", did you mean *ng-for="#item of items"?

    I realize that guessing developer intent is a bit hard to do in the general case, and I apologize for not having a ready suggestion to that end, but I suspect forgetting to use # or var to declare variables is going to be a rather common issue, so it'd be great to get the most helpful messages we can protecting developers against that pitfall.

  3. modified the milestone: on May 29, 2015
  4. vicb commented on Jun 2, 2015

    @vicb
    Contributor

    @naomiblack Have you unassigned me by error or is someone else working on this ?

  5. assigned and unassigned on Jun 2, 2015
  6. 39 remaining items

  7. modified the milestones: alpha-32, alpha-33 on Jul 23, 2015
  8. pkozlowski-opensource commented on Jul 28, 2015

    @pkozlowski-opensource
    Member

    I'm almost here, working on plugging the registry into the whole system. Not sure if we will be able to land #3225 today.

    @mhevery @tbosch could we have a quick chat today about steps to make it fully work for Dart?

  9. pkozlowski-opensource commented on Jul 29, 2015

    @pkozlowski-opensource
    Member

    @mhevery so, we've got already functionality for detecting missing bindings and the initial schema support landed via d894aa9.

    I think that it is time to replace this big issue with smaller, more-focused ones:

    • handling custom elements
    • events
    • attributes
    • hand-written schema for Dart
    • ...?

    I can propose / open those issues and run them through you.

  10. pkozlowski-opensource commented on Jul 31, 2015

    @pkozlowski-opensource
    Member

    @mhevery With basic schema support done in d894aa9 I've opened smaller and focused issues to add missing pieces of elements schema support:

    Closing this one in favor of the newly opened issues, would be great if you could triage those to prioritize work on next steps.

  11. angular-automatic-lock-bot commented on Sep 6, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  12. locked and limited conversation to collaborators on Sep 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions