Как вы используете обновленные компоненты angularjs в модальном модуле ngx-bootstrap?

У меня есть гибридное приложение Angular (Angular 8.2.14 и angularjs 1.8.0), которое использует модальные окна Valor Software ngx-bootstrap (5.3.2). У меня все еще есть несколько компонентов, которые являются angularjs и настолько сложны, что я не могу просто обновить их очень быстро.

Я правильно загрузил свое приложение, чтобы обычно обновленные и пониженные компоненты работали должным образом. Есть один случай, когда этого не происходит, и я думаю, что это из-за того, как BsModalService ngx-bootstrap создает компоненты.

Для 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 может предоставить область видимости.

Кто-нибудь еще преодолел эту проблему? Если да, то как вы это сделали?


person nephiw    schedule 10.12.2020    source источник


Ответы (1)


Похоже, проблема в том, что инжектор UpgradeComponent не может получить родительскую область при попытке обновить компонент. Погружаясь в UpgradeComponent код, мы встречаем этот код:

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
}

Когда я проверил $ ​​parentScope во время его выполнения, я увидел undefined. Интересно, что инжекторы были хороши, поэтому в модуле обновления есть инжектор, и проблема просто в том, что он не может найти родительский прицел.

Все мои компоненты angularjs имеют изолированную область, поэтому мне нужна $ scope, но мне не нужна родительская $ scope. Итак, мое решение - предоставить $scope инжектору в качестве нового экземпляра $rootScope. Это выглядит так:

@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;
}

Я не уверен, что это лучшее решение, но это самое простое решение, которое я мог придумать.

person nephiw    schedule 14.12.2020