【问题标题】:AngularJS + Angular 8 not working together [ Hybrid application ]AngularJS + Angular 8 不能一起工作 [混合应用程序]
【发布时间】:2020-01-30 22:09:27
【问题描述】:

我有一个迁移大型 angularjs 应用程序的用例,我想首先在一个小型应用程序中执行此过程。因此,出于这个原因,我参观了英雄 angularjs webapp 并开始向它添加 angular(通过使用 angular-cli 创建一个新项目),然后添加 NgUpgrade 模块。

我现在遇到的问题是 angularjs webapp 在 angular 8 应用程序中运行得很好,但是属于 angular 8 的组件没有被渲染。

我的印象是我的角度组件没有被引导,因为我已经手动引导了 angularjs 但我不确定......当我在@NgModules 中明确添加引导属性时,它仅适用于角度组件,但不适用于对于 angularjs(这是有道理的)。所以我在想也许我必须升级 angularjs 组件或降级最新的 angular 组件,但我不这么认为。

Here 你会找到带有代码的 git 存储库。以下是与我的项目相关的更多信息:

  • 角度版本:8.2.8
  • angularJS 版本:1.6.10
  • angular-cli: 8.3.6

项目结构

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Common</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>

<body>
  <app-root></app-root>
  <hero-list></hero-list>
</body>

</html>

index.ts(angularjs 根模块)

// initialize root module and make it exportable to be able to bootstrap it
// inside angular
export const heroAppModule = angular.module('heroApp', [
    'ngMaterial',
    'perfect_scrollbar',
    'ngJsTree',
    'ngTagsInput',
    'ui.router',
    'heroApp.underscore'
]).config(['$stateProvider', function ($stateProvider) {
    var heroState = {
        name: 'hero',
        url: '/hero',
        template: '<hero-list></hero-list>'
    };
    $stateProvider.state(heroState);
}]);

/** start: REQUIRE ZONE for angularjs
 * Add angularjs files since they aren't yet fully ES6 modules
 * we use requirejs as module loader
 */
require('./editable-field/editable-field');
require('./hero-detail/hero-detail');
require('./hero-list/hero-list');
require('./underscore/underscore.module');
require('./underscore/underscore.service');
/**
 * end: REQUIRE ZONE for angularjs
 */

app.module.ts(使用 NgUpgrade 引导 angularjs)

import * as angular from 'angular';
import { UpgradeModule, setAngularJSGlobal } from '@angular/upgrade/static';

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { heroAppModule } from './../ngjs/index';
import { HelloworldComponent } from './helloworld/helloworld.component';

@NgModule({
  declarations: [ HelloworldComponent ],
  imports: [
    BrowserModule,
    UpgradeModule
  ] // ,
   // bootstrap: [HelloworldComponent]
})


export class AppModule {
  constructor(private upgrade: UpgradeModule) { }
  ngDoBootstrap() {
      setAngularJSGlobal(angular);
      this.upgrade.bootstrap(document.body, [heroAppModule.name], { strictDi: true });
  }
 }

ma​​in.ts

import 'zone.js/dist/zone';  // Included with Angular CLI.
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/ngx/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

英雄列表组件(angularjs)

declare var angular: angular.IAngularStatic;

(function () {
    'use strict';
    angular.module('heroApp').component('heroList', {
        template: require('html-loader!./hero-list.html'),
        controller: HeroListController,
        controllerAs: 'vm'
    });

    HeroListController.$inject = ['$scope', '$element', '$attrs'];

    function HeroListController($scope, $element, $attrs) {
        var vm = this;

        vm.list = [
            {
                name: 'Superman',
                location: 'The sky'
            },
            {
                name: 'Batman',
                location: 'Baticueva'
            }
        ];

        vm.updateHero = function (hero, prop, value) {
            hero[prop] = value;
        };

        vm.deleteHero = function (hero) {
            var idx = vm.list.indexOf(hero);
            if (idx >= 0) {
                vm.list.splice(idx, 1);
            }
        };
    }
})();

app-root 组件(文件名:helloworld.component)

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './helloworld.component.html',
  styleUrls: ['./helloworld.component.scss']
})
export class HelloworldComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

