Вступительное слово


В процессе работы над проектом на Angular 2 с использованием карт возникла следующая задача: требуется срендерить свой ангуляровский компонент в стандартный popup leaflet’а. В данной статье динамический рендеринг компонентов будет рассмотрен в разрезе именно этой задачи, однако аналогичным образом можно использовать эту информацию в собственных кейсах.

Постановка задачи


Начальный проект находится по ссылке. Это angular 2+ приложение, к которому подключена библиотека для работ с картой leaflet.js. В MapService есть методы для создания карты, добавления маркеров на неё и центровки на маркерах. MapComponent – компонент для отображения карты. Для сборки проекта используется webpack 2. Если запустить приложение, то перед нами появится карта с маркером, к которому привязан popup следующего вида:

marker.bindPopup(`
    	    <h3>Leaflet PopUp</h1>
	        <p>Some text</p>
	        <p *ngIf="false">Should be deleted from DOM if it was angular component because of ngIf = false<p>
    	`);

Кликнем на него и увидим следующую картину:

Карта с открытым popup

В DOM находится элемент с текстом “Should be deleted from DOM...”, который хотелось бы удалить используя *ngIf, однако в popup просто так нельзя записать код ангуляра, чтобы он тут же заработал. Именно здесь на сцену выходит динамический рендеринг компонентов ангуляра.

Решение задачи


Для начала создадим компонент, который мы хотим динамически рендерить:

@Component({
    selector: 'custom-popup',
    template: require('./custom-popup.component.html')
})
export class CustomPopUpComponent {
	public inputData: any;

	private title: string = 'Angular component';
	private array: Array<string> = ['this', 'array', 'was viewed', 'by', 'ngFor!'];
}

Его template:

<div>
	<h1>{{title}}</h1>
	<p>{{inputData}}</p>
	<p *ngFor="let text of array">{{text}}</p>
	<p *ngIf="false">Should be deleted from DOM if it was angular component because of ngIf = false</p>
</div>

Далее создадим новый сервис dynamic-render.service.ts:

@Injectable()
export class RenderService {

	private componentRef: ComponentRef<any>;

	constructor(private ngZone: NgZone,
	            private injector: Injector,
	            private appRef: ApplicationRef,
	            private componentFactoryResolver: ComponentFactoryResolver) { }

	public attachCustomPopUpsToMap(map: Map) {
		this.ngZone.run(() => {
			map.on("popupopen",
			       (e: any) => {
				       const popup = e.popup;

				       const compFactory = this.componentFactoryResolver.resolveComponentFactory(popup.options.popupComponentType);
				       this.componentRef = compFactory.create(this.injector);

				       this.componentRef.instance.geoObject = popup.options.object;

				       this.appRef.attachView(this.componentRef.hostView);

				       let div = document.createElement('div');
				       div.appendChild(this.componentRef.location.nativeElement);

				       popup.setContent(div);
			       });
		});
	}
}

Так как addListener запускается вне зоны ангуляра, нам нужно самим вручную добавить его туда. Таким образом каждый раз при открытии popup’а вызывается componentFactory, которая создаёт компонент, который мы прокинули в поле options. Далее мы можем с помощью instance этого компонента записать в его поля данные, которые мы так же можем прокинуть в options popup’а. В данном примере мы назначаем полю inputData компонента данные из options.data. Затем создаем div элемент, к которому прикрепляем наш только что созданный компонент и назначаем его в качестве контента popup’у.

Замечание: этот код написан для angular 2.3.0+. Для более ранних версий это решение будет выглядеть следующим образом. Вместо

 this.appRef.attachView(this.componentRef.hostView);

нужно будет написать

if (this.appRef['attachView']) {
	this.appRef['attachView'](this.componentRef.hostView);
	this.componentRef.onDestroy(() => {
		this.appRef['detachView'](this.componentRef.hostView);
	});
}
else {
	this.appRef['registerChangeDetector'](this.componentRef.changeDetectorRef);
	this.componentRef.onDestroy(() => {
		this.appRef['unregisterChangeDetector'](this.componentRef.changeDetectorRef);
	});
}

