New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request full support for the Web Components Custom Elements spec in version 1.7 #16428

Closed
raviolibhat opened this Issue Jan 30, 2018 · 9 comments

Comments

Projects
None yet
7 participants
@raviolibhat

raviolibhat commented Jan 30, 2018

I'm submitting a ...

  • bug report
  • feature request
  • other

Current behavior:
Web Components aim to be a standards based web framework for browsers very soon. The Custom Elements spec within it is crucial. From Custom Elements Everywhere one can see that AngularJS 1.6 passes all basic tests but none of the advanced tests. This feature request is to provide full support in version 1.7 and pass the advanced tests as well.

Expected / new behavior:
Long term support for 1.7 has been announced to extend for three years. Hence a goal in this request is to make the transition from AngularJS 1.7 to Web Components directly possible, instead of an intermediate step to another framework.

Minimal reproduction of the problem with instructions:

AngularJS version: 1.7.0

Browser: [all]

Anything else:

@Narretz

This comment has been minimized.

Contributor

Narretz commented Jan 31, 2018

This would be quite a complex task at this point, because AngularJS misses the possibility to bind to arbitrary attributes / listen to arbitrary events, see https://custom-elements-everywhere.com/

I think @gkalpak knows more about this.

@Narretz Narretz added this to the Ice Box milestone Jan 31, 2018

@gkalpak

This comment has been minimized.

Member

gkalpak commented Jan 31, 2018

It is definitely an interesting feature to consider. I don't think it would be too complicated (I expect most complications to arise around sanitization - if we choose to have it 😉).

It is worth investigating more imo.

BTW, you can implement two basic (somewhat hacky) directives to handle the missing features for you (with somewhat awkward syntax). Basically, you need a way to declaratively bind to arbitrary properties:

