Angular: Предложение: Требуется возможность добавлять директивы к элементам хоста в объявлении компонента.

Созданный на 23 мая 2016  ·  114Комментарии  ·  Источник: angular/angular

Я копался в Angular 2 и столкнулся с потенциальным препятствием для расширения определенных видов компонентов.

В следующем примере у меня есть компонент кнопки и директива, которая будет применять стили на основе событий касания. Будет много других объектов, помимо кнопки, которые унаследуют точно такое же поведение касания. Я изучил свои варианты, и я в недоумении:

  • Прямое расширение TouchClass. Это кажется далеко не идеальным, поскольку машинописный текст не поддерживает множественное наследование классов, и я также хотел бы показать поведение потребителям для использования в их собственных классах.
  • Подделка множественного наследования классов через интерфейс. Это похоже на взлом и требует, чтобы я повторно объявил api прокладки для каждого класса, в который я пытаюсь вмешаться. https://www.stevefenton.co.uk/2014/02/TypeScript-Mixins-Part-One/
  • Создайте вспомогательную функцию, которая делает это через службу непосредственно на elementRef.nativeElement в конструкторе компонента. Я действительно не хочу этого делать, поскольку в документации указано, что nativeElement будет иметь значение null при запуске в worker, и эта возможность - это то, что меня больше всего волнует.

Не вдаваясь в подробности, я бы предположил, что componentMetadata доступен во время компиляции компонентов и что свойство хоста можно сканировать на предмет дополнительных директив, которые могут быть добавлены динамически и скомпилированы одновременно. Это позволит вам делать миксины угловым способом: использовать составные директивы для расширения функциональности и делать это без нарушения проекции вида. Краткий пример ниже.

Текущее поведение
Объявление директивы в componentMetadata.host рассматривает ее как обычный атрибут

Ожидаемое / желаемое поведение
Директива, объявленная в host, будет обработана во время компиляции.

/**
 * App
 */
@Component({
    selector: 'app-component',
    template: '<g-btn>TEST</g-btn>',
    directives: [gBtn, gTouch]
})

export class AppComponent {
    constructor() {

    }
}

/**
 * Touch Directive
 * Will be used in lots and lots of components
 */
@Directive({
    selector: '[g-touch]',
    host: { 
        '(touchstart)': '...',
        '(touchend)': '...',
        '(touchmove)': '...',
        '(touchcancel)': '...'
    }
})

export class gTouch {
    constructor() {

    }
}

/**
 * Simple button component
 */
@Component({
    selector: 'g-btn',
    template: '<ng-content></ng-content>',
    host: {
        'role': 'button',
        // WOULD LOVE FOR THIS TO COMPILE THE DIRECTIVE!
        // right now it just adds an attribute called g-touch
        'g-touch': ' ' 
    }
})

export class gBtn {

    constructor() {

    }
}

Некоторые идеи того, как это могло бы работать:

// Option 1: just scan the host properties for directives.
// This would be my ideal, simple and understandable
@Component({
    selector: 'g-btn',
    template: '<ng-content></ng-content>',
    host: {
        'role': 'button',
        'g-touch': true // or {prop: 'foo'} or string
    }
})

// Option 2: definitely more declarative using a hostDirectives property
// more declarative, albeit more annoying to have to reimport the touch class
@Component({
    selector: 'g-btn',
    template: '<ng-content></ng-content>',
    hostDirectives: gTouch,
    host: {
        'role': 'button',
        'g-touch': true
    }
})

// Option 3: declare host directives as its own thing, still just
// use keys pointing to bool, obj, or string
@Component({
    selector: 'g-btn',
    template: '<ng-content></ng-content>',
    hostDirectives: {
        'g-touch': {someOption: someOption}
    },
    host: {
        'role': 'button',
    }
});

// Option 4: Not a huge fan of this one, but understandable if
// people want to keep one host property
@Component({
    selector: 'g-btn',
    template: '<ng-content></ng-content>',
    host: {
        'role': 'button',
        _directives: {
            'g-touch': true
        }
    }
});

Спасибо всем, Angular 2 выглядит великолепно !. Дай мне знать, если что-то мне не хватает.

core directive matching host and host bindings feature

Самый полезный комментарий

@IgorMinar работа Айви делает это более осуществимым. Но да, после v6.

Все 114 Комментарий

В настоящее время я разрабатываю большого клиента и поэтому пытаюсь разбить все проблемы, связанные с графическим интерфейсом, на многоразовые директивы Angular2. Это всегда приводит меня к той же проблеме, как прекрасно указал Джеймс.
Это действительно должно как-то работать ради хорошей модульной и динамической архитектуры. Пример касания - лишь один из многих сценариев, в которых это необходимо. например, перетаскивание, изменение размера наблюдения и т. д. и т. д. и т. д.
Сделал еще один пример как плункер:
https://plnkr.co/edit/J65THEMic0yhObt1LkCu?p=info

Есть ли шанс, что эта функция будет добавлена ​​в ближайшее время?

Вот вопрос StackOverflow, связанный с этим: http://stackoverflow.com/questions/37148080/use-angular2-directive-in-host-of-another-directive

@ Andy1605 Вы когда-нибудь находили способ обойти это? Из-за этого во время RC я вроде как отложил работу с NG2. С удовольствием вернусь к нему, но именно эта проблема мешает мне создавать расширяемые шаблоны пользовательского интерфейса.

Я также чувствую, что в Angular здесь отсутствует важная функция. Компонент должен иметь возможность объявлять (несколько) директив-атрибутов для своего хоста. Неспособность сделать это также является серьезным препятствием для моего проекта.
Кто-нибудь знает, будет ли это реализовано в будущем или есть причины, по которым это невозможно сделать?

Я предложил решение этой проблемы (хотя и для угловой версии 1) здесь: https://github.com/angular/angular.js/issues/15270.