Запровайдим RenderService в MapModule. Также обязательно нужно добавить в MapModule в declarations и entryComponents наш CustomPopUpComponent. Вызовем renderService и добавим возможность для нашего элемента карты рендерить в popup’ах ангуляровские компоненты, после чего прикрепим к маркеру кастомный компонент:

this.renderService.attachCustomPopUpsToMap(this.mapService.getMap());
let options = {
		    data: 'you can provide here anything you want',
		    popupComponentType: CustomPopUpComponent
	    };
let myPopUp = L.popup(options);
marker.bindPopup(myPopUp);

В поле data прокинем данные для компонента, в popupComponentType – сам компонент. Такую конструкцию можно обернуть в интерфейс для удобства использования, но в рамках данного примера делать этого не будем, статья не об этом. Для корректного отображения немного подправим стили, после чего можно запускать приложение. Кликнув по маркеру, видим, что наш компонент среднерился в popup’е leaflet:

Наш компонент срендерился!

Заключение


Нам удалось значительно расширить функционал стандратных popup’ов leaflet в связке с angular 2+. В качестве бонуса наши компоненты получают анимацию открытия/закрытия, изменение размера при зуме и другие стандартные вещи leaflet.

Исходники проекта, в котором реализовано всё описанное в статье находятся здесь.
Поделиться с друзьями
-->

