diff --git a/index.tsx b/index.tsx index 51460e7..c189149 100644 --- a/index.tsx +++ b/index.tsx @@ -17,7 +17,8 @@ import { render, unmountComponentAtNode } from 'react-dom' */ export function react2angular( Class: React.ComponentClass | React.SFC, - bindingNames?: (keyof Props)[] + bindingNames: (keyof Props)[] | null = null, + injectNames: string[] = [] ): IComponentOptions { const names = bindingNames || (Class.propTypes && Object.keys(Class.propTypes)) @@ -25,13 +26,18 @@ export function react2angular( return { bindings: fromPairs(names.map(_ => [_, '<'])), - controller: ['$element', class extends NgComponent { - constructor(private $element: IAugmentedJQuery) { + controller: ['$element', ...injectNames, class extends NgComponent { + injectedProps: { [name: string]: any } + constructor(private $element: IAugmentedJQuery, ...injectedProps: any[]) { super() + this.injectedProps = {} + injectNames.forEach((name, i) => { + this.injectedProps[name] = injectedProps[i] + }) } render() { // TODO: rm any when https://github.com/Microsoft/TypeScript/pull/13288 is merged - render(, this.$element[0]) + render(, this.$element[0]) } componentWillUnmount() { unmountComponentAtNode(this.$element[0]) diff --git a/test.tsx b/test.tsx index 7c30655..88321ec 100644 --- a/test.tsx +++ b/test.tsx @@ -1,6 +1,6 @@ import { bootstrap, element as $, ICompileService, mock, module } from 'angular' import 'angular-mocks' -import { $rootScope } from 'ngimport' +import { $rootScope, $http } from 'ngimport' import * as React from 'react' import * as PropTypes from 'prop-types' import { Simulate } from 'react-dom/test-utils' @@ -53,16 +53,70 @@ class TestFive extends React.Component { componentWillUnmount() { } } +class TestSixService { + constructor(private $q: any) {} + + foo() { + return this.$q.resolve('testSixService result') + } +} + +class TestSix extends React.Component { + state = { + $http: '', + $element: '', + testSixService: '', + } + + render() { + return
+

{this.state.$http}

+

{this.state.$element}

+

{this.state.testSixService}

+

{this.props.foo}

+ $element result +
+ } + + componentDidMount() { + this.props.$http.get('https://example.com/').then((result: string) => { + this.setState({ $http: result }) + }) + this.setState({ + $element: this.props.$element.find('span').text(), + }) + this.props.testSixService.foo().then((result: string) => { + this.setState({ testSixService: result }) + }) + } +} + +class TestSeven extends React.Component { + static propTypes = { + foo: PropTypes.string.isRequired + } + + render() { + return

{this.props.foo}

+ } +} + const TestAngularOne = react2angular(TestOne, ['foo', 'bar', 'baz']) const TestAngularTwo = react2angular(TestTwo, ['foo', 'bar', 'baz']) const TestAngularThree = react2angular(TestThree) const TestAngularFour = react2angular(TestFour) +const TestAngularSix = react2angular(TestSix, ['foo'], ['$http', '$element', 'testSixService', 'foo']) +const TestAngularSeven = react2angular(TestSeven, null, ['foo']) module('test', ['bcherny/ngimport']) .component('testAngularOne', TestAngularOne) .component('testAngularTwo', TestAngularTwo) .component('testAngularThree', TestAngularThree) .component('testAngularFour', TestAngularFour) + .service('testSixService', ['$q', TestSixService]) + .constant('foo', 'CONSTANT FOO') + .component('testAngularSix', TestAngularSix) + .component('testAngularSeven', TestAngularSeven) bootstrap($(), ['test'], { strictDi: true }) @@ -115,6 +169,18 @@ describe('react2angular', () => { it('should have empty bindings when parameter is not passed', () => { expect(react2angular(TestThree).bindings).toEqual({}) }) + + it('should use the injectNames for DI', () => { + const defaultDi = (react2angular(TestThree).controller as any).slice(0, -1) + const injectedDi = (react2angular(TestThree, null, ['foo', 'bar']).controller as any).slice(0, -1) + expect(injectedDi).toEqual(defaultDi.concat(['foo', 'bar'])) + }) + + it('should have default DI specifications if injectNames is empty', () => { + const defaultDi = (react2angular(TestThree).controller as any).slice(0, -1) + const injectedDi = (react2angular(TestThree, null, []).controller as any).slice(0, -1) + expect(injectedDi).toEqual(defaultDi) + }) }) describe('react classes', () => { @@ -196,6 +262,33 @@ describe('react2angular', () => { expect(element.find('span').length).toBe(0) }) + it('should take injected props', (done) => { + spyOn($http, 'get').and.returnValue(Promise.resolve('$http response')) + const scope = Object.assign($rootScope.$new(true), { + foo: 'FOO', + }) + + const element1 = $(``) + $compile(element1)(scope) + + const element2 = $(``) + $compile(element2)(scope) + + $rootScope.$apply() + + setTimeout(() => { + expect($http.get).toHaveBeenCalledWith('https://example.com/') + expect(element1.find('p').eq(0).text()).toBe('$http response', '$http is injected') + expect(element1.find('p').eq(1).text()).toBe('$element result', '$element is injected') + expect(element1.find('p').eq(2).text()).toBe('testSixService result', 'testSixService is injected') + expect(element1.find('p').eq(3).text()).toBe('FOO', 'bindingNames overrides injectedProps') + + expect(element2.find('p').text()).toBe('FOO', 'propTypes overrides injectedProps') + + done() + }, 0) + }) + }) describe('react stateless components', () => {