Моя идея состоит в том, что вместо того, чтобы просто добавлять директивы, у инфраструктуры компиляции была бы новая точка расширяемости, называемая "hostTransforms" (в случае angular 1, "nodeTransforms"), которая будет иметь доступ к немодифицированному, неотфильтрованному объявлению компонента. и исходный, некомпилированный узел узла компонента всякий раз, когда компонент впервые встречается компилятором и готовится к вставке в DOM. Таким образом, разработчик может расширить декораторы компонентов с помощью настраиваемых свойств, а затем использовать nodeTransforms для преобразования этих настраиваемых свойств во что-то знакомое фреймворку angular непосредственно перед компиляцией. Примеры см. В цепочке запросов функций.

Я больше знаком с исходным кодом angular, чем с исходным кодом angular 2, поэтому я не уверен, будет ли процесс реализации здесь таким же. Но поскольку это кажется довольно популярным запросом, я бы хотел, чтобы он был реализован в angular 2 и перенесен обратно, или реализован в angularjs и перенесен вперед (это что-то?).

+1

Я должен согласиться, функция, которая позволяет нам добавлять директивы вспомогательных атрибутов к хосту, была бы замечательной. Я знаю, что мог бы использовать такую ​​функцию прямо сейчас, реализуя более «угловатый» способ добавления функциональности перетаскивания в мои компоненты пользовательского интерфейса.

Как насчет создания нового тега, подобного <ng-container> который позволяет применять их в шаблоне компонента вместо свойства метаданных host ? Что-то вроде <ng-host [attributeDirective]> чтобы указать, что директивы добавлены в компонент хоста.

@jjstreet ваше предложение похоже на replace: true (очевидно, не идентично, но похоже), которое некоторое время назад было объявлено устаревшим. Но, возможно, replace: true устарел по причине, которая здесь не применяется.

@ pkozlowski-opensource Можем ли мы получить какой-либо ответ от команды ng2 по этому поводу?

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

+1 эта функция требуется, чтобы иметь чистый и повторно используемый код в компонентах пользовательского интерфейса

+1

Не могли бы мы получить какой-то ответ от команды ng2 по этому поводу? Даже если это просто сказать, что вы не собираетесь этого делать, или сказать, что это хорошая идея, но не текущий приоритет, я просто хотел бы услышать какой-то вклад.

Я хотел бы добавить для этого еще один вариант использования. Это позволит ng2-mobx (https://github.com/500tech/ng2-mobx) избавиться от компонента упаковки и выглядеть намного чище.

Я тоже хотел бы иметь это. В настоящее время мне нужно создать специальную директиву routerLink . Я бы хотел повторно использовать angular и просто предоставить ему параметры, подготовленные директивой mi.

Поэтому вместо <a [routerLink]="repeatedCodeToGetLink()"> меня будет <a [myRouterLink]> и он будет динамически применять [routerLink] с разрешенными параметрами.

Действительно взволнован перспективами этого!

Нам это нужно какое-то время. Фактически, некоторое время назад, прежде чем я узнал, что для этого есть открытая проблема, я спросил о переполнении стека, по существу, об этой самой функции.

Я представил подробный пример того, как мы могли бы использовать эту функцию для решения https://github.com/angular/flex-layout/issues/162, который у нас был открыт некоторое время. ( См. Пример и объяснение здесь )

Мы действительно с нетерпением ждем любых отзывов, я вижу, что эта проблема - третья по популярности среди всех открытых проблем в этом репо. Надеюсь, мы сможем увидеть это в следующем выпуске или раньше (скрестим пальцы)!

/ cc @tbosch @IgorMinar @mhevery @jelbourn @hansl @ThomasBurleson

@jjstreet Думаю, ваше предложение

<ng-host myDirective="foo"></ng-host> 

... хорошо сочетается с другим отдельным предложением, которое было сделано некоторое время назад по другим причинам, чем мы обсуждаем здесь.

См. Https://github.com/angular/angular/issues/7297

В настоящее время я работаю над этим, добавляя директиву в родительский компонент, а затем добавляя слушателя на хосте с помощью @HostListener.

Parent.html
<my-component myDirective>

Component.ts
@HostListener('myEvent') handler() { // do stuff }

Но было бы чище, если бы мы могли добавлять атрибуты прямо в хост ...

Вот как я справлялся с этим, но я действительно думаю, что реализация этой функции с нуля была бы лучшим решением.

Просто ежемесячное напоминание о том, что мы ждем положительных или отрицательных комментариев по этому поводу от команды Angular.

@tbosch - Любые общественные мысли о приоритетности этого вопроса. Это также влияет на @angular/flex-layout .

@fadzic, вы можете не просто добавить директиву к элементу хоста, сделав это ...

Component.ts
@HostBinding('attr.myHilite') myHilite = new myHiliteDirective()

или вот так, если вам нужны такие параметры, как ElementRef или Renderer2
@HostBinding('attr.myHilite') myHilite = new myHiliteDirective(this.elementRef, this.renderer)

Мне также необходимо добавить директиву к элементу хоста, и я был перенаправлен на эту проблему. Я смог сделать то, что мне нужно, используя приведенный выше код. Я никоим образом не являюсь экспертом в использовании angular, но этот обходной путь, похоже, пока работает, если у кого-то возникнут проблемы с этим подходом, дайте мне знать. Спасибо.

@btinoco , который не работает, потому что не вызываются методы жизненного цикла. Вам придется вручную подключать все в каждом компоненте, который использует директиву, а не просто подключать Angular для вас.

@hccampos, спасибо за внимание. Я просто попытался его , и ngOnInit моей директивы не выполнить (если я не использовать директиву в моем компоненте вручную) или я называю директивы ngOnInit() на моей компонента ngOnInit() . Еще раз спасибо, что сообщили мне об этом.

@btinoco - да. это тонкий, но неприятный вопрос. Та, на которую @ angular / flex-layout надеется, скоро будет исправлена. ;-)

Есть новости по этому поводу от команды Angular? С момента открытия выпуска прошел 1 год ...

Было очень круто найти это подробное описание этой проблемы,
тогда не найти обратной связи от команды Angular было супер не круто :(

По поводу уже работающих решений:

Этот запрос функции очень похож на миксины. Фактически, пуля №2 в описании
этой функции действительно соответствует официальному
документацию по TypeScript см. здесь .
В angular это становится немного хуже, поскольку смешивая класс с @Input() s, вы
необходимо повторно объявить их в базовом классе.

Другое решение, которое уже работает сегодня, заключалось бы в том, чтобы компонент содержал элемент-оболочку и применять к нему директивы.
Например, если компонент содержит шаблон вида <wrapper g-touch>...

Относительно «Создать вспомогательную функцию, которая делает это через службу непосредственно на elementRef.nativeElement»:
Да, это тоже кажется хорошей идеей. Меня пока не волнуют WebWorkers,
поскольку они все еще экспериментальны и в них отсутствуют некоторые более важные функции для производства,
и почти никакая библиотека не будет работать с WebWorkers.
См. Также нашу библиотеку материалов, которая имеет прямой доступ к DOM.

Относительно Варианта 1) предложения:

Текущая семантика для привязок свойств хоста:
что они устанавливают свойство myDir в базовом элементе HTML,
но не директивы. Однако, если host также может вводить директивы, пользователи могут написать следующее
и был бы сбит с толку, почему это не обновляет свойство в директиве myDir :

@Component({
  host: {
    '[myDir]': true
  },
  template: '...'
})
class MyComp {}

Относительно Варианта 1) и Варианта 3):
Введение каких-то привязок host между директивами одного и того же элемента может:

  • приводят к циклу в графе привязки данных, который Angular не поддерживает, и, следовательно,
    приводят к трудным для отладки ошибкам из-за устаревших значений / ошибок «Выражение было изменено после проверки».
  • приводят к дополнительным накладным расходам на производительность по сравнению с директивами, вводящими друг друга
    и общение напрямую.