// Usage:
// ```html
// <!-- Bind `$ctrl.bar` to the `foo` property of `<my-element>`. -->
// <my-element ng-prop="foo->$ctrl.bar">
//
// <!-- Bind multiple to properties. -->
// <my-element ng-prop="foo->$ctrl.bar|||baz->$ctrl.qux+'xyz'">
// ```
.directive('ngProp', function ngPropDirective() {
  // Post-link
  return (scope, elem, attrs) => {
    attrs.ngProp.
      split('|||').
      map(x => /^(.+?)->(.+)$/.exec(x).slice(1)).
      forEach(([propName, exp]) => {
        const watchListener = newValue => elem[0][propName] = newValue;
        scope.$watch(exp, watchListener);
      });
  };
}

Then, you also need a way to declaratively listen to arbitrary events:

// Usage:
// ```html
// <!-- Listen to `foo` event and call `$ctrl.onFoo()`. -->
// <my-element ng-on="foo->$ctrl.bar()">
//
// <!-- Pass the event object to the listener. -->
// <my-element ng-on="foo->$ctrl.bar($event)">
//
// <!-- Listen to multiple events. -->
// <my-element ng-on="foo->$ctrl.bar()|||baz->$ctrl.qux = $ctrl.qux + 1">
// ```
.directive('ngOn', function ngOnDirective($parse) {
  // Post-link
  return (scope, elem, attrs) => {
    attrs.ngOn.
      split('|||').
      map(x => /^(.+?)->(.+)$/.exec(x).slice(1)).
      forEach(([eventName, exp]) => {
        const parsedExp = $parse(exp);
        const listener = $event => scope.$apply(() => parsedExp(scope, {$event}));
        elem.on(eventName, listener);
      });
  };
}

Here is a demo.

@mattdsteele

This comment has been minimized.

mattdsteele commented Feb 1, 2018

For reference, the other library I've used to do arbitrary prop bindings: https://github.com/robdodson/angular-custom-elements

@gkalpak gkalpak modified the milestones: Ice Box, 1.7.x, 1.6.x Feb 1, 2018

@peterblazejewicz

This comment has been minimized.

peterblazejewicz commented Feb 18, 2018

Hi folks,
I think, if it is added in 1.7 it will help to migrate core features of existing apps into platform/library agnostic, standard compliant solution. I could imagine of porting part of UI into custom elements and later use them in any other application.
Thanks!

@Narretz Narretz modified the milestones: 1.6.x, 1.7.x Apr 12, 2018

@gkalpak gkalpak self-assigned this May 9, 2018

@Narretz Narretz self-assigned this May 23, 2018

@Narretz

This comment has been minimized.

Contributor

Narretz commented May 23, 2018

Notes:

  • we can add this to the compiler - the cost shouldn't be too high, but we could always put this feature behind a flag
  • Angular sets a security context to specifc properties like innerHTML and sanitizes the input (something with a schemer)
@benoitjchevalier

This comment has been minimized.

benoitjchevalier commented May 24, 2018

Is there any chance this will make it onto LTS?

@gkalpak

This comment has been minimized.

Member

gkalpak commented May 24, 2018

We would very much like it to make it. But given there is only one month left for feature development, we can't make any promises.
If anyone from the community wants to take a stub at it, that would be 👌

@gkalpak

This comment has been minimized.

Member

gkalpak commented May 30, 2018

BTW, this is the schema used by Angular to assign security contexts to different elements: dom_security_schema.ts

@gkalpak

This comment has been minimized.

Member

gkalpak commented Jun 1, 2018

BTW2, if we implement this (i.e. ng-bind and ng-on), then it would fairly straightforward to also implement ng-bindon (#15464) 😁

*: Names are debateable 😛

@jbedard jbedard self-assigned this Jun 11, 2018

jbedard added a commit to jbedard/angular.js that referenced this issue Jun 26, 2018

Narretz added a commit to Narretz/angular.js that referenced this issue Jul 12, 2018

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 25, 2018

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 30, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as `my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM properties. For example `ng-prop-foo=”x”` will assign the value of the expression `x` to the `foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using such as `ng-click`, `ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example `ng-on-bar=”barOccured($event)”` will add a listener to the “bar” event and invoke the `barOccured($event)` expression.

For properties or events using mixed case underscores can be used before capital letters. For example `ng-prop-my_prop="x"` will bind `x` to the `myProp` property, and `ng-on-my_custom_event="x()"` will invoke `x()` on the `myCustomEvent` event.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 30, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo=”x”` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using such as `ng-click`, `ng-blur` etc.
`ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar=”barOccured($event)”` will add a listener to the “bar” event and invoke the
`barOccured($event)` expression.

For properties or events using mixed case underscores can be used before capital letters. For
example `ng-prop-my_prop="x"` will bind `x` to the `myProp` property, and
`ng-on-my_custom_event="x()"` will invoke `x()` on the `myCustomEvent` event.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 30, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo=”x”` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound such as `ng-click`, `ng-blur` etc.
`ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar=”barOccured($event)”` will add a listener to the “bar” event and invoke the
`barOccured($event)` expression.

For properties or events using mixed case, underscores can be used before capital letters. For
example `ng-prop-my_prop="x"` will bind `x` to the `myProp` property, and
`ng-on-my_custom_event="x()"` will invoke `x()` on the `myCustomEvent` event.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 30, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo=”x”` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using directives such as `ng-click`,
`ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar=”barOccured($event)”` will add a listener to the “bar” event and invoke the
`barOccured($event)` expression.

For properties or events using mixed case, underscores can be used before capital letters. For
example `ng-prop-my_prop="x"` will bind `x` to the `myProp` property, and
`ng-on-my_custom_event="x()"` will invoke `x()` on the `myCustomEvent` event.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 31, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo="x"` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using directives such as `ng-click`,
`ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar="barOccured($event)"` will add a listener to the “bar" event and invoke the
`barOccured($event)` expression.

Since HTML attributes are case-insensitive, property and event names are specified in snake_case
for `ng-prop-*` and `ng-on-*`. For example, to bind property `fooBar` use `ng-prop-foo_bar`, to
listen to event `fooBar` use `ng-on-foo_bar`.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

jbedard added a commit to jbedard/angular.js that referenced this issue Jul 31, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo="x"` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using directives such as `ng-click`,
`ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar="barOccured($event)"` will add a listener to the "bar" event and invoke the
`barOccured($event)` expression.

Since HTML attributes are case-insensitive, property and event names are specified in snake_case
for `ng-prop-*` and `ng-on-*`. For example, to bind property `fooBar` use `ng-prop-foo_bar`, to
listen to event `fooBar` use `ng-on-foo_bar`.

Fixes angular#16428
Fixes angular#16235
Closes angular#16614

@jbedard jbedard closed this in dedb10c Aug 2, 2018

Narretz added a commit that referenced this issue Aug 3, 2018

feat($compile): add support for arbitrary DOM property and event bind…
…ings

Properties:

Previously only arbitrary DOM attribute bindings were supported via interpolation such as
`my-attribute="{{expression}}"` or `ng-attr-my-attribute="{{expression}}"`, and only a set of
distinct properties could be bound. `ng-prop-*` adds support for binding expressions to any DOM
properties. For example `ng-prop-foo="x"` will assign the value of the expression `x` to the
`foo` property, and re-assign whenever the expression `x` changes.

Events:

Previously only a distinct set of DOM events could be bound using directives such as `ng-click`,
`ng-blur` etc. `ng-on-*` adds support for binding expressions to any DOM event. For example
`ng-on-bar="barOccured($event)"` will add a listener to the "bar" event and invoke the
`barOccured($event)` expression.

Since HTML attributes are case-insensitive, property and event names are specified in snake_case
for `ng-prop-*` and `ng-on-*`. For example, to bind property `fooBar` use `ng-prop-foo_bar`, to
listen to event `fooBar` use `ng-on-foo_bar`.

Fixes #16428
Fixes #16235
Closes #16614
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment