Инжектор против ViewContainerRef.injector против ViewContainerRef.parentInjector - PullRequest
0 голосов
/ 12 июня 2018

Предположим, у нас есть следующее:

@Directive({ selector: "[appSome]" })
export class SomeDirective {
    public constructor(
        private viewContainerRef: ViewContainerRef,
        private injector: Injector,
    ) {
      console.log(`injector === viewContainerRef.injector: ${injector === viewContainerRef.injector}`);
      console.log(`injector === viewContainerRef.parentInjector: ${injector === viewContainerRef.parentInjector}`);
      console.log(`viewContainerRef.injector === viewContainerRef.parentInjector: ${viewContainerRef.injector === viewContainerRef.parentInjector}`);
    }
}

В чем разница между этими 3 инжекторами?

  1. this.injector
  2. this.viewContainerRef.injector
  3. this.viewContainerRef.parentInjector

В приведенном выше тесте все они разные.

1 Ответ

0 голосов
/ 12 июня 2018

Прежде всего, Инжектор , который вы получаете в конструкторе, это так называемый Инжектор слияния .

Вот его определение :

class Injector_ implements Injector {
  constructor(private view: ViewData, private elDef: NodeDef|null) {}
  ...
}

Angular просто берет данные о просмотре и определение узла и может создавать экземпляр экземпляра Injector всякий раз, когда этого требует функция createInjector :

export function createInjector(view: ViewData, elDef: NodeDef): Injector {
  return new Injector_(view, elDef);
}

Теперь вернемся кваша директива:

                                 SomeDirective 
                                     |
                                    deps
                               /            \
                        Injector         ViewContainer

Для создания экземпляра директивы Angular разрешает зависимости через выделенную функцию resolDep

export function resolveDep(view, elDef) {
  ...
  case ViewContainerRefTokenKey:
     return asElementData(searchView, elDef.nodeIndex).viewContainer;
  ...
  case InjectorRefTokenKey:
     return createInjector(searchView, elDef);
  ...
}

Предположим, у вас есть такой компонент, как:

@Component({
  selector: 'my-app',
  template: '<h2 appSome>Hello</h2>'
})
export class AppComponent {} 

В этом случае:

                                SomeDirective 
                                     |
                                    deps
                               /               \
                   Injector                      ViewContainer
                      ||                              ||
                      \/                              \/
  resolveDep(AppComponent view, h2 elDef)       resolveDep(AppComponent view, h2 elDef)
                      ||                              ||    
                      \/                              \/   
                 createInjector               viewContainerRef (AppComponent view, h2 elDef)
                                               (created early)
                      ||
                      \/
      new Injector(AppComponent view, h2 elDef)       

ViewContainerRef экземпляр был создан в начале создания узла представления.Так как вам нужен узел ViewContainerRef через DI Angular отмечают h2 со специальным флагом и таким образом он может создать экземпляр ViewContainerRef и для сохранения этого экземпляра в данных узла h2.

if (nodeDef.flags & 16777216 /* EmbeddedViews */) {
   nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData);
}

где createViewContainerData :

export function createViewContainerData(
    view: ViewData, elDef: NodeDef, elData: ElementData): ViewContainerData {
  return new ViewContainerRef_(view, elDef, elData);
}

Итак, что мы имеем здесь: Injector и ViewContainer, которые указывают на то же представление и тот же elDef.

Теперь давайтепосмотрите на ViewContainerRef definition :

class ViewContainerRef_ implements ViewContainerData {
  ...
  constructor(private _view: ViewData, private _elDef: NodeDef, private _data: ElementData) {}
  ...
  get injector(): Injector { return new Injector_(this._view, this._elDef); }

  get parentInjector(): Injector {
    let view = this._view;
    let elDef = this._elDef.parent;
    while (!elDef && view) {
      elDef = viewParentEl(view);
      view = view.parent !;
    }

    return view ? new Injector_(view, elDef) : new Injector_(this._view, null);
  }
  ...
}

Case 1

injector === viewContainerRef.injector  => fail

Поскольку метод getConConererRef.injector создает новый экземпляр Injector с тем жеview и elDef.

Таким образом, верно следующее:

injector.view === viewContainerRef.injector.view
injector.elDef === viewContainerRef.injector.elDef

Случай 2

injector === viewContainerRef.parentInjector => fail

Поскольку метод получения parentInjector получит новый экземпляр Injector с родительским представлением и родительскимelDef.

Родительское представление здесь - это представление хоста, а elDef - my-app.

Случай 3

viewContainerRef.injector === viewContainerRef.parentInjector  => fail

Должно быть очевидно, что они не равны, поскольку указывают на другое представление и на elDef, и создаются с помощью оператора new.


Наконец, вы можете прочитать:

Что вы всегда хотели знать о дереве инъекций угловой зависимости

...