I'm currently exploring an upgrade path for a pretty large AngularJS 1.6 app to Angular 6. I have my app bootstrapping as a hybrid app, and I've begun converting individual modules and components. I need to be able to do the migration in chunks, though. It would be nice if I could migrate a module at a time, but I'm running into some issues, to that end.
I have a NavBar directive which resides in my core AngularJS module. That component is being downgraded with downgradeComponent and registered on the AngularJS core module. The landing AngularJS module has a dependency on the core module so that it can use the NavBar. This works fine, because the LandingComponent has also been converted to Angular6 and is being downgraded and registered on the landing AngularJS module.
There is a problem with using the NavBar component inside of any other AngularJS component, though. I have a third AngularJS module called workflows with a ViewWorkflows component that has a NavBar inside its template. When I navigate to that component, I get the following error:
angular.js:14791 Error: No component factory found for NavBarDirective. Did you add it to #NgModule.entryComponents?
I can fix this by converting and then downgrading ViewWorkflows, but since NavBar is being registered as a downgraded AngularJS component, shouldn't any AngularJS module that declares a dependency on the core module have access to it?
Code (Not runnable)
Edit: I've updated the gist to be a little more simple. The landing module is Angular, with an Angular component, <landing> that is downgraded to run on the AngularJS landing module and has a <t-nav-bar> inside it. It has a dependency on the core module which provides the downgraded <t-nav-bar> directive. The <test> component is an AngularJS component registered on the AngularJS landing module that cannot use the <t-nav-bar>. Without even bringing the workflows module into the situation, it doesn't work. What am I doing wrong?
I have managed to sort this out. I was trying to declare the NavBar as an Angular #Directive. It actually needs to be a #Component. After making that switch, it works exactly as expected.
I spun up this repo to test with, and discovered the issue there. It's a new Angular 6 app that I "downgraded" for experimenting.
Related
I have an existing Angularjs application, and I would like to start using Reactjs.
I tried ngReact, I can create my own Reactjs component using React.createClass and reactDirective, and Angular is able call this directive successfully. I am only using bower to add dependencies for angular, react, and ngReact, I am not using any other tools like gulp, grunt, webpack, etc.
The main reason that I would like to use Reactjs is to invoke third party Reactjs components, which is created using Reactjs, not created using ngReact. I could not find an example that is doing this. What do I need to do to make the Angular application to find the Reactjs components and invoke it?
My angularjs 1.4 app was also not using common UI build tools like webpack. I wanted to introduce some react components, and this was my approach.
I created a file, angularModuleOfReactComponents.js.
It imports react components, then makes an angular module (reactComponentsModule) to hold them:
import MyComponent from './MyComponent.js';
import AnotherComponent from './AnotherComponent.js';
(function(){
var m = angular.module('reactComponentsModule', []);
m.value('reactMyComponent', MyComponent);
m.value('reactAnotherComponent', AnotherComponent);
})();
You should be able to do something similar by importing third party libraries. You could also write a react class that uses a third party library and import your wrapper class.
I then used Babel to convert my jsx react components and my angularModuleOfReactComponents.js to CommonJS, and then I used browserify to convert to something the browser understands. (Although I used build tools, they do not involve my angular app. And, this isn't my permanent mechanism. This is a two step process that doesn't allow auto recompiling when source is changed. I was just trying to get something to work for proof of concept, and I'll be improving this process soon.)
In my angular app, I load angular library files, then react libraries, then ng-react, then my browserified angularModuleOfReactComponents.js and then my app's angular code (controllers, directives, services, etc.).
To use a react component, I declare a dependency on 'react' (from ng-react) and 'reactComponentsModule':
var myModule = angular.module('myModule', ['react', 'reactComponentsModule']);
And then I can inject whichever component(s) I need:
myModule.controller('myController', ['$scope', '$log', 'reactMyComponent', function($scope, $log, reactMyComponent) {
$scope.myprops = {name:'Jack'};
}]);
In html, ng-react's react-component directive is used like:
<react-component name="reactMyComponent" props="myprops" watch-depth="reference" />
To add on #user3141592 answer, I've done a blog post recently on how you can migrate your angular app to React using webpack and ngReact:
https://www.devpanda.me/2018/02/16/Simple-Angular-and-React-Hybrid-App/
I've posted a github repo as well :
https://github.com/danielcondemarin/angular-react-hybrid
Gist
I have an application running AngularJS and Angular side by side, using the UpgradeModule. I have "upgraded" and AngularJS component (angular.component) for use in our Angular components (#Component). I have done so using the instructions on the Angular 1.x upgrade page.
The issue is that when this "upgraded" component is declared in the AppModule declarations: [] array, I receive an error saying unknown element 'tooltip'.
When I remove the declaration from the AppModule and declare it instead in the #NgModule for the component in which the upgraded component will be used, it works fine.
Please review the Gist for the code that is being used.
There is nothing wrong with the behavior.
The components must be declared in the module where you want to use it.
If you want to use the component in multiple modules, Create a SharedModule (shared module) and add your component to it's declarations and exports.
Import the SharedModule in other modules wherever you want to use this component.
More about shared modules in Angular2 Docs.
And here is a nice tutorial on NgModules that might help you.
I'm attempting to integrate React components into our Angular 1.5.x application. I've been successful thus far in learning webpack and utilizing webpack-dev-middleware and webpack-hot-middleware; however, I'm running into a problem when using an external copy of React.
ngReact expects to find copies of React and ReactDOM. In addition, loading Angular and our controllers, directives, etc. takes precedence. To avoid loading multiple copies of React, I set the external property in webpack.config.js.
Now that React is externalized, it doesn't appear Hot Reloading works anymore. The terminal updates, HMR is connected according to the browser console, but the component on screen is not reloading.
Is there a workaround?
I'm trying to build an hybrid Ng1/Ng2 app with NgUpgrade as an intermediate step in a migration towards Angular 2.
The bootstrap seems to work:
platformBrowserDynamic().bootstrapModule(AppModule).then( () => {
adapter.bootstrap(document.body, [Ng1AppModule.name]);
});
But I'm struggling at using a simple Ng1 directive in an Ng2 component, see this very simple plunker: https://plnkr.co/edit/gMSwKKIgEkwcijCCaCMW?p=preview
Even after having upgraded the Ng1 directive and downgraded the Ng2 component, the browser sends a "No provider for $scope!" exception.
What have I missed ?
I know that some people have already reported this exception, but it looks like NgUpgrade has evolved a lot since the beta of Angular 2, and I can't find the appropriate answer for current Angular 2 release.
Found it !
My mistake was to try to bootstrap directly a ng2 module, but it looks like you have to put a ng1 component at top level of the DOM (yes it's written somewhere in the official ngUpgrade guide). Here is the correct updated plunker with a ng1 root component, that calls a ng2 module, that calls another ng1 component.
const myNg1Root = {
template: `
<p>This is the Angular 1 root component</p>
<ng2root></ng2root>
`,
};
Just started a demo Angular2 project (no previous experience with Angular1/AngularJS. Have followed and extended from the online quickstart and tutorials, and all was fine. However I'm at the point where I would like to use some components from a library which is designed for AngularJS, and having no end of problems!
Most of the information available about AngularJS/Angular2 compatibility assumes that you have an AngularJS project that you're adding Angular2 components to - not the other way around - so what I'm hoping to do may not even be possible. What I've tried so far involves a simple stripped-back project based on the Angular2 quickstart, with a single Angular2 component that loads into the index.html. I'd then like to integrate components from the existing library (AngularJS-based) into this.
I've tried using UpgradeAdapter.upgradeNg1Component to create components from the library and add them directly into my Angular2 component
I've tried installing angularjs through npm, importing it in a script tag into my index.html and then using a combination of UpgradeAdapter.downgradeNg2Component and UpgradeAdapter.bootstrap to load my Angular2 as a downgraded module
Neither of these seem to work - the component fails to show, and the browser console tells me I've got an Uncaught SyntaxError: Unexpected token <
Evaluating http://localhost:3000/angular2/upgrade
Error loading http://localhost:3000/app/main.js
My best guess at the moment is that this is actually an unsupported scenario, and I need to have a 'proper' AngularJS app in order to use the UpgradeAdapter functionality from Angular2. Can anyone confirm this? Or is there something stupid I'm missing here?
Here is a working plunkr describing how to mix Angular1 and Angular2 elements:
http://plnkr.co/edit/yMjghOFhFWuY8G1fVIEg?p=preview
An important point is to bootstrap your main component on the UpgradeAdapter. This way all elements are available in providers (services / factories) and in directives (components / directives):
upgrade.bootstrap(document.body, ['heroApp']);
These two answers could help you:
angular 1.x and angular2 together
How to inject upgraded Angular 1 service/factory to Angular 2 component in ES5?
So the major problem in this case turned out to be the fact that it appears that the upgrade components aren't included as part of the basic angular 2 bundle. After adding:
<script src="node_modules/angular2/bundles/upgrade.min.js"></script>
to my index.html file the error I was seeing disappeared.
Thanks to the answer here for pointing me in the right direction!