GithubHelp home page GithubHelp logo

microsoft / angular-react Goto Github PK

View Code? Open in Web Editor NEW
543.0 24.0 71.0 13.36 MB

Use React components inside Angular

Home Page: https://microsoft.github.io/angular-react/

License: MIT License

JavaScript 0.35% HTML 6.59% CSS 0.12% TypeScript 91.15% SCSS 1.79%
office-ui-fabric angular react

angular-react's Introduction

React support for Angular

CircleCI

Industry trends, organizational pressures, and other factors can lead to mandates regarding the use of component libraries or migration from one technology to another. In the case of Office UI Fabric, where its use is required, the client must be written in React (there is no Angular component library for the latest version). Rewrite from Angular to React may be cost-prohibitive or ill advised for other reasons.

Use of Angular-React allows consuming any React elements, but specifically Office UI Fabric, within an Angular [2+] application. The library of wrappers for Office UI Fabric simplifies the use of these components with Angular. However, any React code can make use of the custom Angular-React renderer.

Libraries

@angular-react contains two separate libraries:

  • core: npm version

    Includes the Renderer and supporting logic to render Angular components with React implementations as React components.

  • fabric: npm version

    The light-weight Angular component wrappers that expose the Fabric React component API through common Angular components (including both imperative AND declarative syntax in many cases).

Quick links

Documentation, quick start, and guides | Demo | Contributing | StackBlitz Template | Office UI Fabric

Typical Use Cases

  • Use React component libraries with Angular
  • Incrementally rewrite an Angular application into React (moving from atomic/leaf nodes upward into full features/pages until the entire app is re-written)

Getting started

See a simple StackBlitz Template

Roadmap & Support

Both the core and fabric libraries are in production use in consumer-facing applications at Microsoft. That said, we (the team that currently maintains this project) are a product team, and @angular-react is not our primary focus. We maintain this because we need it and we share it with the wider community with the hope that it will prove useful to others. Of course, we attempt to provide help when possible and we love getting pull requests for improvements/enhancement/fixes from community members. But we don't have any specific plans for the future of this project.

Please take this in to consideration when evaluating this project's suitability for your own needs.

Contributing

If you'd like to contribute, you must follow our contributing guidelines. You can look through the issues (which should be up-to-date on who is working on which features and which pieces are blocked) and make a comment.

angular-react's People

Contributors

aarongreenwald avatar angular-cli avatar benfeely avatar bengry avatar benjamingr avatar dependabot[bot] avatar dorgold avatar eswarpr avatar galvanms avatar kant avatar krdeal avatar microsoft-github-policy-service[bot] avatar mrfrankel avatar nathanwalker avatar noanutke avatar pdong avatar reshaw avatar shairose avatar xjerwa avatar yanivc-ms avatar zavidor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-react's Issues

Dropdown list opens a dialog container

Hi,

Thanks for the repository that allows my angular app to use fabric components in react :). Most of components work very well in my project except the issue below:

I followed the same set up from demo app, and put following component into my app component

<fab-dropdown
  contentStyle="width: 300px;"
  [placeholder]="'Select one'"
  [defaultSelectedKey]="'A'"
  (onChange)="logEvent('dropdown change', $event)"
>
  <options>
    <fab-dropdown-option optionKey="A" text="See option A"></fab-dropdown-option>
    <fab-dropdown-option optionKey="B" text="See option B"></fab-dropdown-option>
  </options>
</fab-dropdown>

However, what I got is a dropdown list that occupies the majority of the page:

Screenshot from 2019-10-30 16-55-12

And when I inspected the dropdown list dom and compared it with the correct dropdown in demo app, the difference is:

In my project, parent div is

<div role="dialog" aria-modal="true" class="hiddenPanel-71" style="outline: none;">

However in demo app it renders as:

<div class="ms-Callout-container container-288">

This issue happens when load the app into outlook add-in. Dropdown list in the same code works very well in web page.

Can we get the 3.x version to work with Angular 10 ?

Hello Team - We are using this library successfully in our project which is using Angular8. Now we have a need to migrate to Angular10 because we want to leverage some other nugget packages that require Angular10 as minimum.

Unfortunately I could not get this library to work with Angular10 and I am battling this for quite a few days. Here is the relevant package.json file configuration.