Относительно Варианта 2) предложения:

  • да, обращение к классу gTouch кажется странным, как и все другие директивы
    запускаются через NgModule s.

@ThomasBurleson, давайте поговорим в автономном режиме о вашем

@tbosch Я хотел бы предложить другой вариант: <ng-host> .

Примечание: @mhevery предложил ввести тег <ng-host> в https://github.com/angular/angular/issues/7546 , однако, хотя я использую здесь то же имя тега, что я предложение является отдельным и предназначено специально для решения поднятого здесь вопроса.

Тег ng-host не будет реализован как обычный класс директив / компонентов, а вместо этого будет «волшебным» кодом фреймворка ... похожим на ng-content , ng-container и т. Д. .,
Тег будет просто служить «указателем» на компонентный хост способом, аналогичным селектору css

Это позволяет избежать неоднозначных сценариев, каждому компоненту будет разрешено иметь не более одного блока <ng-host> и он должен быть корневым тегом / узлом шаблона этого компонента.

Вот как это можно было бы использовать:

// Option 5: Use `<ng-host>`.. Very declarative and intuitive
@Component({
  selector: 'g-btn',
  template: `
    <!-- 
      Besides comments, having dom code inside the template but outside of a declared 
      ng-host code block would raise an error (hopefully at compile-time) .
    -->

    <ng-host role="button" g-touch> 
      <ng-content></ng-content>
    </ng-host>
  `
})

Кстати @tbosch , Спасибо, что вообще ответили. Мы очень ценим ваше участие и отзывы по этому вопросу.

Являются ли мысли всех остальных об этой функциональности специфичными для Компонентов, или было бы также иметь смысл, если бы Директива могла применять другую директиву к своему хосту? Вариант использования, который я начал подписываться на эту проблему, включает в себя несколько сторонних директив, которые A) мы хотели изолировать от нашего кода на случай, если мы захотим изменить позже, и B) хотели применить некоторые функции по умолчанию к каждому экземпляру без необходимости дублировать настройку каждый раз, когда мы ее использовали.

Например, директива всплывающей подсказки, которая будет применяться к большому количеству элементов во всем нашем приложении, и мы хотим установить задержку и appendToBody по умолчанию (она не поддерживает централизованный объект конфигурации). Поскольку он не поддерживал центральный объект конфигурации, нам приходилось размещать три или четыре атрибута везде, где мы хотели его использовать. Позже мы отказались от этой библиотеки (начали использовать всплывающие подсказки материалов), и нам пришлось вручную заменять каждую всплывающую подсказку. Если бы мы могли создать нашу собственную директиву, которая «обернула» ее, было бы так же просто, как изменить эту директиву, чтобы применить [mdTooltip] к его хосту вместо другой библиотеки.

@MikeMatusz Похоже, я тоже это имел в виду, вот мой фрагмент с https://github.com/angular/flex-layout/issues/162#issuecomment -290350270.

@Directive({
  selector: 'fxLayoutFullPage',
  hostDirectives: [LayoutDirective],
  host: { 
    'fxLayout': 'column', 
    'style': 'min-height:100vh; background-color:yellow'
  }, 
}) class LayoutFullPageDirective {}

Можно ли создать декоратор свойств, который инстанцирует директиву?
Например:
@HostDirective(LayoutDirective) myLayoutDirective: LayoutDirective;

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

Где это стоит? Я новичок в Angular2 / 4, и я хочу создать директиву, которая просто применяет сразу несколько других директив. Чтобы вместо:

<button directiveA directiveB directiveC>BUTTON TEXT</button>

Я могу просто написать:

<button customDirectiveABC>BUTTON TEXT</button>

По ощущениям это должно быть легко - базовый состав / СУХОСТЬ. Но насколько я могу судить, это невозможно?

@soynog , я чувствую то же самое. Я также хотел бы знать, где это стоит.