Комментарии (64)


  1. copal
    20.06.2017 18:57
    +1

    Если в сервисе есть ссылка на представление, значит что-то пошло не так.
    Уже вторая статья о динамическом контенте и о том как не нужно писать с использованием angular.


    1. copal
      20.06.2017 19:11

      И какой умник придумал тип Map? Я не верю в то, что компилятор не умолял переименовать тип, так как в js и ts есть встроенный тип Map…


      1. Fesor
        20.06.2017 23:01
        -2

        есть встроенный тип Map…

        вот только в JS типы существуют в своей области видимости и вы вполне можете его переопределить для своего модуля. Не вижу проблемы. Компилятор спокойно разрулит что Map в текущем скоупе это тот Map который мы откуда-то импортировали и ему не на что ругаться. Причем все даже явно.


      1. bodryi
        21.06.2017 10:18

        Тип Map является типом из typings для leaflet. Компилятор ни о чем не умолял. В импортах указано, откуда его брать.


    1. diomas
      20.06.2017 21:28
      +1

      А как делать всякие popup/modal сервисы без ComponentFactoryResolver и ComponentRef? Просто это то, что встречается везде. В каком направлении хотя бы копать?


      1. vintage
        21.06.2017 03:23
        -1

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


      1. s1im
        21.06.2017 08:29

        Навскидку:
        1. Использовать Transclusion
        2. Использовать вторичные роуты (якоря на заголовки на странице глючат, поэтом если вас перекинет не туда, сделайте поиск по странице: «Displaying multiple routes in named outlets»).


        1. diomas
          21.06.2017 15:59

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


          А как быть без ComponentFactoryResolver если мы, скажем, передаем компоненту-таблице класс для отображения содержимого ячеек?


          Я пробовал вариант с вынесенными шаблонами через ngTemplateOutlet но это выглядит очень громоздко


          1. raveclassic
            21.06.2017 17:35

            есть еще *ngComponentOutlet, которая просто это все инкапсулирует


            1. diomas
              21.06.2017 21:11

              ух ты… спасибо, не знал


    1. bodryi
      21.06.2017 11:09

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


  1. raveclassic
    20.06.2017 19:34
    +3

    А почему не стали использовать более более подходящий для этого ViewContainerRef#createComponent?

    А вообще, я не знаю, плакать мне или смеяться, столько геморроя из-за такой простейшей фичи… С кучей ограничений — компонент нужно явно указать в entryComponents, в сервисе вы обязаны знать про интерфейс компонента, чтобы руками насовать ему инпутов, про аутпуты я вообще молчу, ручные подписки/отписки выглядят как заклинания по призыву дьявола. И все ради того, чтобы не писать на одной библиотеке для ui, ей богу, мир сошел с ума.


    1. bodryi
      21.06.2017 11:21

      Для того, чтобы использовать ViewContainerRef#createComponent, нужно написать что-то вроде

      @ViewChild('foo', {read: ViewContainerRef}) foo;
      

      В этой статье мы хотим рендерить компоненты в popup'ах, следовательно на его контейнер нужно сослаться. Сделать этого не вижу возможности, если Вы поможете, буду только благодарен!


      1. raveclassic
        21.06.2017 12:58

        Ну мне кажется, в наглую лезть в чужую DOM-ноду — это перебор…
        Я пошел таким путем: попап явно умеет рендерить в нужное место у себя в шаблоне некий темплейт/компонент. Есть сервис со стримом этих компонентов, который используется в попапе. Собственно дальше понятно — инжектим сервис и пушим в стрим там, где надо.


  1. Dimash2
    20.06.2017 23:10

    Не знаю, стоит ли этот труд времени, на яваскрипте классикой такое запрограммировать легко, я это выношу в отдельные библиотеки, не сервисы, которые потом использую и в ember и в Angular

    Я считаю, что основная задача Фрейворка — дать структуру и порядок, а писать совсем все под фрейворк — не благодарная работа — во-первых производительность спорная (так же поступали с Ангуляр 1, а он вообще дикий тормоз тех годов), так они все еще так быстро меняются

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


    1. Fesor
      20.06.2017 23:18

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

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


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


      1. Dimash2
        20.06.2017 23:23

        Я не путаю, просто в компонент можно поместить простую логику, если за компонент брать какой-то блок, например, блок радиального графика количества заданий, не обязательно же график весь переносить на ангуляр, шаблон отдельные сделали — подключили как компонент — в итоге можно подключать куда и когда угодно, но внутри трудится старичок jquery с популярной библиотекой и простейшей анимацией.

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


        1. Dimash2
          20.06.2017 23:29
          +1

          Добавлю, вот вы трудитесь на большой проект впервые и последний раз? (Риторический вопрос), Ангуляр уйдет из бизнеса, а Javascript останется и где унификация разработки? Фреймворки меняются так быстро, как мода, и это даже просто стильно, а бизнесу надо CRM делать не за 2 месяца, а за 2 недели, а с подобными подходами — вылизывать код под фреймворк, чтобы было красиво — далеко не уплывешь, теперь надо все сидеть и вылизывать под Vue? )

          — PS. Вы же не впервые работаете с картой, я обычно говорю «Ну сколько можно делать одно и тоже уже 10 лет» )))))

          — на яваскрипте классикой такое запрограммировать легко
          не путайте «легко» и «просто». Вопрос масштабов.

          Вообще как-то не в тему, я разве говорил писать кашей колбасу? Разве при помощи js нельзя все сделать красиво через классы, методы и тд… Тем более, внутри компонента


          1. Fesor
            20.06.2017 23:52

            Фреймворки меняются так быстро, как мода

            Вот с 2012-ого года я особо изменений кардинальных не заметил. Есть изменения в деталях реализации, суть и идеи остаются теми же. В целом же больше имеет место цикличность.


            Тут проблема в другом. Много хайпа. И этот хайп забивает людям голову. И они серьезно думают что "есть разница" на чем писать. Мало анализа, много "веры".


            а бизнесу надо CRM делать не за 2 месяца, а за 2 недели

            angular + material и будет сделано. Хотя я понимаю о чем вы. У меня был опыт сотрудничества с разработчиками которые эти 2 недели только webpack настраивали. Сотрудничество завершилось печально. Так же есть интересные метрики когда два разработчика делали задачи схожие по 24 часа, и еще один разработчик ту же задачу делал на тех же инструментах за 4 часа.


            То есть повторюсь, возможно проблема в головах?


            вылизывать код под фреймворк

            это называется "пилить интеграцию". Представьте на секундочку что у нас вообще нет фреймворка, или мы используем сферический в вакууме фреймворк. И для решения конкретной задачи мы нашли какую-то библиотечку на github. Выглядит она слегка заброшенной и написана криво, но задачу с большего решает. Что вы выберите:


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

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


            Разве при помощи js нельзя все сделать красиво через классы, методы и тд…

            в js нет классов. Но это все лирика. Я плохо понимаю вашу позицию. Вы предлагаете отказаться от фреймворков вообще? Предлагаете делать дикий микс из angular и jquery без явного разделения и изоляции?


            Как по мне — разработчики нынче плохо понимают идеи разделения ответственности, декомпозиции, не знают принципов проектирования, ведутся на хайп и все такое. Буквально недавно смотрел код одной команды, которая пилит проект на react. С таким пафосом они накидывали на то что angular это что-то плохое, а react это просто чудо из чудес, а потом другие ребята после них убирали тонны дублирования логики и выносили бизнес логику из UI компонентов.


            1. raveclassic
              21.06.2017 00:04

              С таким пафосом они накидывали на то что angular это что-то плохое, а react это просто чудо из чудес, а потом другие ребята после них убирали тонны дублирования логики и выносили бизнес логику из UI компонентов.
              С таким же пафосом и с пеной у рта просто все наперебой поют баллады «ангуляр для энтерпрайза!», «ангуляр для больших проектов!», «разделение ответственности!», «реакт для хипстеров ничего не может!»
              На выходе тот же говнокод, только на ровном месте в 10 раз сложнее.
              Вы абсолютно правы насчет голов, но не правы, что абсолютно все ведутся на хайп. Разные инструменты по-разному неудачно подходят к разным задачам.


              1. Fesor
                21.06.2017 00:26

                На выходе тот же говнокод, только на ровном месте в 10 раз сложнее.

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


                что абсолютно все ведутся на хайп.

                в каком конкретно месте у меня была фраза "абсолютно все"?


                Разные инструменты по-разному неудачно подходят к разным задачам.

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


              1. vintage
                21.06.2017 03:59

                Такое ощущение, что кроме Ангуляра и Реакта выбирать больше не из чего.


                1. raveclassic
                  21.06.2017 11:15
                  +1

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


                  1. vintage
                    21.06.2017 12:57

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


                    1. raveclassic
                      21.06.2017 13:37
                      +1

                      Вот не надо, так можно про что угодно.
                      Реакт — это тот самый случай, когда модульность. Прям как у вас в $mol. Только вендоры разные, что ничего не меняет, так как ядро все-равно с «охватом и поддержкой», чего не скажешь о зоопарке всякой лабуды, появляющейся тут и там каждый день.


                      1. vintage
                        21.06.2017 19:40

                        Вот не надо, так можно про что угодно.

                        Про высокоуровневый фреймворк ($mol, ExtJS, SAPUI5 и тп) вы такого сказать не сможете, ибо он содержит всё необходимое для создания приложения, а не только базовый каркас. Ангуляр — низкоуровневый. Реакт — вообще шаблонизатор.


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

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


                        1. copal
                          21.06.2017 20:08

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

                          Но безумно говорить что фотошоп(чудо фраймворки будущего) лучше ангуляра или реакта. Реакт, нормальный и ангуляр тоже годный.
                          слегкостью
                          А на мол или эксджеес я смогу написать онлайн фотошоп или текстовый квест или интерактивный сайт или может быть я смогу с легкостью написать конструктор?


                          1. vintage
                            22.06.2017 08:32

                            Сможете, почему нет? Разве что для рисования надо бы батареек завести.


                            1. copal
                              22.06.2017 10:33

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


                              1. vintage
                                22.06.2017 18:58

                                Фреймворк низкого уровня предоставляет архитектуру, но не готовые решения на этой архитектуре.


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


                                Например, Ionic — высокоуровневый фреймворк на базе низкоуровневого Angular.


                            1. copal
                              22.06.2017 12:56

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

                              Это я к тому, что если Вы и хотите вставить красное словцо, то хотя бы объясняйте что это значит, чтобы читающие Вас поняли. В js нет понятия батарейка.

                              И это я к чему… Если на gui я могу наложить некие правила, которые ограничат мою архитектурную фантазию, то это самое правило касается и батареек-логики? Просто я могу представить, что gui реально можно вогнать в некие рамки, но с архитектурой логики это просто не возможно. Единственно возможный вариант, это введение плагинов-фасадов, за которыми будет скрываться такая архитектура на которую способен программист.

                              Но разве это не будет низкоуровнево? разве такое направление не породит армию инвалидов, которым будет лень даже думать?


                              1. Fesor
                                22.06.2017 15:14

                                В js нет понятия батарейка.

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


                                1. copal
                                  22.06.2017 16:27

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


                                1. copal
                                  22.06.2017 16:43

                                  А вообще я не понимаю, как можно ругать react и angular и не ругать сам js, да и все остальные языки, так как реально крутого, лично я ничего не знаю. Я смог приспособится и к react, react+redux, react+mobx и а angular. И при все этом я только раз на реакте на js писал, а затем перешел на ts и могу сказать, что кода нужно писать ну не меньше чем с angular. Только angularjs мне не нравился, но я пробовал его ещё до появления в нем компонентов и именно поэтому перешел на реакт. сообщество только у реакта ненормальное. Оно будет орать что ооп фигня, в то время как ооп сообщества скажет, что есть места где лучше использовать фп. Мне-то пофигу, а вот новичкам они мозг начисто сносят.


                                  1. vintage
                                    22.06.2017 19:11

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


                                    Вы попробуйте к $mol приспособиться, там инфраструктурного кода куда меньше, хоть и на TS :-)


                                    1. copal
                                      22.06.2017 19:23

                                      Какого ещё кода? Вы же говорили что у Вас в mol суперуровень, по сравнению с которым angular кажется низкоуровневым… Если у Вас нужно писать код, то этоуже минимум уровень ангуляра. Вы же понимаете что речь идет о angular, а не о angularjs? Ведь в angular можно вообще без кода писать, если данные статичны, а если нет, то придется руками адрес для запроса записать и сделать это не как лошок в объекте, а как реальный java или c# программист. Даже async в шаблонах пишут.


                                      1. vintage
                                        22.06.2017 20:07

                                        Я вроде бы дал чёткие определения уровней. Зачем вы утрируете?


                                        1. copal
                                          22.06.2017 21:29

                                          Я не утрирую, так как сам дал определение уровня, который выше, чем у angular.
                                          И я повторю, что уровень выше angular, это тот уровень, который принуждает писать только шаблоны и только запросы выполненные в декларативном стиле (например xml или json). Заметьте, нет никакого кода.

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


                              1. vintage
                                22.06.2017 19:07
                                +1

                                Batteries Included (slang), in a product usability (mostly in software) it states that the product comes together with all possible parts required for full usability.


            1. vintage
              21.06.2017 03:58

              Вот с 2012-ого года я особо изменений кардинальных не заметил. Есть изменения в деталях реализации, суть и идеи остаются теми же.

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


              И классы в яваскрипте уже есть :-)


              1. Fesor
                21.06.2017 10:39

                Люди очень не охотно меняют свои привычки

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


                И классы в яваскрипте уже есть :-)

                Ну вы же меня поняли надеюсь?)


                1. vintage
                  21.06.2017 12:52

                  Откуда берутся? Есть куча кардинально других решений, но они не популярны, так как собственно "кардинально другие".


              1. lega
                21.06.2017 13:50

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


                1. vintage
                  21.06.2017 19:41

                  О какой функциональности речь?


                  1. lega
                    22.06.2017 00:31

                    Например нельзя изменить экземпляр до вызова конструктора класса родителя.


                    1. raveclassic
                      22.06.2017 10:46

                      Так это by design. C# вам тоже этого не даст.


                      1. lega
                        22.06.2017 12:30

                        JS весь «by design», вот в python этого ограничения нет.


                        1. raveclassic
                          22.06.2017 14:05

                          Если мне не изменяет память, это потому, что в питоне двух-фазовая инициализация из коробки, и, если вы про __init__, то это на самом деле не конструктор, а инициализатор (initializer), который, по-сути, является обычным методом, вызываемом как раз после конструктора __new__. Вы можете достичь ровно того же в js, введя дополнительный наследуемый метод initialize.


                          1. raveclassic
                            22.06.2017 14:25

                            Перечитал доки, действительно можно вызвать __new__ после какого-то кода. Но этот __new__ является статичным и возвращающим новый объект, так что этот код тоже должен быть статичным.
                            В js/ts/c#/и_ко конструкторы не возвращают значение. Так что возможности ваши при вызове кода до базового конструктора ограничены только статичными полями, и такие трюки возможны только до момента появления class property initializers, так как они происходят как раз в конструкторах. Такое происходит во всех языках, не только в JS.
                            Так что классы как классы.


                            1. vintage
                              22.06.2017 19:21

                              В JS/TS конструктор-таки может возвращать объект, который и будет далее использоваться в качестве this. Именно поэтому нельзя обращаться к this до вызова super.


                              class MyError extends Error {
                                  constructor() {
                                      super()
                                  }
                              }
                              
                              console.log( new MyError() instanceof MyError ) // false

                              class MyError extends Error {
                                  constructor() {
                                      super()
                                      Object.setPrototypeOf( this , MyError.prototype )
                                  }
                              }
                              
                              console.log( new MyError() instanceof MyError ) // true


                              1. raveclassic
                                22.06.2017 20:13

                                А ведь действительно…
                                Ума не приложу, кому это может понадобиться


                          1. lega
                            22.06.2017 15:24

                            Вы можете достичь ровно того же в js, введя дополнительный наследуемый метод initialize.
                            initialize не будет вызываться автоматический и о нем никто не знает (в отличие от конструктора), совсем не ровно тоже, а остальные «оправдания» — просто нюансы реализации.

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


                            1. raveclassic
                              22.06.2017 18:04

                              Вы не уловили суть. Вы не получите «классы как в питоне», потому что питон он «один такой» — конструктор, по сути, статический метод, возвращающий инстанс и вызывающий __init__ уже на инстансе. Вы можете запихнуть кусок кода перед вызовом родительского __new__, но этот код будет так же статическим, отвязанным от инстанса.
                              Во всех остальных языках (конечно же вы меня можете поправить) другая модель, про которую я написал выше. Вы не можете работать с классом до инициализации всей цепочки его базовых конструкторов, и это логично и правильно. Не понимаю, с чего вы решили, что наследование должно обязательно работать априори как в питоне.


                              1. lega
                                22.06.2017 23:54

                                Вы не уловили суть.
                                Вы заблуждаетесь, вы погружаетесь в технические нюансы. На уровне разработчика, это работает в python и ruby (возможно много где), и не работает в js/c# вот и все.
                                Если вам будет легче, можно перефразировать «в js нет автоматической инициализации классов».
                                А правильно/не правильно — это субъективно.


                                1. raveclassic
                                  23.06.2017 00:04

                                  А правильно/не правильно — это субъективно.

                                  Вот мы и подошли к тому, что в js классы как классы, а то, что они не как в питоне — это все субъективно


        1. Fesor
          20.06.2017 23:36

          не обязательно же график весь переносить на ангуляр

          А в этой статье что-то подобное предлагается? я подобного не заметил. Изолируйте старичка jquery в отдельном компоненте и просто предоставьте интеграцию с остальным приложением и ничего страшного.


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


          Я хотел бы обсудить желание все делать нативно

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


          все это рисовалось методами Ангуляра путем напонения массива и его циклом в шаблоне

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


          еще и форсили рендеринг

          не рендринг а запускали $digest цикл возможно?


          считаю, что подобные вещи просто странные.

          Люди очень любят впадать в крайности. А еще есть культ карго. Это не фреймворков вина.


          1. Dimash2
            21.06.2017 00:05
            -1

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

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

            К тому же это тоже лирика, и еще раз, я не говорю, что это все ерунда, я это использую и тоже рулю стейтом, но не всегда это удобно, иногда такая рулежка стейтом приносит вред, а не пользу, все это не всегда «бесплатно»

            Вы ответили на интересующий меня вопрос, вы сказали, что не страшно изолировать старичка — я спокоен, меня волновало отношение к этому вопросу )


            1. Fesor
              21.06.2017 00:35

              что все фрейворки временные

              потому ваша бизнес логика не должна зависеть от фреймворка. А срок жизни UI-ки вашего приложения чаще даже меньше чем срок жизни фреймворка.


              а реально и через 2 года Ангуляр уже будет шататься на своих позициях (он уже шатается).

              То есть мы возвращаемся к теме хайпа вместо выбора инструментов? Ну ок. Да и любопытно почему же он шатается.


              чтобы интерфейс был плавным, а не валился на средне бюджетной сони Xperia )

              Так он и не валится.


              но не всегда это удобно

              ну когда речь о стэйте DOM-а проще сразу DOM-ом рулить, кто ж спорит.


              иногда такая рулежка стейтом приносит вред

              тут стоит конкретизировать что вы имеете ввиду под "такой рулежкой". Любую задачу можно решить как хорошо так и плохо. Фреймворки не особо регламентируют или форсируют определенные решения задач. Тут другой момент, и я помню на себе это прочувствовал лет 5 назад. Читаешь ты такой документацию, все красиво. И вот тебе пример кода где в маленький снипет всунули неплохой кусок логики для демонстрации возможностей. Вот только никто в этой самой доке не дописывал "не делайте так, это лишь для демонстрации, по хорошему вы должны бизнес логику вынести туда-то, взаимодействие с сетью — в отдельную штуку, а вот эта штука с формами — тут можно сделать так и так но это чуть больше кода и сильно усложнит пример".


              А потом открываешь проекты через год и там все те же примеры из доки… размазанные повсюду. Потому что зачем разбираться?


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


              1. vintage
                21.06.2017 04:12
                +1

                Фреймворки не особо регламентируют или форсируют определенные решения задач.

                Низкоуровневые не форсируют. Высокоуровневые ещё как форсируют.


  1. ifynk
    21.06.2017 10:07

    Это будет работать с AOT? Где-то встречал, что Injector не заведется.
    И еще меня мучает такой вопрос. Можно ли с сервера прислать html, в котором будут, например, ссылки с директивой routerLink, отобразить его и заставить работать директивы?


    1. bodryi
      21.06.2017 10:14

      1) Беглым поиском по гуглу нашёл много ссылок на эту тему, все должно работать, единственное что нужно добавить в providers некую вещь, которая поддержит aot.
      2) Думаю, что можно. Первое решение, которое пришло в голову: получаем с сервера html, подкидываем её в компонент, там прикрепляем её к темплейту и динамически создаем этот компонент. Думаю, должно сработать. Скорее всего есть более элегантное решение.


      1. boikovdmitriy
        21.06.2017 12:27

        Можно через templateUrl получить html темплейт и не придется ничего делать для этого специфического)


        1. ifynk
          22.06.2017 16:30

          Насколько я знаю, то динамически в templateUrl нельзя ничего подставить.


      1. ifynk
        22.06.2017 16:29

        А каким образом можно «прикрепить к темплейту»? Я знаю только про InnerHTML.