"dependencies": {
    "@angular-react/core": "3.0.0",
    "@angular-react/fabric": "3.0.0",
    "@angular/animations": "^10.2.5",
    "@angular/cdk": "^7.3.7",
    "@angular/common": "10.2.5",
    "@angular/compiler": "10.2.5",
    "@angular/core": "10.2.5",
    "@angular/forms": "10.2.5",
    "@angular/material": "^7.3.7",
    "@angular/platform-browser": "10.2.5",
    "@angular/platform-browser-dynamic": "10.2.5",
    "@angular/router": "10.2.5",
    "@angular/upgrade": "10.2.5",
    "@microsoft/applicationinsights-web": "^2.5.4",
    "@ng-select/ng-select": "^5.0.15",
    "@types/highcharts": "^7.0.0",
    "@types/react": "~16.8.6",
    "@types/react-dom": "^16.8.6",
    "@uifabric/azure-themes": "7.3.0",
    "adal-angular4": "^3.0.16",
    "admin-lte": "^2.4.3",
    "angular-split-ng6": "^1.0.0-rc.5",
    "bootstrap": "^3.4.1",
    "classnames": "^2.3.1",
    "copy-html-to-clipboard": "^4.0.1",
    "core-js": "^3.6.5",
    "css-to-style": "^1.4.0",
    "font-awesome": "^4.7.0",
    "hammerjs": "^2.0.8",
    "highcharts": "^8.1.2",
    "highcharts-angular": "^2.4.0",
    "highcharts-custom-events": "^3.0.9",
    "ie-shim": "^0.1.0",
    "jquery": "^3.4.1",
    "moment": "^2.22.1",
    "monaco-languageclient": "^0.13.0",
    "office-ui-fabric-core": "11.0.0",
    "office-ui-fabric-react": "7.132.0",
    "pdfmake": "^0.1.72",
    "react": "^16.8.0",
    "react-dom": "^16.8.0",
    "reconnecting-websocket": "^4.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "6.6.7",
    "rxjs-compat": "6.2.2",
    "sass": "^1.54.4",
    "stylenames": "^1.1.6",
    "tslib": "^2.0.0",
    "ua-parser-js": "^0.7.19",
    "vis": "^4.21.0",
    "vscode-ws-jsonrpc": "^0.2.0",
    "web-animations-js": "^2.3.2",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular-builders/custom-webpack": "8.0.2",
    "@angular-devkit/build-angular": "~0.1002.4",
    "@angular-devkit/build-ng-packagr": "~0.1002.4",
    "@angular-devkit/build-optimizer": "~0.800.3",
    "@angular/cli": "10.2.4",
    "@angular/compiler-cli": "10.2.5",
    "@angular/language-service": "^10.2.5",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "^12.11.1",
    "@types/ua-parser-js": "^0.7.32",
    "@types/vscode": "1.67.0",
    "awesome-typescript-loader": "^2.2.1",
    "codelyzer": "^5.1.2",
    "concurrently": "^4.1.0",
    "jasmine": "^3.0.0",
    "jasmine-core": "~3.5.0",
    "karma": "~5.0.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "ng-packagr": "^10.1.0",
    "protractor": "~7.0.0",
    "rxjs-tslint": "^0.1.3",
    "selfsigned": "^1.10.2",
    "ts-node": "~4.1.0",
    "tslint": "~6.1.0",
    "typescript": "~4.0.8",
    "webpack-bundle-analyzer": "^3.6.0"
  }

May I know the right combination of the libraries to use to make it work with Angular10?

This is the error I get when I try to run with Angular10