Я надеялся, что смогу создавать перетаскиваемые диалоги, используя Angular Material и angular2-draggable (поскольку angular / material # 1206 еще не поддерживается), где я хотел бы динамически добавить директиву к md-dialog-container что MdDialog service создает, но здесь гораздо сложнее получить поведение компилятора Angular 1.x для динамических директив.

@tbosch , @ThomasBurleson , был ли случай автономного использования, который вы обсуждали, связан с проблемами или целями, которые Томас случайно поднял в angular / material # 1206? Я просто пытаюсь осмыслить изменения поведения между фреймворками 1.6.x и 2+.

Есть ли обновления по этой проблеме? Вначале он набирал обороты, но я думаю, что ему больше не уделяют внимания.

Да какие-нибудь новости по этому поводу?

Это то, в чем я так нуждаюсь, надеюсь, это предложение получит признание.

Это было бы хорошо, сегодня я понял, что не могу применять директивы программно / динамически, стало грустно.

+1
Мне то же :)
Я ищу способ обернуть несколько привязок директив в настраиваемую директиву, которая сделает все, что мне нужно. Например :

<my-cmp [myDirective]="content"
        [isOpen]="myCondition"
        customProp2="customClass"
        customProp1="customText">
 ...
</my-cmp>

Было бы неплохо, если бы я мог создать директиву, которая обертывает все эти вещи, чтобы я мог повторно использовать их, не копируя / вставляя все строки.

<my-cmp myCustomDirective>
</my-cmp>

И в мою настраиваемую директиву

<ng-host [myDirective]="content"
        [isOpen]="myCondition"
        customProp2="customClass"
        customProp1="customText">
</ng-host>

Приближается вторая годовщина выпуска этого номера! честно говоря, эта функция будет настолько полезной, что позволит нам создавать компоненты и директивы с высокой степенью компоновки, не создавая миллиона оболочек. просто составьте нужный вам компонент из имеющихся у вас директив. просто, чисто, эффективно.

@IgorMinar - В любом случае, мы можем сделать эту функцию доступной для будущих улучшений?

Я хотел бы знать, будет ли такая особенность считаться плохим шаблоном или нет. Кто угодно?

@darkbasic - AFAIU, без этой функции разработчику потребуется ввести элемент оболочки (на ng-container ) просто для добавления родительских директив в представление и содержимое шаблона.

Нет, я не думаю, что возможность полностью контролировать свой собственный компонент без использования оберток - это плохой шаблон. Это необходимость.

@bradlygreen есть комментарий?

Эта функция является самым популярным запросом (если не топ-5) среди всех открытых вопросов этого репо ... По всему Интернету мы видим отчеты (подкрепленные эмпирическими данными) об упадке Angular как де-факто фреймворка ... Я думаю одна из движущих сил - это чувство, что сообщество не слышно. Конкурс; vue.js и react, набирают обороты и превзошли angular, потому что даже если они не обязательно реализуют каждую мелочь, которую хочет каждый, они, по крайней мере, обеспечивают постоянную обратную связь по наиболее популярным запрашиваемым элементам. Так неприятно ждать так долго и ничего не слышать ... даже простого «нет, мы не будем этого делать».

(См. Раздел, посвященный Js-фреймворкам "Angular Slips" )

... хотя я думаю, что на некоторые мнения об Angular / Vue / React / ... влияют разные факторы ... эта конкретная функция действительно заслуживает какой-то формы реализации (даже обстоятельства немного сложнее, чем просто решение с простым списком применяемых директив) ... так что конкретная позиция основной команды Angular будет очень кстати ... 🥇

Нет конкретного ETA, но мы работаем над тем, чтобы сделать эту категорию вещей намного проще в рендерере в 2018 году.

Надеюсь, в 2018 году все станет кардинально лучше. Мы проигрываем

Видеть:

@somombo давно подтвердили, что эта статья - чушь собачья.

Люди, которые действительно знают свое дело, высмеивали автора, и никто из них не воспринимал его всерьез, лайки исходят от реакции, естественно, от фанатов.

Дело в том, что этот вопрос имеет очень низкий приоритет для команды angular, на самом деле это самый низкий из возможных приоритетов.

