trotyl / ng-vdom Goto Github PK
View Code? Open in Web Editor NEW(Developer Preview) A virtual-DOM extension for Angular, also work as React bridge.
(Developer Preview) A virtual-DOM extension for Angular, also work as React bridge.
Only onEventName
and on_eventName
being supported, resulting in listener to eventName
.
Support on-eventName
as well which conforms to Angular template syntax.
children
always be an Array
of renderable nodes.
undefined
when having no nodes;RNode
when having single node;RNode[]
when having more than two nodes;The entire style
property are reassigned on DOM element when patching.
Only apply changed style.
Integrate Directive
s with render
function.
function directive(type: Type<any>): (value: any, extras?: object) => never
type
: the directive class;value
: main input value for directive;extras
: additional input key value pairs in object;import { NgClass } from '@angular/common'
import { NgModel } from '@angular/forms'
import { directive, Renderable } from 'ng-renderable'
const ngClass = directive(NgClass)
const ngModel = directive(NgModel)
@Component()
class MyComponent extends Renderable {
@Input() active: boolean
value: string
render() {
const classNames = { highlight: this.active }
return (
<p ngClass={ ngClass(classNames) }>
<input ngModel={ ngModel(this.value, { ngModelOptions: { /* ... */ } }) } onNgModelChange={ (value) => this.value = value } />
</p>
)
}
}
All children are projected to default slot.
<p>Start</p>
<ng-content select="p"></ng-content>
<p>Middle</p>
<ng-content select="div"></ng-content>
<p>End</p>
Can be used with:
function render() {
return (
<MyComp>
<p>Foo</p>
<p ngProjectAs="div">Bar</p>
</MyComp>
)
}
Note:
Circular dependencies between instruction files (no problem, but got warning in building).
No circular dependencies.
@Component({
template: `
<ng-template #myTemplate let-name>
<p>Hello {{name}}!</p>
</ng-template>
`
})
class MyComp extends Renderable {
@Input() name: string
@ViewChild('myTemplate') myTemplate: TemplateRef<{ name: string }>
render() {
const MyTemplate = this.myTemplate
return (
<MyTemplate name={this.name} />
)
}
}
With helper directive:
import { RenderDef } from 'ng-render'
@Component({
template: `
<p *rnDef>Hello {{name}}!</p>
`
})
class MyComp extends Renderable {
@Input() name: string
@ViewChild(RenderDef) rnDef: RenderDef<{ name: string }>
render() {
const MyTemplate = this.rnDef.template
return (
<MyTemplate name={this.name} />
)
}
}
Support render
function returning Array
.
Angular component always contains a host element, and Renderable
always render content in child position.
Provide an option to render content in sibling position:
import { Renderable } from 'ng-renderable'
@Component({
selector: 'my-comp'
})
class MyComponent extends Renderable {
constructor(injector: Injector) {
super(injector, { sibling: true })
}
render() {
return <p>42</p>
}
}
Resulting to:
<my-comp></my-comp>
<p>42</p>
@Component({
template: `
<render-outlet [def]="myDef"></render-outlet>
`
})
class MyComp {
myDef = <div className="foo">Foo</div>
}
@Component({
template: `
<render-outlet [type]="myType" [props]="{ className: 'foo' }">
Foo
</render-outlet>
`
})
class MyComp {
myType = 'div'
}
Integrate Pipe
s with render
function.
function pipe(type: Type<any>): (value: any, ...extras: any[]) => never
type
: the pipe class;value
: the value passed to pipe;extras
: additional parameters passed to pipe;import { AsyncPipe, DatePipe } from '@angular/common'
import { pipe, Renderable } from 'ng-renderable'
const async = pipe(AsyncPipe)
const date = pipe(DatePipe)
@Component()
class MyComponent extends Renderable {
@Input() title: Observable<string>
@Input() date: Date
render() {
return (
<p title={ async(this.title) }>
{ date(this.date, 'fullDate') }
</p>
)
}
}
() => <p attr-foo={bar} />
Should be equivalent to:
<p [attr.foo]="bar"></p>
() => <p style-background-color={foo} style-font-size-px={bar}>
Should be equivalent to:
<p [style.background-color]="foo" [style.font-size.px]="bar">
Note: %
is not valid in JSXAttributeName
.
() => <p class-foo={x > 0} />
Should be equivalent to:
<p [class.foo]="x > 0"></p>
All nested Array
s are flattened to children, would cause problem when having same key
among different Array
s, also make diffing take more effort.
Each nested Array
should be diffed on its own.
Patching properties on DOM nodes.
Using WeakMap
instead.
@Component({
template: `
<ng-template #dateCell let-date="date">{{ date | date:'yyyyMMdd' }}</ng-template>
<bridged-comp [renderProp]="dateCell | renderable"></bridge-comp>
`
})
class MyComp {}
Corresponding util function:
import { asRenderable, Renderable } from 'ng-render'
@Component({
template: `
<ng-template #dateCell let-date="date">{{ date | date:'yyyyMMdd' }}</ng-template>
`
})
class MyComp extends Renderable {
@ViewChild('dateCell') dateCell: TemplateRef<{ date: Date }>
render() {
return (
<SomeComp renderProp={asRenderable(this.dateCell)}>
)
}
}
When not specifying key
, all children are tracked by non-keyed way (index of type).
Should be keyed by default, element without key should always be consider replaced.
VDOM
has severe problem in casing:
vdom/Vdom
: incorrect;vDom/VDom
: weird for consecutive upper case;VDOM/VDOM
: ugly;ng-render
provides a more meaningful concepts, which integrates Angular with render
function, also matches existing API:
import { Renderable } from 'ng-render'
@Component()
class MyComponent extends Renderable {
render() { /* ... */ }
}
Directives:
VOutlet(v-outlet)
-> RenderOutput(rn-outlet)
;One can only mount elements in existing Angular component.
Support global bootstrap without any Angular code, like:
import { createElement, render } from 'ng-renderable'
import 'ng-renderable/browser'
render(<p>Hello World!</p>, document.querySelector('#main'))
Note: the only dependency should be @angular/core
, not use @angular/platform-browser
.
When JSXAttributeName
contains non-alphabetic character, like:
() => <p data-foo={bar} aria-hidden />
Should be translated to HTML Attribute rather than DOM Property, like:
<p [attr.data-foo]="bar" [attr.aria-hidden]="true"></p>
import { Migration } from 'ng-renderable'
import { Calendar } from 'some-lib'
@Directive({
selector: 'my-calendar',
})
class CalendarComponent extends Migration<Calendar> {
@Input() set date(value: Date) { this.update({ value }) }
@Output() dateChange = this.observe(props => props.onChange)
constructor(injector: Injector) {
super(injector, Calendar)
}
}
Note: to remain compatible with closure-compiler, string literals cannot be used.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.