应用根模板

<p>helloworld works!</p>

angular.json(angular-cli 文件)

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "common": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/common",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": false,
            "assets": [
              "src/favicon.ico",
              "src/assets"            ],
            "styles": [
              "bower_components/jstree/dist/themes/default/style.min.css",
              "bower_components/ng-tags-input/ng-tags-input.bootstrap.min.css",
              "bower_components/utatti-perfect-scrollbar/css/perfect-scrollbar.css",
              "bower_components/angular-material/angular-material.css",
              "src/styles.scss"
            ],
            "scripts": [
              "bower_components/jquery/dist/jquery.js",
              "bower_components/angular/angular.js",
              "bower_components/angular-material/angular-material.js",
              "bower_components/angular-animate/angular-animate.js",
              "bower_components/angular-aria/angular-aria.js",
              "bower_components/jstree/dist/jstree.js",
              "bower_components/ng-js-tree/dist/ngJsTree.js",
              "bower_components/ng-tags-input/ng-tags-input.js",
              "bower_components/utatti-perfect-scrollbar/dist/perfect-scrollbar.js",
              "bower_components/angular-perfect-scrollbar/src/angular-perfect-scrollbar.js",
              "node_modules/@uirouter/angularjs/release/angular-ui-router.min.js",
              "node_modules/underscore/underscore.js"
            ]
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "common:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "common:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "common:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.scss"
            ],
            "scripts": []
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "common:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "common:serve:production"
            }
          }
        }
      }
    }},
  "defaultProject": "common"
}

结果...

【问题讨论】:

  • 在你的 app.module.ts 中试试这个:this.upgrade.bootstrap(document.body, ['heroApp'], { strictDi: false});
  • 嗨@MaximilianBoth,感谢您的评论,是的,我试过了,但这不起作用。我看不到 strictDi 在这里可以如何帮助我,因为它注定要控制显式函数注释的使用,如下所述:docs.angularjs.org/api/ng/directive/ngApp#with-ngstrictdi-

标签: angularjs angular typescript angular-cli ng-upgrade


【解决方案1】:

最后我发现我需要的解决方案永远不会在我的应用程序的根目录中并排使用每个框架的两个组件。相反,我使用了以下模式,因为角度 documentation 说:

运行混合应用后,您可以开始逐步升级代码。一种更常见的模式是在 AngularJS 上下文中使用 Angular 组件。这可能是一个全新的组件,也可能是以前的 AngularJS 但已为 Angular 重写的组件。

因此,由于我的旧应用程序是用 angularjs 编写的,因此该框架将始终包含我的根应用程序,并且还将成为我所有未来功能的包装器。因此,如果有一天我决定在 Angular 8 中编写一个新组件,该组件将存在于 angularjs 中,并且它会被降级以使其能够工作。

【讨论】:

    【解决方案2】:

    隔离您的 Angular 1 代码和 Angular 8 代码

    <body>
      <app-root></app-root>
    <div ng-controller="MyController">
      <hero-list></hero-list>
    </div>
    </body>
    

    【讨论】:

    • 你好@dota2pro,谢谢你的评论,英雄之旅是一个基于组件的应用程序,所以你的方法是不可能的。即使我将一个特定的 div 引导为 angularjs 应用程序,而另一个 angular 8 位于外部(作为隔离方法),这也不起作用。
    • 那么也许您可以创建一个可以更好地解释代码的工作演示
    • 如果你想玩的话,我已经在项目中添加了对 github 的引用:)
    【解决方案3】:

    我遇到了类似的问题,尽管在我的 index.html 中我遇到了这个问题:

    <body>
      <app-root></app-root>
    </body>
    

    我发现通过设置Angular docs for ngUpgrade,顶级组件需要来自Angular.js,而不是来自Angular:

    <body>
      <hero-list></hero-list>
    </body>
    

    【讨论】:

      猜你喜欢
      • 2020-07-21
      • 2018-11-16
      • 2018-06-10
      • 1970-01-01
      • 2018-01-08
      • 2021-01-22
      • 2019-12-27
      • 1970-01-01
      • 2018-10-13
      相关资源
      最近更新 更多