См. Опубликованный список приоритетов на AngularHQ (ищите номер

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

Если вам небезразлична эта проблема и вы действительно хотели бы, чтобы она была реализована, то вместо того, чтобы ждать ... ну, честно говоря, _потенциально никогда_, возможно, вы можете заполнить Официальный ежегодный угловой опрос и дать понять, что вы чувствуете, что эта проблема. должен быть более приоритетным и был бы признателен за его заполнение раньше, чем позже.

Не забудьте поблагодарить нашу команду Angular за проделанную ими большую работу!

Я также хочу проголосовать за эту функцию. Это было причиной слишком многих попыток обойти эту проблему.

@somombo, пожалуйста, не

Это не запрос на быстрое исправление. Я подозреваю, что для того, чтобы сделать это должным образом, потребуются значительные усилия, но то, над чем мы работаем для v6, должно значительно упростить реализацию этого.

@IgorMinar работа Айви делает это более осуществимым. Но да, после v6.

@IgorMinar и @mhevery Я не могу не подчеркнуть, насколько я благодарен (и всем нам тоже, я уверен) за то, что вы дали нам конкретный отзыв о своих мыслях и о том, что должно произойти в первую очередь, прежде чем можно будет решить эту проблему. быть должным образом рассмотрено.

Нам, неспециалистам, не всегда ясно, что такое «быстрое решение», а что нет. Однако, не считая того факта, что это нельзя быстро исправить и что все должно быть сделано правильно, я особенно признателен за то, что, похоже, вы также чувствуете, что это будет полезная функция для angular.

Мы знаем, что вы оба очень заняты и не можете так ответить на каждую проблему.
Так что вы всегда испытываете нашу искреннюю благодарность. Мы взволнованы и с нетерпением ждем выхода angular v6 и последующих версий!

Спасибо за отличную работу!

Вы можете расширить свой класс компонента или реализовать класс директивы. Если вы пытаетесь применить директиву под капотом, то, вероятно, это должна быть просто логика в компоненте.

export class gBtn extends gTouch

@NateMay , что позволяет расширить только один класс. Эта проблема больше касается композиции нескольких частей функциональности с помощью директив.

@Nate Может возникнуть две проблемы: во-первых, вы можете расширить только один класс, а во-вторых, вы просто нарушили внедрение зависимостей.

Просто добавляю свои два цента. Я создаю многослойный SPA с угловой, материальной и гибкой компоновкой, используя вложенные состояния @ uirouter / angular. Тогда невозможность легко применить директивы flex к элементам компонентов очень ограничивает.

Так что проголосуйте за эту функцию, пожалуйста.

+1 за эту добавленную функцию

Можно добавить директиву к ng-container , которая не будет отображаться в DOM.

Мне это было нужно для API-интерфейса наблюдателя пересечения (который вызывает события, когда элементы входят / выходят из области просмотра). У меня есть директива intersector , в которой есть события enter() и leave() когда элемент становится видимым / скрытым. У меня есть определенные компоненты, которым необходимо использовать этот API внутри, но я не хотел добавлять дополнительный DIV в шаблон.

В component.html я сделал следующее:

<ng-container intersector (enter)="weCameOnScreen()" (leave)="byeBye()">
     ... components normal template ...
</ng-container>

Затем конструктор директивы intersector.directive.ts вводит ElementRef .

    constructor(private intersectorElementRef: ElementRef) { ... }

Для обычного элемента DOM вы просто оперируете intersectorElementRef.nativeElement , но для ng-container узел фактически является узлом комментария. Поэтому я просто проверяю, не является ли это комментарием, и если да, то поднимаюсь на уровень выше.

public ngAfterViewInit(): void 
{
    // if the directive is applied to an ng-container must go a level up
    this.domElement = (this.intersectorElementRef.nativeElement.nodeType == 8) ? this.intersectorElementRef.nativeElement.parentElement : this.intersectorElementRef.nativeElement;

   registerIntersector(this.domElement ...);

Это не сработает для всех ситуаций, но пока меня это устраивает. Я считаю, что в компиляторе IVY они могут больше не использовать комментарии - так что это может сломаться. Важным моментом было то, что у меня есть единственная директива, которую я могу использовать на узлах DOM или в том, что фактически является подделкой ' @HostBinding ' для директивы.

Я действительно надеялся, что можно будет добавлять директивы динамически. Я хочу иметь возможность инкапсулировать директивы более низкого уровня в директивы «более высокого порядка», более абстрактные. Я задал следующий вопрос о переполнении стека, и мне было интересно, будет ли решение для этого в будущем: https://stackoverflow.com/questions/51608645/abstract-away-leaflet-directive-in-custom-directive

как сказал @mhevery .. нам нужно напомнить команде, насколько важна для нас эта функция, чтобы они о ней не забывали 😉

Подписка на это. Мне также нужно иметь возможность динамически прикреплять директиву к компоненту, который я создал с помощью resolveComponentFactory / createComponent.

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentItem.component);

const componentRef = viewContainerRef.createComponent(componentFactory);
(<DynamicComponent>componentRef.instance).data = componentItem.data;
(<DynamicComponent>componentRef.instance).cssClassList = componentItem.cssClassList;
// Add directive to new component here
// componentRef.addDirective(someDirective)

Любое обновление ???
Я столкнулся с другим вариантом использования, в котором я использую стороннюю директиву.
В некоторых случаях мне нужно динамически удалить / добавить директиву для элемента HTML.
возможно ли это каким-либо образом или еще не принято решение?

@micronyks ... на самом деле невозможно добавить директиву динамически. Мы должны дождаться появления Ivy, который должен добавить возможность создания такой функции.

@ mlc-mlapis, а какие планы, когда появится IVY? в какой версии?

@micronyks ... Angular 7 по расписанию.

Ребята, давайте будем рассудительны, команда Angular изо всех сил старается работать над несколькими огромными функциями, которые очень востребованы (PWA, SSR, Ivy и особенно Custom Elements), последняя из которых имеет очень высокий приоритет, насколько я мог понять, потому что много крупных предприятий (таких как Microsoft) вечно просили об этом, и для этого есть причина. Чтобы достичь эффективных пользовательских элементов, им нужен Ivy, как только они будут работать с Ivy, как сказал упростит использование динамических директив.

Между тем, вместо того, чтобы продолжать требовать эту функцию (которая, кстати, мне безнадежно нужна), мы можем помочь команде Angular ускорить процесс, тестируя бета-версии, сообщая об ошибках, помогая с документами и т. Д.

Давайте вспомним, что команда Angular даже не такая большая, это всего лишь дюжина людей, пытающихся создать отличный фреймворк для всех, но это требует времени.

... да, сейчас необходимо проявить немного терпения и дождаться того момента, когда мы сможем больше помочь с Ivy ... когда компилятор будет завершен и будут доступны некоторые документы по детальному дизайну.

@avatsaev Я согласен со всем, что вы сказали. Вы не должны требовать здесь чего-либо. Но вы можете объяснить проблемы, с которыми сталкиваетесь при работе с Angular.

Я далеко не очень опытный разработчик Angular, но некоторые вещи кажутся неправильными или недостаточно понятными.

Я столкнулся с этой проблемой, потому что хочу инкапсулировать сторонний компонент / директиву без дырявой абстракции. Частично это позволяет иметь динамические директивы. Что меня удивляет, так это то, что добиться этого довольно сложно.

Я создаю генератор форм, используя Angular Material и Flex-Layout, который принимает конфигурацию JSON и генерирует форму. Эта функция поможет мне применить директивы гибкого макета к компоненту хоста во время выполнения. Я чувствую, что одним из самых больших преимуществ Angular является возможность генерировать код во время выполнения из конфигурации, это в значительной степени сделает этот код более универсальным. Просто хотел добавить хороший вариант использования. Нетерпеливый ;)

Это мой точный вариант использования

@NateMay вот моя реализация, если вы хотите ее проверить.

@NateMay вот моя реализация, если вы хотите ее проверить.

не могли бы вы объяснить? Я думаю, вы имеете в виду динамическое поле. Директива

dynamic-field.directive делает необычные вещи, но также происходит много других вещей. Я просто добавил CONTRIBUTING.md в корневую папку, в которой есть инструкции по локальной настройке. Остерегайтесь использования в продуктах, которые производятся в течение пары месяцев. Я вношу большие изменения, работая над стабильной реализацией.

+1

Безусловно, все мои обходные пути имеют недостатки.

  1. has-it , определить новое свойство члена в качестве этой директивы внутри моего класса компонента, передать все необходимые аргументы конструктора в эту директиву при вызове ее функции-конструктора (например, ElementRef, ViewContainerRef, TemplateRef ... любые вводимые переменные, которые он запрашивает) , и вручную вызвать его обратный вызов жизненного цикла, если он есть, например ngInit() ngAfterViewInit() в соответствующей функции обратного вызова жизненного цикла текущего компонента.
@component(...)
class MyComponent {
   theDirective: TargetDirective;
   constructor(el: ElementRef) {
       this.theDirective = new TargeDirective(el);
   }

  ngOnInit() {
     this.theDirective.ngOnInit();
  }
  ...
}
  1. Оберните все в шаблоне компонентов в ng-шаблон верхнего уровня,
    <ng-template><div targetDirective>....</div></ng-template> отобразить их в ngAfterViewInit() как:
const vf = this.viewContainerRef.createEmbeddedView(this.templateRef);
vf.detectChanges();

Таким образом, Angular создает еще один element с этой директивой и фактическим содержимым моего компонента внутри него сразу после исходного элемента компонента в дереве DOM.

<my-component></my-component>
<div targetDirective>....</div>

Этот способ похож на то, что делает <route-outlet> .

Есть очевидные побочные эффекты

Может ли кто-нибудь подтвердить, возможно ли это теперь с Ivy? Если да, то есть у кого-нибудь пример?

Давайте вспомним, что команда Angular даже не такая большая, это всего лишь дюжина людей, пытающихся создать отличный фреймворк для всех, но это требует времени.

Это могло бы быть больше, если бы у нас было сообщество участников.

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

Так что вместо этого мы вернулись к десятку человек.

Может ли кто-нибудь подтвердить, возможно ли это теперь с Ivy? Если да, то есть у кого-нибудь пример?

Поскольку пока нет ни слова, я подумал, что предоставлю самое близкое, что я смог найти, это недавняя статья о реализации миксинов с Ivy: https://blog.nrwl.io/metaprogramming-higher-order-components -and-mixins-с-angular-ivy-75748fcbc310

Согласно статье, я думаю, что возможным решением исходной проблемы этой ветки является использование новой функции под названием ... «функции».

... Вы можете себе представить, что пытаться загуглить что-нибудь об этой функции - это настоящий кошмар. Надеемся, что скоро они выпустят официальную документацию по Ivy! :)

@nayfin также
И после нескольких месяцев работы над тем, чтобы застрять на самом деле, у меня нет возможности развернуть директиву для динамически добавляемого div, меня сводит с ума .... Должно быть так, чтобы не обращать внимания на вызов некоторого MyDirectiveFactory :: apply (HTMLElement)

Эта функция будет очень приветствоваться, поскольку я всегда делаю один div для присоединения директив верхнего уровня. Кроме того, если мне нужны какие-либо директивы гибкого макета, я также должен сделать этот одноразовый div, и было бы неплохо, если бы я мог прикрепить их непосредственно к элементу хоста, вместо того, чтобы делать это.

Было бы здорово иметь возможность динамически добавлять директивы, например:

const msked = componentFactory.createDirective(MaskedInputDirective);
msked.textMaskConfig = {};
this.elementRef.directives.add(msked);

Кроме того, если мне нужны какие-либо директивы гибкого макета, я также должен сделать этот одноразовый div, и было бы неплохо, если бы я мог прикрепить их непосредственно к элементу хоста, вместо того, чтобы делать это.

@tsteuwer Вы всегда можете просто использовать селектор: host в своем scss, чтобы применить свойства стиля к элементу host.

Но да, я также хотел бы иметь возможность применять директивы к элементу хоста. Было бы полезно сделать элемент хоста прокручиваемым и применить CdkScrollable из Angular Material CDK.

Оберните все в шаблоне компонентов в ng-шаблоне верхнего уровня

Немного более приятная альтернатива этому - использовать https://github.com/trotyl/angular-contrib и добавить

host: { ngNoHost: '' }

Этот проект прокладывает средство визуализации и отображает дочерние элементы элементов с атрибутом ngNoHost без родительского элемента.

Конечно, у него много тех же недостатков.

Жаль, что это все еще открыто через 3 года. Директивы, привязанные к элементу хоста, действительно улучшат возможность повторного использования кода.

Кроме того, если мне нужны какие-либо директивы гибкого макета, я также должен сделать этот одноразовый div, и было бы неплохо, если бы я мог прикрепить их непосредственно к элементу хоста, вместо того, чтобы делать это.

@tsteuwer Вы всегда можете просто использовать селектор: host в своем scss, чтобы применить свойства стиля к элементу host.

Но да, я также хотел бы иметь возможность применять директивы к элементу хоста. Было бы полезно сделать элемент хоста прокручиваемым и применить CdkScrollable из Angular Material CDK.

Не идеально, но вы можете создать CdkScrollable программно следующим образом:
this.scrollable = новый CdkScrollable (this.elementRef, this.scrollDispatcher, this.zone);
this.scrollable.ngOnInit ();

Его тоже нужно уничтожить вручную:
if (this.scrollable) {
this.scrollable.ngOnDestroy ();
}

https://github.com/angular/angular/issues/8785#issuecomment -361004682 IgorMinar, работа Ivy делает это более осуществимым. Но да, после v6.

