2

我有一个使用 Valor Software 的 ngx-bootstrap (5.3.2) 模式的混合 Angular 应用程序(Angular 8.2.14 和 angularjs 1.8.0)。我仍然有几个组件是 angularjs 并且足够复杂,我不能只是快速升级它们。

我已正确引导我的应用程序,以便通常升级和降级的组件按预期工作。有一种情况不会发生这种情况,我认为这是因为 ngx-bootstrap 的 BsModalService 创建组件的方式。

给定一个具有如下定义的 Angular 组件 TestModal:

@Component({ template: `
  <ng1-component [html]="ng1HtmlContent"></ng1-component>
` })
export class TestModal {
  public ng1HtmlContent: string;
}

还有一个像这样的angularjs组件:

angular.
  module('common').
  directive('ng1Componnent', ng1Component);

ng1Component.$inject = ['$compile'];
function ng1Component ($compile) {
  return {
    restrict: 'E',
    scope: {
      html: '<'
    },
    template: '<div></div>',
    link: function ng1Component (scope, elem) {
      let childScope = null;

      scope.$watch('html', (html) => { 
        if (childScope) {
          childScope.$destroy();
        }

        childScope = scope.$new();
        // There is a lot more here I am just not including.

      });
  }
}

模态显示的代码类似于:

constructor(private readonly bsModalService: BsModalService) {}

public showTest(initialState: Partial<TestModal>): void {
  this.bsModalService.show(TestModal, { initialState });
}

如果我将我的 ng1Component 直接放入 DOM 而不是模态框内,则该组件将按照您的预期呈现。但是,如果在模态中使用 ng1Component 我会收到此错误:

ERROR NullInjectorError: StaticInjectorError(AppModule)[$scope]: 
  StaticInjectorError(Platform: core)[$scope]: 
    NullInjectorError: No provider for $scope!

显然,模态代码没有被插入到 DOM 中正确引导的 ng1Injector 可以提供范围的地方。

有没有其他人克服了这个问题?如果是这样,你是怎么做的?

4

1 回答 1

3

It looks like the problem is that the UpgradeComponent injector can not get the parent scope while attempting to upgrade the component. Diving into the UpgradeComponent code we encounter this code:

function UpgradeComponent(name, elementRef, injector) {
  // ... code removed for brevity

  // We ask for the AngularJS scope from the Angular injector, since
  // we will put the new component scope onto the new injector for each component
  var $parentScope = injector.get($SCOPE);
  this.$componentScope = $parentScope.$new(!!this.directive.scope);

  // ... code removed for brevity
}

When I checked the $parentScope while this is executing I see undefined. Interestingly the injectors were good, so the upgrade module does have the injector and the problem is simply that it can't find the parent scope.

My angularjs components all have isolateScopes, so I need a $scope, but I don't need the parents $scope. So my solution is to provide the $scope to the injector as a new instance off of the $rootScope. This looks like:

@Component({ template: `
  <ng1-component [html]="ng1HtmlContent"></ng1-component>
`,
  providers: [
    {
      deps: ['$injector'],
      provide: '$scope',
      useFactory: ($injector: Injector) => $injector.get('$rootScope').$new()
    }
  ]})
export class TestModal {
  public ng1HtmlContent: string;
}

I am not sure if this is the best solution, but it is the simplest solution I could conceive.

于 2020-12-14T14:22:28.460 回答