Skip to content
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

Components with imperative views #1088

Closed
mhevery opened this issue Mar 25, 2015 · 12 comments
Closed

Components with imperative views #1088

mhevery opened this issue Mar 25, 2015 · 12 comments
Assignees

Comments

@mhevery
Copy link
Contributor

mhevery commented Mar 25, 2015

A component which is responsible for rendering its own shadow DOM rather then loading it from template.

The mental model is that this is a component, but because it does not have a @Template it is responsible for rendering its own content. To reproject the light DOM it can add <content> tag. The component can inject DocumentFragment to do its own DOM manipulation. (WebWorkers, will be addressed seperatly).

Single Thread Model

  • Participates in full DI just like @Component
  • Can inject special ContentDom abstraction, described later.
@Component({
  selector: 'line-chart',
  bind: {
    'data': 'data'
  }
})
@View({
  directive: [DependentComponent],
  renderer: 'imperative'
})
class LineChart {
  constructor(dom:ComponentDom) {
    dom.root; // Is root of the shadow DOM. It is a real DOM Node
    dom.root.innerHTML = '<div style="border: 1px solid red;"></div>
    var div = dom.root.firstChild;
    var content = dom.createContent(); // Must use this API to create '<content>'
    content.append(div); // project will works as expected.
  }
}

ComponentDom Abstraction

Because Angular runs in both Emulated and Native Shadow DOM mode, it is important that we abstract the API for shadow DOM so that Angular's emulation mode will know when and which nodes to redistribute.

// DOM that contain Component and <content> tags.
class ComponentDom {
  // Any DOM manipulation will show up in the right place.
  root:Node;

  component:ComponentRef;
  redistribute();

  createContent(selector:string):Content;
  // Only types which are declared in the @View.directives can be used here.
  createComponent(type:Type, node:Node):ComponentDom;  
}

class Content {
  destroy();
  // order of insertions must match the order of creation
  // each Content tag must be inserted at the logical location where created.
  insertBefore(node:Node);
  append(parentNode:Node);
}

WebWorkers Model

See #1207

@mhevery mhevery added this to the M7: GT Customer milestone Mar 25, 2015
@matanlurey
Copy link
Contributor

Can you give an example of what the API for moving child elements would look like?

@jelbourn
Copy link
Member

  • When you say "child elements can be moved to simulate reprojection", do you mean support projection to <content> tags?
  • Will these components be able to receive injection (both element and app services)?
  • Does data-binding within the component work normally in the NativeComponent leaf?

@yjbanov
Copy link
Contributor

yjbanov commented Mar 25, 2015

This sounds like what @tbosch and I have been calling "render directive". I think directives that access platform-specific APIs should not participate in data binding, DI, the view hierarchy, or anything else that lives in the "application layer". According to the new rendering architecture such directives would live in the render layer. The API available to this type of directive should be sufficient to implement:

  • Binding data to native properties such as classList, style, attributes
  • Binding data to web components (this alone would already enable svg, canvas, webgl)
  • Implement animations
  • Implement overlays

@jelbourn
Copy link
Member

If this type of directive does not participate in DI, you lose the ability to make a directive that uses something like canvas and consumes both built-in and your own defined services.

@yjbanov are you suggesting that a directive that uses canvas wouldn't be able to define custom property bindings?

@jelbourn
Copy link
Member

Here's a use case that might inform this:

In Material 1, we have a directive called md-icon. This directive lets the user load an SVG icon either directly by URL or by an alias. The alias is what we're concerned with here. The icons are configured with a provider:

  $mdIconProvider
       .defaultIconSet('my/app/icons.svg')       // Register a default set of SVG icons
       .iconSet('social', 'my/app/social.svg')   // Register a named icon set of SVGs
       .icon('android', 'my/app/android.svg')    // Register a specific icon (by name)
       .icon('work:chair', 'my/app/chair.svg');  // Register icon in a specific set

and then referenced by name:

<md-icon md-svg-icon="info"></md-icon>
<md-icon md-svg-icon="social:cake"></md-icon>

In Angular two, the analog to this provider would be creating a service at the root level "app" component. The directive would need to consume this service to look up the SVG content by name, and then append the content into its DOM. The specific icon set to the directive could also be determined by some binding.

@yjbanov
Copy link
Contributor

yjbanov commented Mar 26, 2015

@jelbourn While render directives do not participate in DI, you can still data-bind to them. In your example md-icon would be a normal component that participates in the DI. So the user of md-icon can still do:

<md-icon md-svg-icon="info"></md-icon>

However, internally, it would use a render directive and pass data to it, e.g. this way:

<div [svg]="svgData">
  <!-- here be SVG drawn by "svg" render directive -->
</div>

Here [svg]="svgData" binds SVG data (or any custom data) to an svg render directive.

@naomiblack naomiblack assigned yjbanov and unassigned vsavkin Mar 30, 2015
@mhevery
Copy link
Contributor Author

mhevery commented Apr 2, 2015

/everyone, I have update the bug description, please take a look.

@yjbanov
Copy link
Contributor

yjbanov commented Apr 8, 2015

@mhevery, I moved this back to M7 because this is blocking cubicle table migration.

@mhevery mhevery assigned tbosch and unassigned yjbanov Apr 9, 2015
@mhevery mhevery added the ♥ GT label Apr 9, 2015
@tbosch
Copy link
Contributor

tbosch commented Apr 21, 2015

Implemented basic feature to update the DOM via DirectDomRenderer.setImperativeComponentRootNodes() and load Angular components into an imperative view via DynamicComponentLoader.loadIntoNewLocation (see ada1e64).

Note that the internal name is "Component with an imperative View", not "Native Component".

@tbosch
Copy link
Contributor

tbosch commented Apr 21, 2015

Missing:

  • Provide access to light dom / shadow dom emulation

@tbosch tbosch changed the title NativeComponent Components with imperative views Apr 21, 2015
@mhevery
Copy link
Contributor Author

mhevery commented Apr 21, 2015

#1481

@mhevery mhevery closed this as completed Apr 21, 2015
@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants