AngularJS Directive into React App - javascript

We are looking at writing a new app using React but will need some existing Angular Directive that are specific for our business, for example a modified Angular Date Picker for example. There are many components so we won't be able to rewrite them all.
I am wondering if anyone has experience or knows the effort or feasibility of this?
The only article I've managed to find on this so far has been. Most resources I find mention going the other way from an Angular App with added React. http://softeng.oicr.on.ca/chang_wang/2017/04/17/Using-AngularJS-components-directives-in-React/

There's a library called angular2react that makes possible reuse angularjs code inside react components. You can see if it fits your needs. :)

I have written a simple demo app showcasing how to achieve it: react-angularjs-bridge
The basic steps are as follows:
Create a react component that is going to host the angular component in the DOM. This component should always render a simple html element (eg. a HTMLDivElement) so that react does not get confused when reconciling the virtual DOM with the real DOM.
After the react component was mounted componentDidMount, create a shadow root under the rendered HTMLDivElement and initialise the angular application under it. This will ensure that the angularJS component is encapsulated and is not affected by the react application and vice-versa
Click here for a demo. Check how the react application styles do not impact the styles of the angular component.

Independently of Angular, ref is a way to go: it gives to access to an underlying DOM node and the ability to manipulate the DOM inside that node in any way you like, including AngularJS. Your changes will stay - at least until react clears the component altogether.
You can create a ref in react by
<divOrAnyOtherDom ref={((el) => {this._elem=el;}).bind(this)}></...
(for the full description and alternate ways to the same end see here: https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
Anyway, as you now have a DOM node, you can start working with it, i.e. adding angular to the mix inside componentDidMount. Sadly, this is not really obvious - here's a way that has worked for me in the past (moduleName needs to be a module you have put in place already with your logic):
let baseElement = angular.element(this._elem);
let templateElement = angular.element(templateSource);
angular.injector([ 'ng', moduleName ]).invoke(function($compile, $rootScope) {
let cmp = $compile(templateElement);
scpe = $rootScope.$new(false);
scpe.varname = whateverYouHave; # point is: you can set scope variables
cmp(scpe);
baseElement.append(templateElement);
scpe.$digest();
});
Now you have angular inside the DOM node react gave you.
(I've taken this from a slightly different integration: Vaadin to AngularJS, but the principle is the same: Vaadin, just like react, gives you a DOM node. When you're interested in the full code: https://github.com/akquinet/vaangular/blob/master/vaangular/src/main/resources/de/akquinet/engineering/vaadin/vaangular/angular/NgTemplate.js)
Plus: For any callbacks from the angular component, you'll likely have to use setState et al.

Related

Visual builder to work with manually hard-coded templates/components

I wonder, is it possible to create a visual no-code builder to work with JS components (e.g. React JSX) if them are manually hard-coded before?
Let me explain what I mean.
Suppose a simple React component pages/index.js previously written by a developer manually:
function HomePage() {
return <div>Welcome to Next.js!</div>
}
export default HomePage
How can we change such a component in the front-end using a visual builder?
For example, we want to add a new HTML element (e.g. H1) inside the existing div.
As I can understand, the builder first needs to know in which JS file the HTML markup is stored to update it. So we can add id="homepage" to the div first and then store a relation as a config like
{"homepage": "pages/index.js"}
And now if we add a new element inside <div id="homepage">, the builder adds the element to the DOM of the div at the client, then takes the whole updated DOM of the div and writes back to the file index.js according to the config
Ok, but the file contains not only HTML markup - it's JS (React) code.
How to keep all the JS code e.g. function HomePage(), return, export default and so on ?
As an option, we can separately load all the JS code as HTML including non-HTML code as #text nodes. Then update the DOM and re-write everything back to the file.
But it sounds complicated and may cause unexpected issues.
So what solution would be the best?
Or maybe there is a ready React-specific solution?
Or maybe it's a bad idea at all to parse and re-write manually hard-coded components by visual builder and the only solution is to store everything as JSON like "homepage":{"div", {"class":""}, "Welcome..."} which is more easy for re-writing ? (but requires a new render)
It depends
I believe the answer that you are looking for very much depends on the level of flexibility that you want your no-code builder to have.
Depending on that, your project could benefit of the trade-offs and advantages of different solutions.
Let's briefly remember that basically a React component will need some props that then will be taken through a render template and output a working HTML. This is assuming a basic case where you don't need your react components to be smarter. Additionally, JSX is just sugar coating over function calls, so you could basically just compose functions to output a React component independently of using the JSX syntax. Hence no need to declare HTML, just changing the output of your no-code tool to JS instead of HTML.
For example, if you can modify how the no-code tool render, you can specify that when moving an element inside another you basically:
Highly Flexible & Customisable
In a highly flexible setup, I will recommend going through the last option you numbered, having a Data-Driven UI is the most common of the cases for complex systems. For example, Figma has an option to export the designs as react components, you can read how they do it here. Basically they take the tag output from figma which is a JSON of tags and create some React componets using templates. If you define "you own UI language" you could have quite a good control over what blocks you can build and define the way of interacting with them (e.g. adding a img component could be quite easy if you know the props and what it needs to render, then creating a React template for it is easy).
Limitations: you require to plan quite well the API of the parser and interaction between different sets of items.
Simple no-code builder
For simpler scenarios you could go with the first approach that you mention, you won't even need to add ids, some tools like React Developer Tools can already inspect the VirtualDOM to understand which part of the render belongs to which React Element (using react internals, which could take some time to understand, but for example you can inspect in the rendered how they use the data-reactid for identification). Knowing this, you can already define the template functions for the render() method (so the JSX output), and separate it code wise, so that when you generate the code, the HTML template is split from the React code as much as possible.
Silly example of how it could look:
// htmlBlockTemplate.js
export const helloPageTemplate = (props) =>
`<div> <h1>${props.title}</h1> </div>` // This can be generated from the `no-code`
// page.jsx
export const Page = (props) => {
return helloPageTemplate(props)
}
Using functions it could look like:
const Page = (props) =>
return React.createElement('div', null,
React.createElement('h1', title: prop.title, `The title ${title}`)
);
}
Limitations: eventho you could, adding custom components (like another React Component or a web component), it becomes more difficult since you will also have to deal with the import graph and probably.
Inevitably you will need to tweak how the render of the component works (rather by creating a parser from your UI language, or changing how the react component is written. If you have a good control of AST, then writing a parser for either of the cases should not be a problem.

Using existing cljs components in a React project?

https://www.reddit.com/r/Clojure/comments/4el0xi/how_to_use_an_existing_reactjs_component_with/
There is this existing post about using existing ReactJS components in a CLJS/Reagent project. I'm looking to do the opposite. I have a bunch of CLJS components and would like to compile them into a ui library of some sort so that they can be used by React developers. That is, if I have a button CLJS component, I would like to be able to render that Button using < Button /> or mylib.Button(_) etc.. in a React/js app file.
I have read this - https://shadow-cljs.github.io/docs/UsersGuide.html#target-node-library - extensively but it's not quite working out. I've been using ":target :node-library" and I can get simple functions (that return strings/numbers, for example) to compile and work in my app, etc.. but it doesn't work for entire components. For example, my cljs button component takes in :
defn button [props & children]
but when I try to pass in these parameters (I call {lib.button({}, {})} in my App.js file), I get errors like "No protocol method IMap.-dissoc defined", because I'm trying to pass JS objects into CLJS-only functions, I believe. Not sure how to resolve this..
I can explain more on this if it would help clarify. It would also be super helpful if anyone had a reference demo project or any resources they could link me to.
I only have a few suggestions:
You can try to build a new sample project to consume your library with lein new figwheel myproject and use JavaScript interop to move one step at a time closer to the native JS way of using your library.
You can create an interface namespace that can consume JS objects and wrap these into Clojure data structures to sort out the protocol errors you're seeing, eg. functions that take a props parameter and pass down (js->clj props) to the rest of the code underneath.
For the authoritative source, check the Reagent docs, especially this: http://reagent-project.github.io/docs/master/InteropWithReact.html#creating-react-components-from-reagent-components

Use Knockout.js on the same page as Vue.js

Hi I have an existing project which uses alot of knockoutjs.
Im attempting to add vuejs to the project and slowly move everything over to vuejs in time.
Ive added vue to a wrapper element which contains the whole page and created a single vue component.
My aim is to use that component anywhere on the page but not break my knockout code.
The problem im having is my knockout bindings are not being defined when I apply the vue el tag to the main element that wraps the page and the ko.applyBindings scripts. (vue elements work ok but all ko scripts throw an error )
I am using complied templates and the vue-cli with webpack-simple.
Im pretty new to vuejs but I think this is happening because vue is trying to parse the knockoutjs code inside the page html
console error:
ReferenceError: Unable to process binding "slideVisible: function(){return !isShowBillingForm() }"
Message: isShowBillingForm is not defined
at slideVisible (eval at parseBindingsString (knockout-3.3.0.js:61), <anonymous>:3:65)
at init (slidevisible.js:15)
at knockout-3.3.0.js:65
at Object.u (knockout-3.3.0.js:35)
at knockout-3.3.0.js:65
at Object.o (knockout-3.3.0.js:10)
at g (knockout-3.3.0.js:65)
at h (knockout-3.3.0.js:63)
at k (knockout-3.3.0.js:63)
at h (knockout-3.3.0.js:63)
If anyone could help me that would be amazing
(Ive also added the vue cdn to the header and added in vue markup into the page directly and their are no conflicts) so I guess its something to do with the compiled templates?
I've added Vue to a wrapper element which contains the whole page and created a single Vue component.
I believe that's the issue. When migrating to VueJS from legacy Knockout you will have to pick and choose where you want to use Vue.
The way Vue parses the DOM is very different compared to Knockout. It uses a concept of virtual DOM, so the final DOM output is only valid HTML and no framework specific markup. That inherently will break any KO code bound to it.
So the approach I'd recommend is finding pieces of the app you want to convert to Vue and then instantiate Vue inside a Knockout VM (or with plain JS) like this:
import Vue from 'vue';
import MyVueComponent from 'libs/components/my-component.vue';
const propsData = {my: props};
const myComponent = Vue.extend(MyVueComponent);
new myComponent({el: '#some_element', propsData: propsData})
Also important, make sure you tell KO not to process #some_element that Vue is bound to by using the stopBinding handler as described here.
Hope that helps!

Vue js 2 - Accessing data in App.vue from child components

I'm pretty new to Vue and I'm trying to create my first app with it (I have worked through a whole tutorial though so it's not like I'm completely new to it). I come from a Java/Grails background so this new "frontend oriented webapps" is still pretty confusing to me. I'm using Vue 2 with webpack.
The problem I'm having is running methods when the app initializes which creates data in the App.vue component (which I'm assuming is the root component, is that correct?) and then accessing this data in child components. So specifically what I'm trying to do is on in the 'created' life cycle hook I want to check if the user is logged in or not and then I want to update my navbar accordingly (show a login button if not, else show the user's name, for example).
I haven't even quite figured out how exactly I'm gonna determine if the user is logged in yet coz so far I've only been trying to create dummy data in the App.vue component and then accessing it in child components. Everywhere that I've researched says that I should use an event bus but (I think) that's not gonna work for me (correct me if I'm wrong) coz the only examples I can find is all $emit functions being called on user events (like button clicks) and I want it to have the data globally accessible (and mutate-able) everywhere all the time.
So I'll try to show you some code of what I had in mind:
App.vue:
...stuff...
data() {
return {
authToken = '',
userdetails = {},
loggedIn = false
}
},
created: function() {
// check browser storage for authToken
if(authToken) {
// call rest service (through Vue Resource) to Grails backend that I set up
// beforehand and set this.userdetails to the data that gets returned
if(this.userdetails) {
this.loggedIn = true;
}
}
}
...stuff...
Home.vue:
<template>
<div class="home">
<nav-bar></nav-bar>
</div>
</template>
...stuff
NavBar.vue:
<template>
<div class="navBar">
<div v-if="loggedIn">Hi {{ userdetails.name }}</div>
<div v-else>Please log in before continuing.</div>
</div>
</template>
Please excuse if any of that code has any mistakes in it, it's just to show more or less what I'm trying to do and I made most of it up right now. So the main question: How do I go about getting the v-if="loggedIn" and {{ userdetails.name }} part to work (coz obviously the way it's set up now that won't work, right?). And then besides that, any general advice on "global variables" and data flow in Vue js will be appreciated coz I believe that my server-side app mentality might not work in front-end javascript apps.
To get Data from parent component you can use this.$parent.userdetails in the child component.
But a much better way is to use props like this
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-with-Props
Lite pattern, not for complex sharing tasks
You can access global app component everywhere (routes, components, nested components) with the predisposed field:
this.$root
Notes for overengineers: It is officially suggested as "lite" approach in vue guide: https://v2.vuejs.org/v2/guide/state-management.html.
Obviously, it is not a architectural patternized solution, but ok for just sharing a variable or two.
In these case this lean approach avoids developer to import a full sharing framework like vuex, heaving development, know-how requirement and page download, just for such a trivial sharing task.
If you dislike lite approaches, even when appropriated and officially suggested, maybe is not how to share the problem, but which framework to use.
For instance, Angular is probably best fitted for heavy engineered approach, and I not mean one is better than the other, I mean different instruments suite best for different task and approaches, I too use it when need to realize a heavier and more complex solution, in these case even with vuex I could not handle all the components interaction and realtime data sharing.
Following methods are not recommended by other developers or vue itself.
this.$root;
or
this.$parent.userdetails
In my opinion the best way to share any data across components is using vuex state management.
Here is the official documentation link: https://vuex.vuejs.org/#what-is-a-state-management-pattern

Testing an ember component that uses another component with separate template

I'm trying to test an emberjs component that uses another component. I'm using ember-qunit with the moduleForComponent method.
In there I define that my component needs another component, needs: ['component:my-kitten'].
But it seems that if you use a component with a separate template, then the template of that component is not loaded.
I altered the jsbin example from the emberjs guides.
Working example with template defined in the component as layout
Not working example where I moved the layout to a separate template
The needs property must also include any nested component templates:
...
needs: ['component:my-kitten', 'template:components/my-kitten'],
...
Look for "If you are using nested components with templates" on https://github.com/rwjblue/ember-qunit.
As an update, I'm running into a similar issue and the ember-qunit guides now expressly state
"You do not require dependencies through needs:. Doing so will force the test into unit mode."
Adding needs to my component integration test causes them all to fail, so the above answer is not relevant for current versions of ember-qunit (0.4.17).

Categories

Resources