Rendering AngularJS code inside React component - reactjs

Is it possible to render AngularJS component inside React component which is rendered from an AngularJS component.
I have a specific scenario where:
<angularjs-component-1>
<react-component>
<angularjs-component-2>
</angularjs-component-2>
</react-component>
</angularjs-component-1>
Inside of AngularJS app I have access to a library of react components which are in separate repo where they are exported and assigned to a window object so that they can be consumed inside of AngularJS app.
Inside of the angularjs-component-1 I have an access to a ref of react-component where I have to inject my angularjs-component-2.
I can append text to react-component from angularjs-component-1, but not sure how to inject another angularjs component/directive inside of it.
I don't have much experience with AngularJS and I am not sure if I am able to access angularjs-component-2 from angularjs-component-1 in order to pass it to the react component.
I don't think I can use angular2react since my react components are in separate repo, exported and assigned to window object so that they can be consumed in angularjs.
UPDATE: Solution found
<angularjs-component-1> has method which is passed to <react-component> that method is called from react and it passes ref to a div in which <angularjs-component-2> will be placed. Logic inside of that method is something like this:
function sendRef(ref) {
var $angularComponent2 = angular.element('<angularjs-
component-2 ng-model="propName"></angularjs-component-2>');
var reactComponent = angular.element(ref.current);
reactComponent.append($angularComponent2);
reactComponent.injector().invoke(function($compile) {
var scope = angular.element($angularComponent2).scope();
// if you need to assign some values to angular-component-2 scope
// this is the place to do it
scope.propName = $scope.someValue;
$compile($angularComponent2)(scope);
});
}
Hope this helps someone.

Related

How safely to pass params to react component with react-rails

I'm using react-rails to add some react componenets to an existing ruby on rails app. I just realized that all the props being passed initially to the component are easily seen if you inspect the component
<%= react_component('ProfileWeeklyWriting', {
languages: #user.languages,
currentUser: #current_user,
responses: #writing_responses,
clapLottie: asset_url('lottie/clap.json'),
clapIcon: asset_url('icons/clap.svg'),
arrowIcon: asset_url('icons/arrow_green.png')
}) %>
But when you inspect the element, allll those variables are shown!
I know I can just do an ajax call from within the component, but is there a way to pass variables to the component initially, without them being shown to the world?
Let's take a bit theory about how it works. When you do classic SPA without any backend engine you usually do something like
ReactDOM.render(<App />, document.getElementByID('root'))
Which simply render the root component on place of <div id="root" />. When you apply Rails templates on the top, you are connecting 2 different worlds. ReactDOM and Rails slim templating engine (probably) but they don't know nothing about each other. ReactRails is really simply routine which does something like this:
1 Inject custom react-rails script to page
Wait for DOM ready
Collect all [data-react-class] elements
Iterate through of them and call ReactDOM with props.
You can think of it like calling several "mini apps" but in fact those are only components (react doesn't distinguish app/component, it's always just a component)
So the code is something like this (I didn't check the original code but I wrote own react-rails implementation for my company)
function init () {
const elements = document.querySelectorAll('[data-react-class]')
if (elements.length > 0) {
Array.prototype.forEach.call(elements, node => {
if (node) {
mount(node)
}
})
}
}
function mount(node) {
const { reactClass, reactProps } = node.dataset
const props = JSON.parse(reactProps || '{}')
const child = React.createElement(window[reactClass], props)
ReactDOM.render(child, node)
}
Then the DOM ready
document.addEventListener('DOMContentLoaded', e => {
init()
})
Son in fact Rails doesn't know anything about React, and React doesn't know anything about Rails unless it's not living on window. (THIS METHOD IS HIGHLY DISCOURAGED.
In real world there are ways how to make "server" rendering, which means that this piece of code is done on server to not expose props and whole React lifecycle and just flush real prepared HTML to DOM. That means that in the lifecycle BEFORE HTML is sent to the client, there is called transpiler which compiles those components, you can read about it here
https://github.com/reactjs/react-rails#server-side-rendering
So it just calls those methods with a help of https://github.com/rails/execjs
So the only way how to "not expose" props to the client is to "pre-render" components on backend by some engine (either some JS implementation for your language or directly node.js backend). I hope I gave you a better picture how it works and how it can be solved!

Render angular 2 component in DOM node

I'm creating an Angular 2 application that uses CodeMirror as a source code editor. I'd like to add a line widget to it, which requires that I provide a DOM node to CodeMirror. I'd like to put some complex logic that depends on application data in this widget, so it will need to be an Angular component, however I can't figure out how to render an Angular element in a DOM Node (or whether it is even possible). Normally I would do it using a ViewContainerRef, but that doesn't work in this case.
Is there any way to achieve this using Angular 2?
You can always use ng2-codemirror (https://www.npmjs.com/package/ng2-codemirror), that already takes care of that for you.
In anycase, if you need to get a DOM node from an Angular 2 component you can do something like this:
<div #element>
</div>
And then, on your typescript file you can:
import * as ng from "angular2/core";
export class MyComponent {
#ng.ViewChild("element", {read: ng.ElementRef})
element: ng.ElementRef;
ngAfterViewInit(){
this.element.nativeElement; // you dom node is here!
}
}

React js in Aurelia js, call aurelia function

Am very new to react js and aurelia js, my requirement is use react for view and aurelia for model/routing and all. I refered this doc for installation, it works well. Done like this,here my view is in react js, while clicking the details in the table(doted icons),needs to call a function which should be in aurelia.
I followed the above mentioned doc for coding, instead of list in the my-react-element.jsx i changed into table style like in the pic.
Yeah, i got it. just understand passing value to components (custome-component in aurelia, component in react). In both, aurelia and react it works nearly same(like call-back function).
Code :
react-example.js Just declare a function, which you want to execute.
myfun(){
alert('Hi, am in aurelia..');
}
react-example.html use bind to set the declared function to custome-component.
<react-element myfun.bind = "myfun"></react-element>
react-example.js
#bindable('myfun')
<MyReactElement data={this.data} myfun={this.myfun}/>,
my-react-element.jsx
<p onClick = {this.try.bind(this)} >click </p>
try() {
this.props.myfun(); }
Note : Basic knowledge of react and aurelia required and compare the doc to fix.

I don't know how to organize a web app that uses component based web framework

I am trying to learn component based frameworks for frontend apps. Currently, I am using RiotJS but it applies to any framework that uses the same concepts (React, Angular 2.0 etc).
In a basic MVC frontend frameworks (e.g AngularJS), the controllers and router were very connected to each other. But with a component based framework, the line between router and controllers is much wider. And this is what confuses me the most.
Here is one example of an app that I am trying to build:
I have three main UI elements: Navigation Bar, Content Area, and Signin Form. So, I created three components: my-navbar, my-content, my-signin. I was able to create multiple routes per component. So for example, if there is a route changes, the navbar updates the active "module." Making this was easy because all I am doing is changing class of a list item.
Now, I want to load other tags inside <my-content></my-content>. In AngularJS, I was always changing the view completely (using ui-router). How can I achieve that in a component based framework. Let's say that I have 2 more components called my-content-users-list-view, my-content-users-detail-view. How can I add them to the component my-content based on the route? Do I just add it like document.innerHTML += '<my-content-users-list-view></my-content-users-list-view>?
I know most of my syntax is RiotJS but I will understand it if you write it in another framework's syntax.
Thank you!
Essentially, yes, you could just append your tag as a DOM node and then call Riot to mount it:
riot.route('/awesome-route', () => {
const tag = 'your-awesome-tag';
const options = { ... };
const elem = document.createElement(tag);
// TODO empty your content container using pure DOM or jQuery to get rid of the previous route's view...
document.querySelector('#content').appendChild(elem);
riot.mount(elem, tag, options);
});

How React Component expose data to external app?

Let's say i have a React Component <forecast id="test"/>. And i want import this component into a legacy project which only have jquery involved.
Is it possible to get the value of this component like document.querySelector('#test').value?
I got some information from React website, that we cannot access data from outside the component. The recommended way is dispatching data from inside of the component.
My question is, the way to dispatching data is behind of the component implementation. Is it means that i have to read the source code of component in case i don't know how it works?
If this is true, i won't think React is free to inject to any product, it cost too much.
If you want to inject some React to your project you should do it with some independent part of your system.
If you have tightly coupled code base its always high cost to add any new technology to it. So its not a React problem. Try to find some independent module or subapplication in your system and move it to React. If you cannot find one, try to refactor existing code first.
You need to write a plain JS wrapper to do it. Something like this might work
function Forecast(element) {
this.value = initialValue;
React.render(<forecast onChange={onChange.bind(this)}/>, element);
function onChange(newValue) {
this.value = newValue;
}
}

Resources