TypeError: Cannot read properties of undefined (reading 'nativeElement')    
at FabPrimaryButtonComponent.set (https://localhost:3000/vendor.js:240061:41)    
at Object.ngOnChangesSetInput [as setInput] (https://localhost:3000/vendor.js:116112:25)    
at setInputsFromAttrs (https://localhost:3000/vendor.js:123461:13)    
at instantiateAllDirectives (https://localhost:3000/vendor.js:123199:7)    
at createDirectivesInstances (https://localhost:3000/vendor.js:122484:3)    
at Module.ɵɵelementStart (https://localhost:3000/vendor.js:131388:5)   
 at FabricFeedbackComponent_Template (https://localhost:3000/main.js:75213:73)    
at executeTemplate (https://localhost:3000/vendor.js:122452:5)    
at renderView (https://localhost:3000/vendor.js:122189:7)    
at renderComponent (https://localhost:3000/vendor.js:123684:3)    
at renderChildComponents (https://localhost:3000/vendor.js:122043:5)   
 at renderView (https://localhost:3000/vendor.js:122223:7)    
at renderComponent (https://localhost:3000/vendor.js:123684:3)    
at renderChildComponents (https://localhost:3000/vendor.js:122043:5)    
at renderView (https://localhost:3000/vendor.js:122223:7)]

This is the line of code from the browser tools window.

image

Components with Angular content in them don't render the content in production build

For component that accept <ng-content>, when running in production (ng build --prod), the content doesn't show up.
Seems to be related to having buildOptimizer: true in angular.json, running with --aot (but without --prod) works fine.

Reproduction steps:

  1. Clone https://github.com/bengry/angular-react-content-bug-repro
  2. npm install
  3. ng serve --prod
  4. You should see a text in the message bar. Actual result - the message bar is empty.

Issue seems to be related to the cause of #8 - where the Angular CLI/WebPack's tree shaking removes actual code that's being executed.

Create a generic wrapper component

Explore the option of creating a simple generic wrapper components, similar in nature to what projects like react2angular offer (but for Angular 2+), to allow easier usage of React components within Angular. These components would not enjoy the benefit of having a more Angular-y API when exposed to apps, but may be sufficient for some use-cases.

Prior art

Affected packages

  • @angular-react/core - or possibly creating a new package for this - @angular-react/generic?

Getting error reactNodeRef must hold a reference to a ReactNode. unclear why

I'm trying to wrap a slate editor by following the fabric examples. I can't seem to get a basic example working. I've set up a module like:

import { registerElement } from '@angular-react/core'
import { CommonModule } from '@angular/common'
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'
import { Editor } from 'slate-react'
import { SlateEditorComponent } from './slate-editor/slate-editor.component'

@NgModule({
  declarations: [SlateEditorComponent],
  imports: [CommonModule],
  exports: [SlateEditorComponent],
  schemas: [NO_ERRORS_SCHEMA],
})
export class SlateModule {
  constructor() {
    registerElement('Editor', () => Editor)
  }
}

and a simple component:

import { Value } from 'slate'
import { EditorProps } from 'slate-react'

@Component({
  selector: 'app-slate-editor',
  template: `
    <Editor #reactNode [value]="value" [Change]="onChange"></Editor>
  `,
  styles: ['react-renderer'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SlateEditorComponent extends ReactWrapperComponent<EditorProps> {
  @ViewChild('reactNode', { static: true }) protected reactNodeRef: ElementRef

  @Input() value: EditorProps['value'] = Value.fromJSON({
    document: {
      nodes: [
        {
          object: 'block',
          type: 'paragraph',
          nodes: [
            {
              object: 'text',
              text: 'A line of text in a paragraph.',
            },
          ],
        },
      ],
    },
  })

  @Input() onChange: EditorProps['onChange'] = ({ value }) => console.log(value)

  constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, renderer: Renderer2) {
    super(elementRef, changeDetectorRef, renderer)
  }
}

I've installed the following dependencies:

  "dependencies": {
    "@angular-react/core": "^1.0.1",
    "@angular/animations": "~8.0.3",
    "@angular/cdk": "^8.0.1",
    "@angular/common": "~8.0.3",
    "@angular/compiler": "~8.0.3",
    "@angular/core": "~8.0.3",
    "@angular/forms": "~8.0.3",
    "@angular/material-moment-adapter": "^8.0.1",
    "@angular/platform-browser": "~8.0.3",
    "@angular/platform-browser-dynamic": "~8.0.3",
    "@angular/router": "~8.0.3",
    "@types/slate-react": "^0.22.6",
    "@types/stylenames": "^1.1.0",
    "immutable": "^4.0.0-rc.12",
    "react": "^16.11.0",
    "react-dom": "^16.11.0",
    "rxjs": "~6.5.2",
    "slate": "^0.47.8",
    "slate-react": "^0.22.9",
    "tslib": "^1.9.0",
    "zone.js": "~0.9.1"
  },

I'm at a bit of a loss and would appreciate any guidance on what I'm doing wrong here.

React-wrapped components inside ng-template don't re-render on changes

When rendering a react-wrapper component (e.g. <fab-default-button>) as a render prop in another react component, the inner component is not re-rendered on changes.

More comprehensive example:

// app.component.html
<fab-command-bar>
    <items>
      <fab-command-bar-item key="custom">
        <render>
          <ng-template let-item="item">
            <counter></counter>
          </ng-template>
        </render>
    </items>
</fab-command-bar>
// counter.component.ts
@Component({
  selector: 'counter',
  template: `
    <fab-default-button [text]="count + '+'" (onClick)="onClick()"></fab-default-button>
    `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CounterComponent {
  count = 0;

  constructor(private readonly cd: ChangeDetectorRef) {}

  onClick() {
    this.count++;
    this.cd.detectChanges();
  }
}

When clicking the button, the text is not changed.

Support for ngModel and two way data binding

At present none of the input components support using ngModel to allow support for two way data binding and usage in forms within Angular applications. The proposal below attempts to address that:

New abstract base class for input components

I propose a simple abstract base class that all input components can derive from. It should provide the necessary plumbing to support NG_VALUE_ACCESSOR for individual input components, but should also allow sufficient amount of flexibility for individual input components to implement support for it. The proposed base class should be named FabInputComponent which inherits from ReactWrapperComponent

ngModel specific methods

The abstract base class will define 2 abstract methods: onModelValueChanged and onViewValueChanged which will allow inherited input component to react and respond to framework events pertaining to ngModel bindings. The input components will then implement their own logic to handle those events. For e.g. FabDropdownComponent will use these events to set it's internal selectedKey property as well as use the onViewValueChanged to provide feedback to the framework when a drop down option is selected by the user.

Current status

I have a blueprint of this implementation working in one of my fork branches. There is a case for this to be reviewed by the community since these are fundamental changes to some of the widely used components in the library.

Create kitchen sink

Currently when working on the @angular-react/fabric package (and also on the core one, but less-so), we constantly change the AppComponent in the demo app.

Ideally, we'd have some sort of playground for these sort of these (as a separate app or otherwise), and all components, with all usages would be available in a kitchen sink app, probably under the docs app.

This would allow easier testing of components, showcasing various things that they offer, in different syntaxes sometimes (e.g. the FabCommandBarComponent's both imperative and declarative syntax options for items (and farItems and overflowItems).

Cannot use *ngFor or *ngIf inside of <ng-content> inside of react components

Hello, and great library by the way! I've successfully created wrappers for my react components, but now I'm trying to generate a list of components with *ngFor which I can't seem to get working. If needed, I can make a plunker or other sample app; just let me know, thanks.

Example from /angular-react/blob/master/apps/demo/src/app/app.component.html

This doesn't work:

<fab-pivot>
    <fab-pivot-item *ngFor="let item of items" headerText="item.name">
         <div>{{item.content}}</div>
    </fab-pivot-item>
</fab-pivot>

This doesn't work:

<fab-pivot>
    <div *ngFor="let item of items">
        <fab-pivot-item headerText="item.name"> <div>{{item.content}}</div> </fab-pivot-item>
    </div>
</fab-pivot>

This works:

<fab-pivot>
    <fab-pivot-item headerText="Tab 1"> <div>Tab 1's content</div> </fab-pivot-item>
    <fab-pivot-item headerText="Tab 2"> <div>Tab 2's content</div> </fab-pivot-item>
    <fab-pivot-item headerText="Tab 3"> <div>Tab 3's content</div> </fab-pivot-item>
</fab-pivot>

Attribute validation can break the app if plugins have mutated the DOM

Inside _passAttributesAsProps() there is a check to ensure that the DOM node that is being updated does not have style, class or key attributes. This code will throw if any of these attributes are found.

This assumes that the application is the only code that is writing to the DOM. In practice, many browser extensions will also mutate the DOM. This will cause angular-react to throw and break the application.

This check should be, at most, a warning in production code.

Test case

Run this code in console.

Array.from(document.querySelectorAll('body *')).forEach(n => n.setAttribute('style', n.getAttribute('style') || 'zoom: 1'))

The next time that the Angular component is re-rendered, it will throw and break the application.

Configure Karma

Any ideas on how I would configure karma to not have to skip all my tests?

ng serve throws errors

Hi there, I want to use angular-react with Fabric, but it doesn't work.
Whenever I import a module and run ng serve, it throws some errors.

image

ERROR in node_modules/@angular-react/fabric/src/lib/components/callout/callout.component.d.ts(7,34): error TS2339: Property 'componentRef' does not exist on type 'ICalloutProps'.
node_modules/@angular-react/fabric/src/lib/components/image/image.component.d.ts(5,32): error TS2339: Property 'componentRef' does not exist on type 'IImageProps'.

I'm using following package versions:

  • Angular 8
  • @angular-react/fabric: 1.0.2
  • office-ui-fabric-react: 6.200.0
  • rxjs: 6.5.2
  • react: 16.9.0
  • react-dom: 16.9.0

Running on Ubuntu 18.04 on Windows 10.
Depending on which versions of the packages I use, there are different errors.

Any ideas on how to fix this are very appreciated. Thanks!

Use display: contents on wrapper components

Wrapper components currently either have the default display (inline), or when using setHostDisplay: true, have it be set to whatever the root element is.

This is done because support for display: contents is partial at the moment, with Edge and IE not supporting it at all, and Safari and all Chromium-based browsers having accessibility issues.

This should be further explored, and use CSS.supports() to do use display: contents when available if possible.

Deprecated lifecycles

Hello,

I'm getting warning messages indicating that the components are using deprecated lifecycles. The primary ones I've noticed so far have been componentWillReceiveProps, componentWillMount, and componentWillUpdate. The message indicates these should be replaced with componentDidUpdate and componentDidMount. Appreciate the help.

Many thanks,
Stacy

When using React components inside Angular ones, they are attached to the root of the VDOM tree & not removed

From @bengry on July 22, 2018 7:57

When having the following structure: React -> (via ReactContent) Angular -> React,
the inner React component is attached to the root of the VDOM:
image

Instead of being nested under the ReactContent (seen above under the div with key="run"), it's nested as a root node in the VDOM.
These nodes are also kept in the VDOM after the DOM element has been removed.

Demonstrated here.

A workaround for this (but not a solution) by @xjerwa - in AngularReactRendererFactory:

end() {
    if (DEBUG) { console.log('RootRenderer > end > isRenderPending:', this.isRenderPending, 'reactRootNodes:', this.reactRootNodes); }
    // Flush any pending React element render updates.  This cannot be done
    // earlier (as is done for DOM elements) because React element props
    // are ReadOnly.
 
    // Potential fix: manually unmount ReactNodes that don't correspond to a DOM element
    for (let i = 0; i < this.reactRootNodes.length; i++) {
      const node = this.reactRootNodes[i] as any;
      if (!document.contains(node._parent) && ReactDOM.unmountComponentAtNode(node._parent)) {
        this.reactRootNodes.splice(i--, 1);
      }
    }
    // End potential fix
 
    if (this.isRenderPending) {
      // Remove root nodes that are pending destroy after render.
      this.reactRootNodes = this.reactRootNodes.filter(node => !node.render().destroyPending);
      this.isRenderPending = false;
    }
}

Copied from original issue: benfeely/angular-react#13

Help Request: React component is checking for a prop when it is created, but the prop doesn't appear to be supplied until later

Hi!

I'm trying to create a wrapper around a React component to use within Angular. I haven't done much with React before, so that side of things is quite new to me.

I'm getting an error that a prop is required, but I am supplying that prop.

I had a look and the component is expecting a prop to be set when it is created. However it appears that in Angular-React, the property is supplied later.

The component still works, but it logs a whole lot of errors before it starts working.

The error is like this:

ERROR TypeError: MyReactComponent requires a fetch function.
    at new MyReactComponent (MyReactComponent.js:114)

The code that is throwing the error is this:

if (typeof props.fetch !== 'function') {
  throw new TypeError('MyReactComponent requires a fetch function.');
}

In my template I have (This is slightly simplified, there are multiple related components in there)

<div #reactNode className="myreactcomponent-container">
    <MyReactComponent [fetch]="fetch"></MyReactComponent>
</div>

And fetch is a function in the class (and it is being called)

So I am just wondering if I am doing anything incorrectly, or is there a way I can supply the fetch prop earlier on to avoid the error?

Thanks!

Ryan

Types are missing in the 4.1.0

I got this problem when I try to compile my angular app (angular 13) I have the following error.

node_modules/@angular-react/core/src/lib/components/wrapper-component.d.ts:1:23 - error TS2688: Cannot find type definition file for 'libs/core/src/lib/@types/geteventlisteners'.

1 /// <reference types="libs/core/src/lib/@types/geteventlisteners" />
                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When I look into the libray downloaded by npm https://registry.npmjs.org/@angular-react/core/-/core-4.1.0.tgz I don't found the folder types in core. Moreover the path seems wrong in lib and not in the code

/// <reference path="../@types/geteventlisteners.d.ts" />

After investigation it's because d.ts files are not embedded during compilation process.

So I forked the project to propose you an update of the lib to have the right compilation and avoid to have this error.

Problem passing children and modifying them

We have a React based library, which contains a 'button group toggle' component - a wrapper to a group of Button(s) components (handled to it as children), which modifies them lightly (after checking that they are of the right type) to add a click event handler and attaching an 'active' prop based on the wrapper state.

In React, the code works fine.

However, in Angular using angular-react, it doesn't work as expected: first, the children of the wrapper component are not the buttons themselves but rather the ReactContent element. Next, the even if taking the ReactContent children (this.props.children[0].props['children-to-append']) they are the buttons but their type is not the same type as seen by the code in when we use the library in React directly: the angular type instead of the React type. This causes React to shout when we attempt to modify the children (as mentioned above).

This is how we render the children in the wrapper component:

<ButtonGroupToggle
      #reactNode
      [fill]="fill"
      [minimal]="minimal"
      [large]="large"
      [vertical]="vertical"
      [defaultActive]="defaultActive"
      (onActiveChange)="handleActiveChange($event)">
      <ReactContent>
        <ng-content></ng-content>
      </ReactContent>
</ButtonGroupToggle>

I suspect this is a usage issue more than a bug... .
Any help will be appreciated. TIA!

Help requested on wrapping react component into angular

Hi all,

I'm trying to learn how to use the angular-react through the examples in the wiki. Not sure if this is the correct place to ask, please tell me otherwise.

  • I've successfully achieved the use of already provided fab elements (fab-calendar, fab-dialog or fab-primary-button) and setting their properties successfully

  • I've successfully created a React JS library (packed and deployed) and used in React Applications

import React, { Component } from 'react'
import PropTypes from 'prop-types'

import styles from './styles.css'

export default class ExampleComponent extends Component {
constructor(props) {
super(props);
}

static propTypes = {
name: PropTypes.string
}

render() {

return (
  <div className={styles.test}>
    Hello {this.props.name} {this.props.lastname}
  </div>
)

}
}

Module specification is quite straightforward, but I'm stuck with component definition. I've tried looking at how it was made for Fabric e.g. Dialog => React and Component Wrapper but these are bit complex to follow.

One of the requirements of ReactWrapperComponent is to place a <TProps extends {}> which for Fabric element is made through Typescript Interface definitions e.g. export class FabDialogComponent extends ReactWrapperComponent, but as I'm using React in JS and not Typescript, It's not clear to me, what to put in ReactWrapperComponent<> and how to access my react Props (i.e. name & lastname).

  • Is it necessary to work with React Typescript or is it possible to wrap libraries in React JS?
  • What is the goal of renderCount && onRenderCount in the Authoring wiki?
  • Following Fabric Component Wrapper example I miss (onIncrement)="onIncrementHandler($event)" or similar in the template, am I missing something?
  • Could you provide or is it accessible the 'my-react-ui-library' used in Authoring wiki?
  • Could somebody provide a corresponding wrapper code for the simple example (ExampleComponent) provided above?

Thanks in advance and sorry for the dumminess,

Gorka

Help Request: React does not recognize the prop

Hi,

I'm trying to achieve 2 way data binding to a property. Similar to in this example where the React prop doesn't meet the naming conventions for the Angular banana box syntax.

https://github.com/microsoft/angular-react/blob/master/libs/fabric/src/lib/components/checkbox/checkbox.component.ts

However I get a warning from React

Warning: React does not recognize the `queryChange` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `querychange` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

My prop is called query, the React prop is called onEditQuery (which I bind as [EditQuery]), so I've made a queryChange EventEmitter, then emit an event in the EditQuery handler function.

Is there any workaround for this? It still all works, I just don't like the errors in the console.

Thanks!

Generate components

The issue

Currently creating @angular-react components is done manually, specially in @angular-react/fabric (but the same holds true for any library implementation).
This is fine for a few components, and didn't prove to be worth the effort of creating such a tool, but as the library grows, and more components are added - this seems like it would simplify the long-term maintenance, especially in regards to upgrading the underlying React UI framework (e.g. office-ui-fabric-react, Semantic-UI-React).

Proposed solution

There are a number of ways to go about this, but the most likely is to use Angular Schematics to generate components, which as part of the inputs will take some sort of identifier for a *Props interface (e.g. ICheckboxProps), and together with the TypeScript compiler API (or any of its wrappers) and add the relevant Inputs and Outputs for the component, as well as bindings for the template etc.:

  1. Props that are of type string | number | boolean | object should be added as-is. e.g: componentRef?: IRefObject<ICheckbox> -> @Input() componentRef?: ICheckboxProps['componentRef']
  2. Props that conform to (...args: any[]) => void should be added as @Outputs, with the arguments added as an object with properties the same name as the function parameters. e.g.: onChange?: (ev?: React.FormEvent<HTMLElement | HTMLInputElement>, checked?: boolean) => void -> @Output() readonly onChange = new EventEmitter<{ ev?: Event, checked?: boolean }>().
  3. Props that confirm to (...args: any[]) => *non-void* should be added as-is (see 1. above), also as @Inputs.
  4. Props that are of type IRenderFunction<T> should be added as InputRendererOptions<T>. If the prop name is prefixed with an on, omit it (the Angular doesn't let Inputs be prefixed with on), and camel-cased. e.g.:
    onRenderNavigation?: IRenderFunction<IPanelProps> -> @Input() renderNavigation?: InputRendererOptions<IPanelProps>.
  5. (optional) copy the JDoc as-is.

Open issues:

  • The proposed solution is very specific to office-ui-fabric-react, as this is the only actively-maintained package wrapper - I think this is enough to support automating it, for the moment at least.
  • There are probably more things that could be automated as far as generation goes, but the above list is a (very) good start.
  • For anything that's not defined above, examples and patterns from the existing code-base of @angular-react/fabric can be used as reference.

Could you add quick start?

I found that amazing library and I'd like to use it, but documentation isn't good enough.
The links in READMEs such as Documentation, quick start, and guides go to page that contains some performance tests, components presentations etc., but there is no any documentation, quick start and guides.

And my question is: Could you add these resources?

Set selection on fab-details-list

Hi,
I'm using a fab-details-list with groups items and I need to select an item programmatically and also to show it (scroll to selected item) and to expand the group that contains the selected item.
is it possible ? if yes .... how can do it ?
Thanks.

fab-people-picker resolveSuggestions callback gets invoked with the incorrect scope

I am using the fab-people-picker component and have attached a callback to resolveSuggestions. When the callback is invoked, the this pointer points to the fab-people-picker component instead of pointing to the container (i.e.. my component where the fab-people-picker is added).

This is a screenshot of the this pointer when resolveSuggestions callback is invoked.
image

Same's the case with any callback that is provided as an input to the component, e.g.. selectedItems callback

I tried to get around this by binding my method to (onResolveSuggestions)="AuthorPickerInputChanged($event)" however as expected, the $event is empty, however the this variable is correct and points to my component.

I need this to point to my component so that I can use the injected services to actually resolve the suggestions.

Any suggestions on how I can get this to work?

Implement declarative pattern for "fab-" components

From @benfeely on July 12, 2018 18:20

The initial effort to create wrappers for Fabric components is targeted at closely following the React Fabric API. This means implementing a largely imperative pattern, particularly for scenarios such as defining "items" within a "CommandBar". Following the react pattern, these items are defined by passing in an object as a property. Although this is a valid pattern, the Angular community tends to lean more towards a declarative model...

Imperative

This is the initial implementation which follows the React Fabric API for the component closely.
Component

commandBarItems: ICommandBarItemOptions[] = [
  {
    key: 'run',
    text: 'Run',
    iconProps: {
      iconName: 'CaretRight',
    },
    disabled: true,
  },
  {
    key: 'custom-element',
    onClick: () => {
      console.log('custom element clicked');
    },
    render: this._customCbItemRef/* this.customCbItemTemplate */,
  },
];

Template

<fab-command-bar #commandBar [items]="commandBarItems" [farItems]="commandBarFarItems">
</fab-command-bar>

Declarative

This is the proposed implementation to add to the extend the API and allow for declarative syntax (preferred by many Angular teams).

<fab-command-bar #commandBar [items]="commandBarItems" [farItems]="commandBarFarItems">
  <items>
    <fab-action-button [iconProps]="{ iconName: 'AddFriend' }" text="Compound" [secondaryText]="'Loren ipsum dolor sit amet'" (onClick)="onActionButtonClicked($event)"></fab-action-button>

    <fab-compound-button [iconProps]="{ iconName: 'AddFriend' }" [secondaryText]="'Loren ipsum dolor sit amet'" (onClick)="onCompoundButtonClicked($event)" text="Compound"></fab-compound-button>
  <items>
  <far-items>
    ...
  <far-items>
</fab-command-bar>

Note: This proposal is based on Commercial Store's implementation of BSX-List (which is patterned after the Angular Material list and other components). Please see BSX-List source for implementation examples.

Copied from original issue: benfeely/angular-react#11

Working from source

Hi,
I have an angular project which hosts a sub-directory with several components.
I want to migrate the sub-project to react and embed it in the angular.
But, I don't want to bundle the react migrated folder as an NPM package.
Is it possible to embed the react folder (source code)? if not, is there a simpler solution rather then bundling a react NPM package?

Thanks

ComponentRef passed to RenderInput disappears after detecting changes

From @bengry on July 13, 2018 14:36

When passing a ComponentRef as a RenderInput to a component, after a change detection is triggered the component is removed from the DOM.
This doesn't happen when passing a TemplateRef or a () => HTMLElement.

Repro code:
Template

<fab-command-bar [items]="commandBarItems">
</fab-command-bar>

<button (click)="toggleRun()">Toggle change detection</button>

Component

private _customCbItemRef: ComponentRef<any>; // initialized via a `ComponentFactoryResolver`.

commandBarItems: ICommandBarItemOptions[] = [
  {
    key: 'run',
    text: 'Run',
    iconProps: {
      iconName: 'CaretRight',
    },
    disabled: true,
  },
  {
    key: 'custom-element',
    render: this._customCbItemRef
  },
];

toggleRun() {
  // Triggers change detection - `FabCommandBar` is defined as `OnPush`
  this.commandBarItems = this.commandBarItems.map(item => item.key === 'run' ? { ...item, disabled: !item.disabled } : item);
}

Expected result:

  • "Run" command bar item changes the disabled state.

Actual result:

  • run command bar item changes the disabled state.
  • custom-element command bar item disappears.

Copied from original issue: benfeely/angular-react#12

Panel & Dialog both are opened. If you click outside the panel, the panel closes.

The issue, for office-ui-fabric-react, is documented here: [https://github.com/microsoft/fluentui/issues/7225]. I reproduced the problem with this code:

<fab-panel [hasCloseButton]='false' [isBlocking]='true' [isOpen]='true'>
  <fab-default-button text='close' (onClick)='Visible = true'></fab-default-button>
</fab-panel>

<fab-dialog [hidden]='!Visible'>
  <div>Are you sure ?</div>
  <fab-dialog-footer>
    <fab-default-button text='yes'></fab-default-button>
    <fab-primary-button text='no'></fab-primary-button>
  </fab-dialog-footer>
</fab-dialog>

although isBlocking = true if you click outside the panel, the panel closes.
To resolve the problem, I added this line to the template of fab-panel

(onOuterClick)='undefined'

obviously it's possible to define another event handler:

(onOuterClick)='onOuterClick.emit($event)'

how to set style of fab-details-list header

Hi, I'm working with fab-defails-list and I would customize the header and the rows passing custom styles (IDetailsHeaderStyles / IDetailsRowStyle) or overriding the default styles. I try to understand the code behind renderDetailsReader and renderRow but I don't understand if it's possibile and how to call the defaultRenderer passing a modified props parameters. Can you help me ? Thanks

When using tree shaking (ng build --prod), some components lose their styling

Some components in Fabric lose styling when served/built using tree shaking (ng build|serve --prod).
These components are at least:

  • DatePicker (fab-date-picker)
    • The Calendar within it is unstyled.
  • Panel (fab-panel)

These seem to happen due to these components using plain Sass and not CSS-in-JS like most of the office-ui-fabric-react lib uses.
Components that use CSS-in-JS are not affected (for example, the text field and the icon in the DatePicker appear fine in a prod build, the calendar inside the popup does not).

The way office-ui-fabric-react works for plain CSS-styled components is that they have an original *.scss file, that's compiled down to a *.js file in the following format (unminified & shorten below for readability):

import { loadStyles } from '@microsoft/load-themed-styles';
loadStyles([
  {
    rawString:
      ".root_c754aea6{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:none;box-shadow:none;margin:0;padding:0}.root_c754aea6 *::-moz-focus-inner{border:0}.root_c754aea6 *{outline:transparent}.root_c754aea6 *{position:relative}.ms-Fabric--isFocusVisible .root_c754aea6 *:focus:after{content:'';position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;border:1px solid ",
  },
  { theme: 'neutralSecondary', defaultValue: '#666666' },
  ...
]);

export var root = 'root_c754aea6';
...

It seems like the Angular CLI prod build removes the call to loadStyles in the code, since I can import these files in the app and access the values of the exported variables (root above, though there are others, depending on the file).

Support for angular 12

The current v4 is working with Angular 11, any plans for upgrading the library for angular 12 support?

office-ui-fabric-react v7?

Is there a timeline for upgrading this project to use office-ui-fabric-react v7?

We're starting a new add-in based on an Angular project - and we'd like to start with 'the latest'.

Should we start with the current release in hopes that v7 will come soon or?

Other alternatives we should be looking at?

Thanks, Chad

Invalid links in wiki

In the Architecture page Architecture:-High-level.md twice an incorrect link is used.

Line 19: [more on that here](https://TODO)
Line 25: [caveats](https://TODO)

Working with Angular 9?

Does @angular-react/fabric work with Angular 9?

Playing around, and it appears children aren't working with the new version. I get an empty react-content element where I'd expect child elements to display.

fab-panel and renderFooterContent

Hi, I've an issue using renderFooterContent in a fab-panel. This is the template to reproduce the problem.

<fab-panel [isOpen]='true' headerText='Test' [renderFooterContent]='TEMPLATE'>
  <render>
    Content
    <button (click)='IncCounter()'>Change</button>
  </render>
</fab-panel>

<ng-template #TEMPLATE>
  {{Counter}}
</ng-template>

I had this exception

ERROR TypeError: Cannot convert undefined or null to object
at Function.assign ()
at ReactTemplate.push../src/@angular-react/core/src/lib/renderer/react-template.ts.ReactTemplate.componentDidUpdate (react-template.ts:66)
at commitLifeCycles (react-dom.development.js:16242)
at commitAllLifeCycles (react-dom.development.js:17592)
at HTMLUnknownElement.callCallback (react-dom.development.js:149)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:17280)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:498)

I tried to patch the code of react-template in this way (obviously it's only a temporary workaround).

  componentDidUpdate() {
    // Context has changes, trigger change detection after pushing the new context in
    try {
      Object.assign(this._embeddedViewRef.context, this.props.context);
    } catch {
      console.info('ReactTemplate invalid context');
    }
    this._embeddedViewRef.detectChanges();
  }

Naturally it seems to work, but when I click on the button the counter in the footer changes only if there is an event on the page (mouse move o click another time on the button).

It sounds like the componentDidUpdate method is called outsize the Angular Zone.
Another strange thing is that if I set the renderHeader with TEMPLATE, after rollback the workaround (try ... catch), it doesn't throw the previous exception but I've the same problem about the counter updating.

Thanks

How to declare IDetailsListColumnOptions.render in angular

Hi,

I want to create a fab-details-list by passing in colums: IDetailsListColumnOptions[]. I want to do this to simplify column sorting, amongst other things, i.e. specify columns and manipulate meta-data via typescript in a similar way to the Fabric UI React documentation/examples

I am trying to specify renderers for some columns, but am not having any luck creating InputRendererOptions<>. Could you please provide an example of how I can specify a simple renderer. Obviously, what I have below doesn't work.

columns: IDetailsListColumnOptions[] = [
    {
      key:'name',
      name:'Name',
      minWidth: 100,
      // ....
      render: (ctx: IDetailsListColumnOptionsRenderContext) => { 
         return `<strong>how do I do this? or how to {{ ctx.item }} or ` +ctx.item + `</strong>`
      }
    },
]

It would be great to be able to reference an <ng-template> or similar, within the component, but I can't utilise the columns > fab-details-list-column > render tag/directive, as doing so means I have to define (and maintain) the columns in the template.

The React method for specifying a renderer is very straight forward, using JSX:

onRender: (item: IDocument) => {
          return <img src={item.iconName} className={classNames.fileIconImg} alt={item.fileType + ' file icon'} />;
        }

Sorry for asking a question as an issue, but the lack of documentation and community support leads me here.

version 0.6.4 is missing "main" key in package.json

I don't see a main or module key in package.json or any reference to js in the package.json file. my build tools are not able to resolve the JS for this version. Going to have to move back to an older version for now...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.