@mhevery В полностью приземлился, можем ли мы иметь эту функцию в (или раньше) выпуске v10? Если нет, пожалуйста, сообщите нам, какие еще соображения могут сдерживать это.

Есть какие-то изменения?

Если бы эта конкретная функция была в обзоре Angular https://twitter.com/angular/status/1252646001162088448?s=20 , я уверен, что это была бы запись с наибольшим количеством голосов.

Есть множество функций, которые будут признаны лучшими, это наверняка, но также с использованием Observables для @output и многих других. К сожалению, при нынешних темпах они никогда не будут реализованы.

Бьюсь об заклад, если бы эта конкретная функция была в обзоре Angular, она была бы наиболее популярной.

Отличная идея @princemaple!

Хотя это и не идеально, на самом деле это можно решить в разделе «Дополнительные комментарии» опроса (вопрос 2).
Где написано:

"How else should we improve Angular for you?"

Поэтому в эту возможность, пожалуйста , известно, что вы заботитесь много о наблюдении «Выпуск № 8785» реализованы и решены.

Вот прямая ссылка на опрос:
https://goo.gle/angular-survey-2020

Да прибудет с тобой сила! 🙂

Я тоже боролся с тем, как программно добавлять дополнительные функции к компонентам, и, честно говоря, я думаю, что некоторые из предложений здесь кажутся ЛУЧШИМИ способами решения этих конкретных проблем.

Я поговорил с членами команды angular по поводу этой статьи

Может ли кто-нибудь подтвердить, возможно ли это теперь с Ivy? Если да, то есть у кого-нибудь пример?

Поскольку пока нет ни слова, я подумал, что предоставлю самое близкое, что я смог найти, это недавняя статья о реализации миксинов с Ivy: https://blog.nrwl.io/metaprogramming-higher-order-components -and-mixins-с-angular-ivy-75748fcbc310

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

Я не уверен, что, если существует какая-либо техническая причина, которая мешает нам сделать это, но я думаю, что если бы у нас были возможности для этого, это СРАЗУ улучшило бы мою повседневную работу с angular.

«Мы резко увеличили наши инвестиции в работу с сообществом. За последние три недели количество открытых проблем уменьшилось более чем на 700 проблем по фреймворку, инструментам и компонентам. Мы затронули более 2000 вопросов и планируем в течение следующих нескольких месяцев сделать крупные инвестиции, работая с сообществом, чтобы сделать еще больше ». - @StephenFluin
из анонса Angular 10

Полагаю, это означает, что мы увидим, что эта проблема будет отменена в версии 11? 🤞😏

Есть ли лучший способ «работать с сообществом» (и успокаивать их), чем работать над добавлением одной из их наиболее востребованных функций !? (этот 😉)

Слушай их!

Просто чтобы установить ожидания, то, что вы просите, - это нетривиальный объем работы, и текущие структуры данных на самом деле не предназначены для этого. Так что для поддержки чего-то подобного потребуются серьезные инженерные работы.

@mhevery, чем это отличается от применения их из родительского в шаблоне?

@ k3nsei Необходимо увидеть это с точки зрения NgModule , который на самом деле является ключевым элементом, создающим инфраструктуру для всех ее компонентов.

@ mlc-mlapis У нас есть @HostBinding и @HostListener, поэтому, возможно, @HostDirective будет хорошим выбором для этой функции. Я видел разговоры о том, что Ivy apis поддерживает такие функции.

Для меня ключевым моментом является наличие некоторого API композиции, который позволил бы нам иметь больше разделенных классов с возможностью иметь расширения / черты с многоразовыми ненужными функциями. Например, как выбираемый, расширяемый / сворачиваемый.

@ k3nsei Может быть, но я не уверен, что это не слишком динамично, поэтому менее производительно, чем строго статические структуры.

«Просто чтобы установить ожидания, то, что вы просите, - это нетривиальный объем работы, и текущие структуры данных на самом деле не предназначены для этого. Так что для поддержки чего-то подобного потребуются серьезные инженерные работы». - https://github.com/angular/angular/issues/8785#issuecomment -654391378

Спасибо за своевременный ответ @mhevery.

Я думаю, что буду говорить от имени сообщества, говоря, что мы не упускаем из виду, что это будет очень большой вызов. Если бы это было не так, я уверен, что к настоящему времени мы бы сделали некоторые сторонние библиотеки, которые (каким-то образом) добились этого должным образом. [насколько мне известно, их нет].

Кроме того, само собой разумеется, но, пожалуйста, дайте нам знать, есть ли какие-то низко висящие фрукты (или что-то еще), которые мы можем помочь в этом.

Мы искренне благодарим вас и ценим ваше искреннее общение и надеемся, что продолжим участвовать в диалоге о том, что нам нужно и что реалистично / прагматично добавлять.

Хотя я понимаю, что Айви делает это проще, чем раньше.

@mhevery

@IgorMinar работа Айви делает это более осуществимым. Но да, после v6.

Хотя я понимаю, что Айви делает это проще, чем раньше

Мое новое понимание "проще", но не значит "легко".

Мое новое понимание "проще", но не значит "легко".

Айви: То, на что вы потратили два года, но до сих пор не решает ни одной из самых популярных проблем с Angular.

Айви: То, на что вы потратили два года, но до сих пор не решает ни одной из самых популярных проблем с Angular.

@pauldraper Я полагаю, что наши проблемы не в их «проблемах», поскольку эта конкретная даже не находится на их радаре (см. Дорожную карту https://angular.io/guide/roadmap).

Лично я считаю, что пора мне поискать в другом месте не только проект с открытым исходным кодом, но и проект, на направление которого сообщество (и пользователи) имеют реальное влияние.

@pauldraper Я полагаю, что наши проблемы не в их «проблемах», поскольку эта конкретная даже не находится на их радаре (см. Дорожную карту https://angular.io/guide/roadmap).

@somombo Я разочарован тем фактом, что эта проблема все еще остается открытой после всех этих лет, но я не могу согласиться с вами. Первый пункт в дорожной карте явно касается решения открытых проблем с github. Не имеет смысла перечислять их всех в дорожной карте, не так ли? Этот вопрос является одним из самых upvoted (или самый upvoted) , и я надеюсь , что он будет окончательно решен , взятые.

Первый пункт в дорожной карте явно касается решения открытых проблем с github. Не имеет смысла перечислять их всех в дорожной карте, не так ли? Эта проблема является одной из самых популярных (или самых популярных), и я надеюсь, что она будет наконец решена.

нет, это просто принятие желаемого за действительное, прочтите https://github.com/angular/angular/issues/5689, нет абсолютно никаких указаний на то, что они хотят решать какие-либо из наиболее популярных проблем, кроме «строго типизированных форм» в будущее

@pauldraper Я полагаю, что наши проблемы не в их «проблемах», поскольку эта конкретная даже не находится на их радаре (см. Дорожную карту https://angular.io/guide/roadmap).

@somombo Я разочарован тем фактом, что эта проблема все еще остается открытой после всех этих лет, но я не могу согласиться с вами. Первый пункт в дорожной карте явно касается решения открытых проблем с github. Не имеет смысла перечислять их всех в дорожной карте, не так ли? Этот вопрос является одним из самых upvoted (или самый upvoted) , и я надеюсь , что он будет окончательно решен , взятые.

Тем не менее ... Я закончил ждать ... эта проблема буквально стала для меня огромным препятствием. Так что тот факт, что это даже не планируется на ближайшее время, означает, что мне лично пора двигаться дальше. Удачи всем остальным.

Я бы хотел, чтобы это было переименовано в «Поддержка добавления директив в директивы». Хотя это название может сбивать с толку, я считаю важным, чтобы эта функция работала с директивами, а не ограничивалась компонентами. Другими названиями для функции могут быть «подразумеваемые директивы» или «прикрепленные директивы», что означает, что когда вы используете данный компонент или директиву в шаблоне, он извлекает подразумеваемые / прикрепленные директивы в элементе хоста.

Я хотел этого много раз, в основном потому, что композиция потенциально является более чистой формой повторного использования в Angular по сравнению с наследованием. Наследование может быть неуклюжим, потому что здесь нет множественного наследования, параметры конструктора должны передаваться вниз, и некоторые функции Angular работают при наследовании, а другие необходимо «повторно подключать» в каждом листовом классе.

Я представляю себе «подразумеваемые / прикрепленные директивы», работающие как локальная для компонента или локальная для директив форма создания экземпляра директивы, что приводит к созданию экземпляра директивы в элементе хоста без необходимости наличия селектора директив в разметке шаблона.

Вот пример:

@Directive({
  selector: 'app-popup',
  attachDirectives: [
    FocusAreaDirective
  ]
})
export class PopupDirective {

  // Attached directives can be injected, just like template-declared directives today
  constructor(public focusArea: FocusAreaDirective) {
  }

}

В шаблоне можно использовать свойства @Input() и @Output() присоединенной директивы, а методы жизненного цикла присоединенной директивы должны вызываться как часть жизненного цикла компонента хоста. Присоединенная директива также может быть привязана к элементу хоста. По сути, сегодня она действует точно так же, как директива, объявленная шаблоном, но ее не нужно объявлять в шаблоне.

Я думаю, что эта функция принесет значительную пользу Angular, позволив создать более чистую / простую архитектуру компонентов с помощью композиции директив.

Сегодня у вас есть 2 варианта, если вы хотите повторно использовать аналогичную форму директивы:

  • Требовать, чтобы набор связанных директив всегда объявлялся вместе в разметке шаблона; и обнаруживать и выдавать ошибки, если требуемые директивы отсутствуют в конструкторе. Невозможно потребовать, чтобы необходимые директивы объявлялись в одном элементе. Это беспорядочно с точки зрения создания шаблонов и документации, и не является сильным API или контрактом из-за избыточности, но в остальном не является ужасным.
  • Вручную создайте экземпляры прикрепленных директив внутри директивы хоста и перенаправьте параметры конструктора, свойства @ Input / @Output , привязки хоста и методы жизненного цикла к внутренним директивам. Это хрупкая путаница для авторов компонентов, но ее можно решить с помощью простого набора связанных компонентов. Это намного удобнее для создания шаблонов.

Другими словами, отсутствие этой функции иногда создает ненужный компромисс между чистым + простым использованием компонентов и чистым + простым созданием компонентов.

@johncrim
Обратите внимание, что в реальном мире ваша настраиваемая директива будет иметь входные данные, и вы захотите преобразовать их и передать в качестве входных данных присоединенной директиве. Возможно, это можно сделать с помощью синтаксиса, аналогичного атрибутам host в параметрах декоратора директивы.

@amakhrov : Хороший момент - я исключил

В случаях, когда есть либо конфликты именования, либо проблемы с ясностью именования (чего я бы старался избежать при разработке директив для композиции), или когда входные или выходные данные необходимо преобразовать, с этим можно довольно легко справиться, вставив прикрепленную директиву в родительский элемент. директиве и создайте новые входные или выходные свойства для родительского объекта, которые делегируют присоединенные директивы.

Я исправился.
Эта проблема теперь указана в разделе «Будущее» официальной дорожной карты. См. Https://angular.io/guide/roadmap#support -adding-directives-to-host-elements

Поддержка добавления директив к элементам хоста

Давний запрос функции - добавить возможность добавлять директивы к элементам хоста. Эта функция позволит разработчикам дополнять свои собственные компоненты дополнительным поведением без использования наследования. Проект потребует значительных усилий с точки зрения определения API, семантики и реализации.

Поскольку я только что заметил это, я не уверен, когда он был добавлен, но я признаю, что это отличная новость и значимый и обнадеживающий жест. Я буду скрещивать пальцы.

Спасибо команде за то, что поместили его туда! 🙏🏾

Была ли эта страница полезной?
0 / 5 - 0 рейтинги