Angular: Предложение: входные данные как наблюдаемые

Созданный на 8 дек. 2015  ·  183Комментарии  ·  Источник: angular/angular

Извините, я плохо говорю по-английски.

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

Цель

  • Входные данные родителя и входное свойство ребенка должны быть синхронизированы.
  • Разработчики должны понимать, что входные свойства изменяются асинхронно.

    Предложение

@Component({ selector: "child" })
class Child {
  @Input("input") inputValue: Observable<T>;

  ngOnInit() {
    this.inputValue.map((value)=>...);
  }
}

@Component({
  template: `
  <child [input]="valueToChild"></child>
  `
})
class Parent {
  valueToChild: T;
}

Выше код не работает. В настоящее время, чтобы получить ввод как Observable<T> , я должен написать его, как показано ниже.

@Component({ selector: "child" })
class Child {
  @Input("input") inputValue: Observable<T>
}

@Component({
  template: `
  <child [input]="valueToChild"></child>
  `
})
class Parent {
  valueToChild: Observable<T> = new Observable<T>((observer)=>{
    ...
    observer.next(val);
  });
}

Пример: http://plnkr.co/edit/BWziQygApOezTENdTVp1?p=preview

Это хорошо работает, но не обязательно. Исходные данные родителя - это изначально простые данные.

Думаю, это предложение нас обрадует.

Спасибо.

core inputs / outputs feature Needs Design

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

Уважаемая команда Angular. Пожалуйста, дайте нам что-то, чего мы будем ждать в 2020 году :-)

Также решение @jcomputer - это именно то, что мне нужно. Не большой поклонник другого имени декоратора, но, возможно, можно добавить параметр, аналогичный тому, как @ViewChild имеет { read } . например:

@Input({ observable: true }) 
@Input({ asObservable: true }) 
@Input({ asSubject: true })

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

Привет, @ laco0416, с твоим английским все в порядке, не волнуйся!

Мне очень нравится эта идея, и мы уже обсуждали это раньше. Он также хорошо сочетается с https://github.com/angular/angular/issues/4062 (наблюдение за событиями просмотра) и https://github.com/angular/angular/issues/5467 (наблюдаемые дочерние события от родителей)

Важно помнить, что не все захотят использовать Observables (эти люди упускают из виду!), Поэтому мы должны предоставить варианты для обоих вариантов использования, и поэтому маловероятно, что мы превратим @Input() непосредственно в Observable. Я действительно думаю, что наличие чего-то вроде @ObserveInput() может сработать, и мы обсудим, _после_ когда_ мы отправим бета-версию некоторых из этих более интересных функций, я думаю.

А пока вот базовая (и _ очень_ экспериментальная !!! НЕ делайте этого по-настоящему) реализация этой идеи. Это концептуально то, о чем вы думали? http://plnkr.co/edit/Nvyd9IPBZp9OE2widOcW?p=preview

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

@alexpods я считаю, что идея здесь именно в этом - его _listening_ к изменению входных свойств _as_ Observable, а не выдачи значений вверх по течению, что абсолютно нормально, насколько я понимаю.

@robwormald

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

Спасибо! Я так рада.

Твой @ObserveInput - это именно то, что я хочу!
Кроме того, @Input не имеет критических изменений. Думаю, это очень хорошее решение.

@alexpods Я тоже совсем.

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

Я думаю так же, как Роб.

@ laco0416 Ой , извините за недоразумение. Фраза «если в дочернем компоненте было изменено свойство Input» меня смутила.

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

Я пытался (но до сих пор безуспешно) написать такой декоратор, а потом наткнулся на plunkr @robwormald , который работает почти идеально (но не совсем).

Что меня воодушевило в этом подходе, так это то, что он задействован в ловушке жизненного цикла ngOnChanges .
Я бы хотел увидеть способ отображения _all_ хуков жизненного цикла как Observables, то есть как onChanges$: Observable<{[key: string]: SimpleChange}> , onInit$: Observable<{}> и т. Д.

Наличие всех хуков жизненного цикла, доступных как Observables, поможет мне Rx все ;-)

Есть обновления по этому поводу?

AFAIK, Нет.
@robwormald у вас есть новости?

Я знаю, что это старое, но это было бы здорово! @robwormald Есть что-нибудь об этом?

Я хотел бы предоставить изменение значений свойства @Input как Observable, как это делает декоратор @ObserveInput @robwormald. Не всегда возможно, чтобы родительские компоненты передавали Observables, особенно когда вы переносите существующее (Angular 1) приложение. Однако невозможность «содержать» Observables в одном компоненте значительно усложняет использование мощи и элегантности RxJS.

К сожалению, Роб не шутил, когда сказал не использовать эту версию @ObserveInput . Проблема, с которой я сталкиваюсь, заключается в том, что Observables создаются на «уровне класса» (если эта терминология имеет смысл) и, следовательно, являются общими для всех экземпляров компонента. Очевидно, это никуда не годится. Создание Observables во время создания экземпляра у меня тоже не сработало. Кажется, что Angular неправильно подключает обнаружение изменений в этом случае.

Кому-нибудь удалось лучше реализовать @ObserveInput или есть какие-нибудь новости об официальной поддержке?

@lephyrus Хотя официальный декоратор @ObserveInput был бы очень хорош, он не является строго необходимым для получения Observable изменения значений свойства @Input . Декоратором будет просто очень изящный «сахар».

Уже существует событие жизненного цикла ngOnChanges . Внутри ngOnChanges мы можем использовать rxjs Subject для создания наблюдаемых изменений, то есть:

<strong i="13">@Input</strong> inputString: string;
private Subject<string> inputString$ = new Subject<string>;

ngOnChanges(changes: { [key: string]: SimpleChange }) {
    if (changes.hasOwnProperty('inputString')) {
        this.inputString$.next(changes['inputString'].currentValue);
    }
}

constructor() {
    inputString$.subscribe(x => {
        console.log('inputString is now', x);
    });
}

Или, если вам нужно что-то более многократно используемое, вы можете создать базовый класс, в котором ваш компонент extends :

import { SimpleChange } from '@angular/core';
import { Observable, ConnectableObservable, Observer } from 'rxjs';

export interface TypedSimpleChange<T> {
    previousValue: T;
    currentValue: T;
}

export class ReactiveComponent {
    private changesObserver: Observer<{ [key: string]: SimpleChange }>;
    private changes$: ConnectableObservable<{ [key: string]: SimpleChange }>;

    constructor() {
        this.changes$ = Observable.create((observer: Observer<{ [key: string]: SimpleChange }>) => this.changesObserver = observer).publishReplay(1);
        this.changes$.connect();
    }

    public observeProperty<T>(propertyName: string): Observable<TypedSimpleChange<T>> {
        return this.changes$
            .filter(changes => changes.hasOwnProperty(propertyName))
            .map(changes => changes[propertyName]);
    }

    public observePropertyCurrentValue<T>(propertyName: string): Observable<T> {
        return this.observeProperty<T>(propertyName)
            .map(change => change.currentValue);
    }

    ngOnChanges(changes: { [key: string]: SimpleChange }) {
        this.changesObserver.next(changes);
    }
}

... который можно использовать следующим образом:

@Component({
    ...
})
export class YourComponent extends ReactiveComponent {
    @Input() inputString: string;

    constructor() {
        super();
        this.observePropertyCurrentValue<string>('inputString')
            .subscribe(x => console.log('inputString is now', x));
    }
}

Я использую этот подход, пока не будет доступен официальный декоратор @ObserveInput .

Спасибо, @wmaurer. Ваш ReactiveComponent очень приветствуется, а использование безупречного кода и безопасного набора текста для загрузки - действительно приятно! Важно отметить, что он также хорошо себя ведет при тестировании и по-прежнему позволяет использовать стратегию обнаружения изменений OnPush . Я теперь с радостью жду "официального сахара". (Также я уверен, что кое-что узнаю, когда выясню, почему вам пришлось использовать логику Observable.create() - я еще не нашел времени, чтобы изучить это.) И снова: merci gäll! :подмигивание:

@lephyrus , пожалуйста, gärn gescheh ;-)

Я использовал Observable.create() чтобы получить Observer , чтобы иметь возможность сделать next() . Я мог бы использовать Subject который одновременно является Observable и Observer , но я считаю, что в целом плохая практика «раскрывать» Subject ( Observer ).

@ laco0416 закрыть в пользу https://github.com/angular/angular/issues/13248 ?

@DzmitryShylovich Нет. В этом выпуске предлагается функция только для чтения и управляемая событиями передача данных.

@ObserveInput будет супер круто! : +1:

Спасибо @wmaurer за хороший пример. Но у меня есть один вопрос. Я хотел бы иметь возможность использовать объект вместо строки в качестве наблюдаемого.

Например

@Input() chartConfig: ChartConfig;

constructor(private _reportService: ReportService) {
        super();
             this.observePropertyCurrentValue<string>('chartConfig')
            .subscribe(changedConfig => this.updateChart(changedConfig));
 }

export class ChartConfig {
    public id: string;
    public type: any;
    public data: any;
    public labels: any;
}

Однако this.updateChart и ngOnChanges не вызываются. Как можно расширить образец из простой строки, чтобы вместо этого наблюдать за объектом?

@ChrisWorks также должен работать с объектами:

this.observePropertyCurrentValue<ChartConfig>('chartConfig')
            .subscribe(changedConfig => console.log(changedConfig));

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

Привет @wmaurer , спасибо за ответ. Сможете ли вы расширить свой образец рабочей версией, в которой вы используете объект «config»? Я просто не могу заставить свою работать. Образец репозитория Git? :)

@ChrisWorks, он действительно должен работать так, как есть. observePropertyCurrentValue не делает различий между строковым вводом и объектом.
Вот действительно старый проект ng2 beta 0, который я сделал, где входные данные бывают разных типов, а не только строки:
https://github.com/wmaurer/todomvc-ng2-reactive
например https://github.com/wmaurer/todomvc-ng2-reactive/blob/master/src/app/todo-item/todo-item.component.ts

+1 Такой фундаментальный вариант использования, не могу поверить, что он еще не рассортирован!

Наконец-то у меня есть лучшее решение, оно работает без повторов и с компиляцией AOT :) Секрет в том, чтобы объединить @Input() со вторым декоратором.

Декоратор:

import { ReplaySubject } from 'rxjs/ReplaySubject'                                                                                                 

const subjects = new WeakMap()                                                                                                                     

export function ObservableInput() {                                                                                                
  return (target, propertyKey) => {                                                                                                                
    delete target[propertyKey]                                                                                                                     

    Object.defineProperty(target, propertyKey, {                                                                                                   
      set(value) {                                                                                                                                 
        this[propertyKey].next(value)                                                                                                              
      },                                                                                                                                                                                                                            
      get() {                                                                                                                                      
        let subject = subjects.get(this)                                                                                                           
        if (! subject)  {                                                                                                                          
          subject = new ReplaySubject<any>(1)                                                                                                      
          subjects.set(this, subject)                                                                                                              
        }                                                                                                                                          
        return subject                                                                                                                             
      },                                                                                                                                           
    })                                                                                                                                             
  }                                                                                                                                                
}                                                                                                                                                  

Использование:

class SomeComponent {
  @Input() @ObservableInput()                                                                                                                    
  public index: Observable<number>
}                                                                                                               

РЕДАКТИРОВАТЬ: Теперь я сделал это библиотекой. Рад получать идеи по его улучшению. Добавление нового метода, который дополняет существующий @Input с Observable next. См. Https://github.com/ohjames/observable-input

Если бы мне пришлось сделать что-то подобное, я бы предпочел использовать один аналог Subject для ngOnChanges: Subject<SimpleChanges>
Вы по-прежнему можете фильтровать и отображать только один конкретный ввод, если хотите.

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

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

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

changes$ пропускает интерфейс BehaviorSubject к компоненту, в идеале он должен быть набран как Observable<...> , в остальном это кажется разумным, хотя и немного более подробным.

Что касается проблемы многих тем ... используете ли вы n subject или 1 вас все еще есть подписки на n . Когда у вас есть 1 объект, вы в конечном итоге добавляете один оператор карты и один оператор фильтра к каждой подписке, накладные расходы на производительность при этом будут не намного меньше, чем при простом использовании n субъектов, это может быть даже хуже.

Игнорируя типизацию самих входных параметров, версия на основе декоратора предоставляет потребителям наблюдаемых более безопасный по типу API, чем типы SimpleChange основанные на any .

@ohjames

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

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

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

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

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

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

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

Вот еще раз ссылка: https://stackblitz.com/edit/angular-observableinput?file=observablechanges%2Fimpl.ts

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

Хорошо, я понимаю вашу точку зрения, завершение наблюдаемых приведет к закрытию всех подписок, но это не то, что меня действительно беспокоит. В нашем приложении 99% подписок происходят через асинхронный канал, и в некоторых из них не нужно закрывать вручную, так как они часто исходят из внешних наблюдаемых источников, полученных из Redux / etc черезcommonLatest / switchMap.

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

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

~ Также использование вашего класса через наследование не будет работать, код, сгенерированный компилятором AOT, не вызывает методы жизненного цикла в родительских классах, см. Https://github.com/angular/angular/issues/12756#issuecomment -260804139, вы нужно добавить ngOnDestroy() { super.ngOnDestroy() } и еще один для ngOnChanges всем потребителям класса. ~ <- похоже, было исправлено в Angular 4.4 с некоторыми ограничениями.

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

Итак, я думаю, что мое предыдущее утверждение в порядке:

Я использую не BehaviorSubject, а простой Subject, потому что я вижу эти Observable не как держатели значений, а как изменения с течением времени. Если вам нужен доступ к входному значению, свойство все еще существует, и вы можете ссылаться на него синхронно.

Этот код в высшей степени экспериментален, это просто своего рода poc, и я играл с ним только на этом stackblitz.
Так что мне не следовало говорить, что это было довольно безопасно, извините, и это может не работать с AOT, как вы заявили.
Просто попробовал, и оба подхода в настоящее время работают с AOT (angular v4.3.6, cli v1.4.1).

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

Также существует только 1 объект для управления реализацией и 1 свойство для использования пользователем по сравнению с 1 для каждого входа.

То, что я мог бы изменить, - это просто испускать новые значения, а не объект SimpleChanges поскольку пользователь, вероятно, может использовать pair и map для получения такой же структуры, как SimpleChange . Но в настоящее время у нас есть SimpleChanges поэтому было бы глупо разбирать его, чтобы потом перекомпоновать что-то подобное.

PS:

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

недействителен для вас .

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

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

Вот версия с разными недостатками и преимуществами, но для нее требуется базовый класс:

import { OnChanges, OnDestroy, SimpleChanges } from '@angular/core'
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/distinctUntilChanged'

export class ChangeObserver implements OnChanges, OnDestroy {
  protected ngChanges = new BehaviorSubject<object>({})

  ngOnChanges(changes: SimpleChanges) {
    const props = { ...this.ngChanges.value }
    for (const propName in changes) {
      props[propName] = changes[propName].currentValue
    }
    this.ngChanges.next(props)
  }

  ngOnDestroy() {
    this.ngChanges.complete()
  }

  changes<K extends keyof this>(key: K): Observable<this[K]>
  changes<V>(key: string): Observable<V>
  changes(key: string) {
    return this.ngChanges.map(props => this.ngChanges.value[key]).distinctUntilChanged()
  }
}

и использовать:

class MyComponent extends ChangeObserver {
  @Input() public field: string
  // typescript knows this is Observable<string>
  field$ = this.changes('field')

  @Input() private privField: number
  // typescript can't access private stuff from outside the class so we need to help it out
  privField$ = this.changes<number>('privField')
}

Не уверен, что я неправильно понял проблему, но разве асинхронный канал не решает эту проблему?
[inputVar]="observableValue | async" ..

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

@ohjames в моем случае, он работал с использованием async pipe для наблюдаемого. И когда я обновляю наблюдаемое значение от родителя, значение отражается в дочернем компоненте.

@najibla эта проблема с github @Input в наблюдаемые, это слабо связано с описываемым вами случаем.

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

@icepeng На самом деле вы не совсем правильно поняли, речь идет о превращении стандартного ввода в наблюдаемое. Итак, новый паттерн на самом деле будет:

<app-child [prop]="prop$ | async"></app-child>

... тогда он предоставляет способ доступа к prop внутри AppChildComponent как к наблюдаемому, даже если он не является наблюдаемым (или если бы он был наблюдаемым, вы бы получили наблюдаемое из наблюдаемых ). Теперь, конечно, если бы у вас было prop$ в первую очередь, как в вашем примере, тогда это могло бы показаться неразумным (вы уже можете просто передать наблюдаемое с входными данными сейчас). Однако он предоставляет большую ценность, когда переданный ввод еще не является наблюдаемым (например, index из ngFor ).

Проблема с передачей наблюдаемого с вводом (что вполне возможно прямо сейчас) заключается в том, что он не будет работать с OnPush .

@fxck Что ж, вы правы, что ngOnChanges не будет вызываться, когда наблюдаемое излучает (потому что входные данные остаются такими же), но до тех пор, пока вы используете асинхронный канал для подписки на наблюдаемое, переданное через @Input затем OnPush будет работать нормально, поскольку асинхронный конвейер вручную запускает детектор изменений дочернего компонента.

Да, это было направлено на @icepeng.

@ohjames @fxck Я не знал, что передача наблюдаемого возможна прямо сейчас, извините за неверную информацию.

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

@icepeng Подумайте об этом:

<ng-container *ngFor="value in (values$ | async); let i = index">
  <child-component [value]="value" [index]="i"></child-component>
</ng-container>

Как сделать здесь index расходным материалом в качестве наблюдаемого, не прыгая через обручи?

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

Есть много других примеров, когда это полезно.

@ohjames index будет статическим значением для каждого child-component , поэтому я не думаю, что это должно быть наблюдаемым. Однако теперь я понимаю, почему людям нужна эта функция. И ваше решение кажется хорошим для написания сторонней библиотеки.

Подход BehaviorSubject кажется лучше, было бы неплохо, если бы ядро ​​Angular предоставило такой декоратор @NgChanges() .

{
  @NgChanges() ngChanges$: BehaviorSubject<{ prop: string }>
  @Input() prop: string;

  ngOnInit() {
    this.ngChanges$.subscribe(changes => console.log(changes.prop));
  }
}

Возможно ли это реализовать?

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

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

мои 2 цента: поскольку object.observe обесценился в пользу прокси, моим решением было расширить прокси (да, вы не можете знать, почему я вернул его из конструктора), а затем прослушать любой ключ, принадлежащий этому объект как Observable с помощью метода $ get (keyName). Вы можете использовать его с любым объектом, а не только с угловым классом.

import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

/**
 * Extends this class to be able to observe any key affectation
 */
class ObservableProxy {
    private changes: Subject<[PropertyKey, any]> = new Subject<[PropertyKey, any]>();

    constructor() {
        return new Proxy(this, {
            set: (object, key, value) => {
                this.changes.next([key, value]);
                object[key] = value;
                return true;
            }
        });
    }

    public $get<K extends keyof this>(key: K): Observable<this[K]> {
        const value: this[K] = this[key];

        const startWith: Observable<this[K]> = Observable.of(value)
            .filter((initialValue) => // remove this filter if you dont mind receiving an undefined value on subscription
                initialValue !== undefined;
            );

        return this.changes
            .filter(([changedKey]) => {
                return changedKey === key;
            })
            .map(([changedKey, nextValue]) => nextValue)
            .merge(startWith);
    }
}

Пример:

class User extends ObservableProxy {
public name: string;
}

const user: User = new User();
user.$get("name").subscribe((value)=> {
console.log(value);
})

user.name = "toto"; // prints console.log("toto")

@robwormald , есть ли какие-нибудь

@bryanrideshark Наилучшие шансы на поддержку этого - через https://github.com/angular/angular/issues/10185 Я думаю, удивлен, что PR не связан с этой проблемой.

Этого не произойдет, пока мы не отправим Ivy
В среду, 21 февраля 2018 г., в 7:56, Джеймс Пайк написал на [email protected] :

@bryanrideshark https://github.com/bryanrideshark Лучший шанс
это поддерживается через # 10185
https://github.com/angular/angular/issues/10185 Думаю, удивило то, что
PR не связан с этой проблемой.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/angular/angular/issues/5689#issuecomment-367372931 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/AAgpkvtGA4w8uHgiz0QsdYwBgqgM2EpAks5tXDyWgaJpZM4Gwr8f
.

Ваш английский великолепен, а ваш угловой больше.

@ pldin601 Ваш метод не поддерживает код, скомпилированный AOT, поэтому приведет к огромным утечкам памяти для производственного кода большинства людей. Вместо этого посмотрите мой пакет observable-input , который хорошо работает с AOT.

@ pldin601 проблема с вашим кодом в том, что он динамически добавляет метод жизненного цикла ngOnDestroy . Скомпилированный код AOT вызывает ngOnDestroy случае, если компилятор может статически сделать вывод о его существовании. Таким образом, ваш метод будет работать только в том случае, если каждый компонент, использующий декоратор, также определяет ngOnDestory (он может быть пустым, если не требуется). Во всех остальных случаях происходит утечка подписок, предотвращая сборку мусора для компонентов.

Я предполагаю, что это произойдет после завершения раздела 3.2 (и, надеюсь, эта необходимость будет учтена)?
https://is-angular-ivy-ready.firebaseapp.com/#/status

Будет ли Ivy частью 7.0.0?

Я реализовал декоратор, который может привязать свойство к наблюдаемому свойству-компаньону. Его можно использовать в свойствах ввода angular, но также и в любом другом свойстве. Он вдохновлен декоратором @ObservableInput() @ohjames , но позволяет избежать возможных проблем, вызванных несоответствием типов между методами получения и установки свойств, за счет использования другого свойства для предоставления Observable.

https://github.com/PSanetra/bind-observable

Пример:

class MyClass {

  @BindObservable()
  public myProp: string = 'initialValue';
  public myProp$!: Observable<string>;

}

const myInstance = new MyClass();

myInstance.myProp$.subscribe(console.log);

myInstance.myProp = 'newValue'

Этот код выводит на консоль значения 'initialValue' и 'newValue' .

Любое обновление о том, когда оно будет выпущено, пока что пакет observable-input кажется наиболее элегантным, ничего не нарушая + без подклассов. @ohjames Насколько это стабильно / хорошо протестировано на данный момент?

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

* без ущерба для совместимости с ненаблюдаемыми входами или необходимости в дополнительном шаблоне для гибридных входов, например: сеттер вызывает следующий по теме

Используется наблюдаемый вход в угловых 4, 5 и 7 с и без aot. Вроде хорошо работает. Я почти уверен, что смутно знал, что делаю, когда писал это.

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

Я предлагаю следующий API для асинхронного ввода с определяемым пользователем observer

decalre function AsyncInput(bindName?:string) : <T extends Observer>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => any

пользователи могут просто использовать его как

@AsyncInput()
asynchronusProperty1 = new Subject();

@AsyncInput()
asynchronusProperty2 = new ReplySubject(1);

@AsyncInput()
asynchronusProperty3 = new UserObserver(); // where UserObserver implement `Observer` interface

Angular internal может просто вызывать observer.next(newValue) при изменении значения.

Не забывайте и о поддержке @HostBinding !

Это должно быть объединено с конструктором @Input Injection, чтобы сделать его еще более крутым. Таким образом мы могли бы очень элегантно исправить "strictPropertyInitialization":

class MyComponent {
  inputData$: Observable<Data>;
  constant: string;

  constructor(
    @Input() inputData$: Observable<Data>,
    @Input() constantString: string
  ) {
    this.inputData$ = inputData$;
    this.constant = constantString;
  }

}

@benneq просто стоит отметить, что он может быть таким маленьким, как:

class MyComponent {
  constructor(
    @Input() private inputData$: Observable<Data>,
    @Input() private constantString: string,
  ) {}
}

@ maxime1992 да, хотя вам понадобится отдельный декоратор для входных данных в качестве наблюдаемых, чтобы различать случаи, когда наблюдаемые объекты передаются от одного компонента к другому.

@benneq @ maxime1992 Имена параметров не являются частью метаданных декоратора, как их сопоставить?

@trotyl Я думаю, вы могли бы тогда использовать @Input('paramName') private myParam: Observable<Data>

@trotyl @benneq да у меня плохо. Неважно: zipper_mouth_face:

Я не знаю, опубликовал ли кто-нибудь это решение, но это довольно хороший обходной путь.

@ElianCordoba Это не про HTML <input> . Речь идет об угловом @Input()

Это другой, но не менее болезненный вопрос @ElianCordoba. https://github.com/angular/angular/issues/13248

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

Это очень похоже на неявное преобразование типов в javascript, может вызывать путаницу, даже вызывать ошибку, и ее трудно найти.

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

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

Плюс это не про тихое преобразование, это API для подписки на изменения через rxjs. Учитывая, что angular.http и маршрутизатор предоставляют наблюдаемые, очень неудобно, что обработка изменений ввода не делает этого, объединение миров обратных вызовов и RxJs требует слишком большого количества шаблонов.

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

@Input('isOuterPanel')
set isOuterPanel(value: CheckoutPanelHeaderSettings)
{
    this.inputs.outerPanel$.next(value);
}

@Input('config')
set config(value: CheckoutPanelHeaderSettings)
{
    this.inputs.config$.next(value);
}

// observables for <strong i="6">@Inputs</strong>
inputs = {
    config$: new BehaviorSubject<CheckoutPanelHeaderSettings>(1),
    outerPanel$: new BehaviorSubject<CheckoutPanelHeaderSettings>(1)
};

Затем вы можете просто поместить что-то вроде combineLatest(this.service.magicInput$, this.inputs, config$)...... для объединения входных данных с RxJS.

Либо BehaviorSubject либо ReplaySubject работает. BehaviorSubject обычно более безопасен и предсказуем.

  • BehaviorSubject - используйте, если у вас есть значения по умолчанию
  • ReplaySubject - наблюдаемый не будет генерировать, если вы забудете установить входное значение

Это не только помогает с ясностью кода, но, поскольку я группирую все входные данные вместе, я могу легко увидеть, что такое «чистый» наблюдаемый вход, просто набрав this.inputs. и получив автозаполнение.


Вы можете пойти дальше с безопасностью типов с этим (в основном это просто для развлечения).

// define this globally to 'unwrap' a property 'inputs' with an object of ReplaySubject / BehaviorSubject
export type InputTypes<T extends { inputs: { [key: string]: ReplaySubject<any> | BehaviorSubject<any> } }> = {
    [P in keyof T['inputs']]: T['inputs'][P] extends Observable<infer X> ? X : unknown;
}
// define a local 'InputType' helper above each component
type InputType = InputTypes<CheckoutSmartHeaderComponent>;

Тогда вам не нужно явно указывать тип свойства @Input .

@Input('config')
set config(value: InputType['config$'])
{
    this.inputs.config$.next(value);
}

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

@simeyla Слишком много шаблонов.

Я решил поставить своего собственного декоратора. Это мой первый пакет npm, поэтому я уверен, что мне чего-то не хватает, но вот он: https://www.npmjs.com/package/@ng-reactive/async -input

Установка

npm install @ng-reactive/async-input --save

использование

import { Component, Input } from '@angular/core';
import { AsyncInput } from '@ng-reactive/async-input';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.css']
})
export class HelloComponent {
  @Input() name: string;
  @AsyncInput() name$ = new BehaviorSubject('Default Name');

  constructor() {
    this.name$.subscribe(name => console.log('from async input', name));
  }
}

@ mfp22 действительно хорошо, я не вижу причин, по которым что-то подобное не должно быть встроено. К вашему сведению, ссылка на github на npm для пакета устарела, она идет сюда:

https://github.com/mfp22/async-input/tree/master/projects/async-input

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

Что еще круче, так это то, что с наблюдаемыми входами вам не нужен OnChanges hook - вы можете использовать оператор pairwise rxjs, чтобы получить предыдущие и текущие значения наблюдаемого входа:

@Component({...})
class MyReactiveComponent {
  @ObservableInput() prop: Observable<string>; // Whatever syntax may be...

  // emits [prevValue, currValue] and no OnChanges hook yay!!
  propChanges$ = this.prop.pipe(pairwise());
}

https://github.com/rx-ts/ngrx/blob/master/src/utils/decorators.ts#L56 -L124

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

Я опубликовал решение, которое лично использовал в своих проектах, в виде пакета npm:

https://github.com/futhark/ngx-observable-input

Установка

npm install ngx-observable-input

использование

...
<image-item [url]="currentImageUrl"></image-item>
import { Component, Input } from "@angular/core";
import { ObservableInput } from "ngx-observable-input";
import { Observable } from "rxjs";

@Component({
    selector: "image-item",
    template: `<img [src]="url$ | async" />`
})
export class GalleryComponent {
    @ObservableInput() @Input("url") public url$: Observable<string>;

    ...
}

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

Что еще круче, так это то, что с наблюдаемыми входами вам не нужен OnChanges hook - вы можете использовать оператор pairwise rxjs, чтобы получить предыдущие и текущие значения наблюдаемого входа:

@Component({...})
class MyReactiveComponent {
  @ObservableInput() prop: Observable<string>; // Whatever syntax may be...

  // emits [prevValue, currValue] and no OnChanges hook yay!!
  propChanges$ = this.prop.pipe(pairwise());
}

Это проблема, которая тоже беспокоит меня некоторое время, поэтому я немного исследовал и нашел то же решение, которое вы упомянули здесь (@gund).

Я реализовал небольшой помощник-декоратор ( @ObservableInput ), который внутренне расширяет декоратор @Input и допускает такой вид композиции. Вы можете проверить это здесь (также как пакет npm ). Я тестировал простые примеры, но у меня не было времени использовать это для расширенных проектов. Любые отзывы приветствуются :)

Вот пример использования:

@Component({
  selector: 'app-test',
  template: `<span>{{ message$ | async }}</span>`
})
class TestComponent {
  @ObservableInput<number>('price') price$: Observable<number>;
  @ObservableInput<string>('name') name$: Observable<string>;

  message$ = combineLatest(this.price$, this.name$).pipe(
    map(([price, name]) => `${name} costs {price}`)
  );
}

И этот компонент можно использовать так:

<app-test [price]="price"
          [name]="name">
</app-test>

@aleics Вы уверены, что это будет работать с компилятором AOT?

@aleics Вы уверены, что это будет работать с компилятором AOT?

Нет, конечно, не из коробки, поскольку свойство @Input явно не определено. Но вы можете определить свой модуль с помощью CUSTOM_ELEMENTS_SCHEMA , как при использовании веб-компонентов, а затем он должен скомпилироваться.

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

Айви наконец-то здесь, так что я думаю, у кого-то есть время поработать над этим? Пожалуйста пожалуйста пожалуйста!

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

Очень жду этого

Я понимаю, что Angular - это открытый исходный код, но ошибочно или наивно с моей стороны думать, что проект, управляемый Google, должен иметь возможность разрешать проблемы с большим количеством звезд и запрашиваемые проблемы менее чем за 5 лет? Есть ли какие-то финансовые проблемы, о которых я не знаю, которые мешают Google нанимать больше разработчиков для работы над Angular?

@ etay2000 Я не знаю, я думаю, это забавно, как вы можете делать 75% вещей в Angular с помощью rxjs, а затем для чего-то столь же фундаментального и обычно используемого в качестве компонентных входов, внезапно вы вынуждены выполнять процедурные Мир. У вас всегда есть эта важная часть вашего проекта, которая не может работать с миром наблюдаемых, поэтому вам всегда приходится использовать шаблон, чтобы склеить их вместе. Вы никогда не сможете достичь полностью функционального подхода к своему проекту. Таким образом, этот вопрос, открытый в течение 4 лет, напоминает мне об отсутствии прагматизма, который заставил меня отказаться от Angular и перейти к другим фреймворкам, потому что это довольно полезно. Если вы хотите использовать rxjs для всего, возможно, cycle.js - лучшее решение, а если вы вообще не хотите, чтобы вас заставляли использовать rxjs, возможно, Vue. Необходимость использовать наблюдаемые половину времени и не иметь возможности использовать их в другой половине просто не имеет никакого смысла. Интегрировать очень мощную абстракцию с высокой кривой обучения, а затем не удалось полностью интегрировать ее, просто сбивает с толку.

Я чувствую, что цепочка расстановки приоритетов выглядит так

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

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

источник: https://medium.com/@jeffbcross/jeffs-letter-to-the-angular-team-and-community-5367934a16c9)

Просто взгляните на некоторые из самых популярных вопросов.

Предложение: входные данные как наблюдаемые # 5689

Создан 5 лет назад, последний ответ от соответствующего члена команды - 5 лет назад, текущий статус неизвестен.

Поддержка холодных потоков событий в шаблонах # 13248

Создан 4 года назад, последний ответ от соответствующего члена команды - 1 год назад, текущий статус - ожидает приземления Айви.

Предложение: предоставить обработчики жизненного цикла компонентов как наблюдаемые # 10185

Создан 4 года назад, последний ответ от соответствующего члена команды - 3 года назад, текущий статус неизвестен.

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

Создан 4 года назад, последний ответ от соответствующего члена команды - 2 года назад, текущий статус неизвестен.

as local-val без * ngIf # 15280

Создан 4 года назад, последний ответ от соответствующего члена команды - 2 года назад, текущий статус неизвестен.

Поддержка проецирования динамического содержимого # 8563

Создан 4 года назад, последний ответ от соответствующего члена команды - 3 года назад, текущий статус неизвестен.

ng-content содержимое по умолчанию # 12530

Создано 4 года назад, последний ответ от соответствующего члена команды - никогда, текущий статус неизвестен.

Затем есть такие вещи, как функции компонентов, которые позволят использовать компоненты более высокого порядка, и, конечно, есть еще много проблем, за которые проголосовали чаще всего, но я надеялся, что они будут решены (то есть решены, не обязательно ожидая, что они будут реализованы сразу после того, как Ivy ), потому что они связаны с повседневным использованием фреймворка И реактивностью, что, я думаю, никто не станет спорить, это то, что использует большинство людей (учитывая, что ngrx является самой популярной библиотекой управления состоянием).

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

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

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

Несколько человек уже сделали, например. https://github.com/insidewhy/observable-input

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

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

@ganqqwerty Я пытался реализовать это внутри Angular до того, как написал эту библиотеку. Однако Angular чрезвычайно сложен. Честно говоря, код гораздо более читабелен и понятен, чем React и его сумасшедшие функции, состоящие из пятисот строк, но он «изощренный». И я все равно был бы счастлив приложить усилия, чтобы реализовать эту реализацию, если бы думал, что это того стоит. Но я не считаю это целесообразным именно по причинам, указанным выше в

Я думаю, это проблема не только с Angular, но и со многими предложениями от Google. Эта и другие проблемы, перечисленные выше в одним примером эндемичных проблем в Google. Если вы посмотрите на Dart или GoLang, вы также увидите, что разработчики поднимают очень известные и часто встречающиеся проблемы, а проблемы остаются открытыми более 5 лет.

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

https://github.com/angular/angular/issues/5689#issuecomment -507001686

Если это слишком много шаблонов, у нас уже есть несколько простых сторонних вариантов:

https://github.com/Futhark/ngx-observable-input

Я доволен разработкой Angular и, конечно же, не откажусь от удивительно полнофункциональной и надежной структуры из-за такой мелкой (хотя и желательной) функции.

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

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

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

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

Я бы точно не стал отказываться от Angular, несмотря на все его недостатки, он мне нравится больше, чем все другие альтернативы. Но я думаю, будет справедливо сказать, что ему не хватало «управления отношениями с сообществом» (в частности, на github).

// редактировать

Не могли бы вы, добрые люди, заполнить этот опрос? Учитывая вашу текущую ситуацию и все рассмотренные обстоятельства, какая из этих проблем влияет на вас больше всего / больше всего улучшит ваш опыт разработчика https://forms.gle/cprhx239kuqwWd5M8

@fxck Спасибо, что написали это. Я начал задаваться вопросом, приняли ли все только что тот факт, что команда Angular будет делать то, что они хотят, и когда они хотят. Хотя это, безусловно, их право, я также считаю, что людям необходимо вызывать их, когда они постоянно игнорируют голоса разработчиков. Я согласен с тем, что я не думаю, что кто-то ожидает немедленного решения проблем, но игнорировать их в течение 4-5 лет или просто ждать, пока проблема не будет автоматически заблокирована, кажется действительно непрофессиональным для любого проекта, не говоря уже о проекте, запущенном Google. Они выиграли время, добавив теги «Исправлено Айви» к множеству открытых проблем, а затем ничего не сделали.

Я бы точно не стал отказываться от Angular, несмотря на все его недостатки, он мне нравится больше, чем все другие альтернативы. Но я думаю, будет справедливо сказать, что ему не хватало «управления отношениями с сообществом» (в частности, на github).

Думаю, это предложение прекрасно резюмирует мои мысли.

@chriszrc На самом деле я ничего не интерпретировал в этой ветке как "ненависть". Скорее, люди, наконец, выражают свое разочарование тем, что Angular регулярно игнорирует проблемы в течение многих лет. Речь идет даже не об этой проблеме конкретно, а о принципе поддержания некоторой формы взаимодействия с сообществом. Считается ли, что команда Angular настолько превосходит всех остальных, что чувствует, что может игнорировать запросы разработчиков, потому что знает, что лучше для всех?

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

Всем привет, извините за тишину в этой ветке. Мы получаем два ортогональных запроса:

  1. Лучшая первоклассная поддержка RxJS во фреймворке
  2. Меньше RxJS в Angular, что потенциально делает его необязательным

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

В то же время у нас уже есть много реактивных API-интерфейсов, но некоторые из примитивов, предлагаемых Angular, являются абсолютно обязательными, и все не очень хорошо связано. Тем не менее, имеет смысл улучшить поддержку реактивности, но должно ли это быть частью ядра Angular или делегировано проекту сообщества (например, ngrx - реактивное расширение Angular), с которым мы тесно сотрудничаем?

Есть много способов решить эту проблему, но мы должны учитывать:

  • Обратная совместимость - не только для исходного кода, но и для учебных ресурсов.
  • Кривая обучения
  • Согласованность с текущими API
  • Согласованность между проектами
  • Производительность - время выполнения и время начальной загрузки

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

@mgechev Спасибо за ответ. Если rxjs и реактивный apis будут разделены на другое расширение (не мое личное голосование), возможно ли будет иметь больше смысла в том, чтобы это не было связано с конкретной реализацией хранилища состояний / редукции? Я быстро перешел от ngrx к ngxs (который казался менее шаблонным и более «угловатым» с декораторами), а затем, наконец, к Akita, которая является моим текущим фаворитом и с которой я работал больше всего. Или, если он будет объединен с ngrx, по крайней мере, упростите просто добавление необходимых нам частей, чтобы мы не были привязаны к использованию ngrx или включению этих зависимостей -

Если rxjs и реактивный apis будут разделены на другое расширение (не мой личный голос)

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

@mgechev действительно, спасибо за ответ.

Однако мне интересно, если реактивная часть Angular каким-то образом «понизится» в проекте сообщества, не будет ли это означать, что реактивная часть станет второсортным гражданином Angular?

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

Вот наши требования для такого разделения:

  • Использование как императивной, так и реактивной потребности, чтобы чувствовать себя родной, и ни одна из них не должна ощущаться навязчивой.
  • Нет привязки к конкретному решению для управления состоянием, чтобы включить реактивное решение (полное раскрытие информации, к настоящему времени мы перенесли все 50+ проектов на использование akita)
  • Оба варианта должны быть выпущены в одной версии одновременно (без задержек / задержек).
  • Не может быть "любимого", все, что делает angular, должно работать в обоих мирах, но при этом чувствовать себя родным.
  • Полная официальная поддержка обоих подходов при поддержке команды angular (исходя из нашего опыта, это жесткое требование клиента).

На основании вышеизложенного:

  • Есть 2 основных варианта:

    • основной императив + аддон реактивный

    • основной реактивный + аддон императив

  • Реактивная упаковка, чтобы она казалась императивной, довольно проста, а не наоборот.
  • Следовательно, мы бы проголосовали за использование реактивного кода в ядре и за то, чтобы надстройка содержала императивные API.
  • Из-за нулевой задержки + отсутствие требований к избранному, а также необходимой официальной поддержки, я не понимаю, как аддон может быть проектом сообщества

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

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

добавьте функцию, пожалуйста

@mgechev Я не понимаю твоих опасений. Это предложение об объединении двух миров с единым и понятным для начинающих разработчиков интерфейсом. Речь идет не о выборе того или другого, а о включении комбинации. Например, разработчик x решает создать потрясающий реактивный компонент. И разработчик решает использовать его в своем не очень реактивном проекте. Почему нет? Зачем ему зависеть от клея ngrx?
Разница между этими двумя мирами заключается в том, храните ли вы / управляете состоянием в своем конечном интеллектуальном компоненте или в центральном хранилище состояний, и это то, чем должен быть ngrx, но для компонентов я считаю, что сам фреймворк должен быть активным фактором.

Мы получаем два ортогональных запроса:

  1. Лучшая первоклассная поддержка RxJS во фреймворке
  2. Меньше RxJS в Angular, что потенциально делает его необязательным

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

Лично мне любопытно посмотреть, как у вас вообще будут версии без RxJS для всех пакетов Angular (HTTP, Router, Forms). Я подозреваю, что у них нет хороших версий, отличных от RxJS, поэтому в первую очередь у них есть RxJS.

То есть .... если я чего-то не упускаю, (2) невозможно.


PS Я бы не стал называть эти запросы «ортогональными»; больше похоже на «противоположное».

Меньше RxJS в Angular, что потенциально делает его необязательным

Из любопытства @mgechev , есть ли для этого проблемы с Github? (Я не видел ни одного.) Или это больше похоже на гуглеров?

@pauldraper Я видел по крайней мере одну проблему на github, когда кто-то жалуется на то, насколько ужасно сложен rxjs, и хочет, чтобы он был полностью необязательным. Лично я люблю rxjs, но сейчас я работал с двумя командами, где они вызывали страх и отвращение как у младших, так и у старших разработчиков. Кроме того, ортогональный - лучший термин, чем противоположный, поскольку можно реализовать оба запроса одновременно (при условии, что каждое решение может работать, не отвлекая одно от другого, предоставляя несколько вариантов API для использования вещей реактивно и императивно).

На каждый комментарий с жалобой на rxjs на github, вероятно, тысячи разработчиков используют и наслаждаются им без проблем.

image

image

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

Unsurprisingly формы самая большая боль в заднице, но , по- видимому @brandonroberts и @MikeRyanDev может быть готовя что - то, в конце концов.

На каждый комментарий с жалобой на rxjs на github, вероятно, тысячи разработчиков используют и наслаждаются им без проблем.

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

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

Это разработчики, которых Angular пытается удовлетворить тогда, выгоренные и не желающие учиться? :) И кого это вообще волнует в данный момент. Angular существует уже некоторое время, он никуда не денется, и он абсолютно не потеряет тяги, если вы добавите наблюдаемый жизненный цикл, наблюдаемый ввод, наблюдаемые события. Просто добавьте эти три мелочи, и люди будут счастливы какое-то время, вот и все (и следуйте за этим с помощью https://indepth.dev/component-features-with-angular-ivy/, чтобы завершить базовый пакет).

angular_rxjs

Этот говорит сам за себя. IMHO Angular должен оставаться последовательным и использовать больше RxJS: без RxJS вообще он не был бы Angular.

Таких разработчиков Angular пытается удовлетворить? :)

Да, было бы претенциозно обслуживать только разработчиков, которые хотят писать код с использованием rxjs. Хотя я предпочитаю использовать rxjs, я хочу, чтобы Angular обслуживал оба набора разработчиков. Почему Angular должен обслуживать только нас, а не тех, кто думает иначе? Особенно когда я считаю, что мы в меньшинстве, а не в большинстве.

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

А функции компонентов полезны независимо от того, нравится вам реактивное программирование или нет.

@fxck Я ни на секунду с этим не

Несмотря на то, как angular решает разработать ядро ​​- реактивно или нет, в идеальном мире должен быть противоположный пакет, построенный поверх для удовлетворения противоположных потребностей (например, @angular/reactive или @angular/imperative - с лучшими именами. с надеждой).

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


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

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

Из любопытства @mgechev , есть ли для этого проблемы с Github? (Я не видел ни одного.) Или это больше похоже на гуглеров?

Не внутреннее дело Google. Вы будете удивлены (как и я, когда присоединился к команде), насколько велико пересечение между внешними и внутренними требованиями. Основное отличие заключается в системе сборки и управлении зависимостями, за исключением того, что гуглеры предъявляют почти те же требования, что и не гуглеры.

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

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

Я думаю, что наличие единого реактивного или императивного подхода (это выбор для каждого проекта) при разработке приложения angular было бы очень полезным. Возможность смешивать и сопоставлять не помогает при разработке и создавать не СУХИЙ код (например, нереактивные входные данные).

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

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

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

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

@mgechev Поскольку этот вопрос поднимался несколько раз, было бы интересно услышать ваши мысли о реактивном ядре / императивном расширении, и есть ли у него какая-то нога, на которой можно опереться?

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

Замечательно, полезно знать. Определите, что нужно делать с помощью RxJS? Как в это вписывается добавление наблюдаемого жизненного цикла, наблюдаемых входных данных и наблюдаемых событий? И нет, ни у одного из них действительно нет «хорошо зарекомендовавших себя обходных путей / решения сообщества».

@fxck ни у одного из них нет "хорошо зарекомендовавших себя обходных путей / решения сообщества".

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

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

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

Наблюдаемые события еще хуже, решений сообщества не так много, они обычно требуют дополнительного этапа сборки (который в некоторых случаях нарушает SSR в настройках монорепозитория) и взламывает поверх этого даже (если вы используете расширение класса, например, для получить наблюдаемые события жизненного цикла, потому что, эй, angular не поддерживает это изначально) https://github.com/typebytes/ngx-template-streams/issues/8

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

@fxck Насколько мне известно, невозможно очистить подписки на события жизненного цикла без использования родительского класса (ну) или метода, который пользователь должен вызывать из своего собственного события жизненного цикла уничтожения (что еще хуже).

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

Я также пытался реализовать события жизненного цикла (чтобы заставить его реагировать) с помощью настраиваемых декораторов, и это больно. ~ Без расширения класса, я не знаю, возможно ли это без 100 хаков ~. Пользовательские возможности по расширению angular пока очень плохие, и для этого нужно использовать хаки или множество шаблонов.

@ tonivj5 Если бы компонентные функции были общедоступными API, считаете ли вы это потенциальным способом реализации жизненных циклов без наследования?

@ntziolis hah, забавно, вы должны упомянуть функции, я на самом деле работаю над частью жизненного цикла ngx-sub-формы, и функции - это именно то, что, как я думаю, могло бы помочь. А пока очень реально исправить фабрику компонентов с помощью ivy. Я считаю, что это очень полезно за пределами ngx-sub-формы, поэтому я думаю, что выделю эту логику в отдельную библиотеку

@ntziolis На данный момент я не уверен, увидим ли мы когда-нибудь, чтобы обещания Айви действительно выполнялись.

Вы проверили угловой эффект? (не ngrx / effects) https://dev.to/stupidawesome/reactive-adventures-in-angular-introduction-angular-effects-1epf С помощью этого инструмента вы можете писать полностью реактивные приложения.
Включено двустороннее наблюдаемое состояние между родительскими и дочерними компонентами
https://dev.to/stupidawesome/exploring-the-angular-effects-api-2gol
Версия 9.1.0 представит модель композиции / хуков, основанную на Vue 3 Composition API.
Я думаю, что это действительно следующий шаг для angular в работе с реактивностью.

@mgechev

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

Просто любопытно, кто мы и сколько гуглеров активно участвуют в процессе принятия решений Angular?

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

Возникает ли когда-либо во внутренних обсуждениях тот факт, что обычно существует 2500 открытых вопросов в любой момент времени?

@ntziolis , как сказал @zakhenry , я думаю, features поможет

@ntziolis Я попробовал еще раз с жизненным циклом, и у меня есть рабочий POC (без расширения класса и без реализации интерфейсов жизненного цикла). Он полагается на частный API (: восклицание :)

@ tonivj5 ха, у меня не было возможности прочитать вашу, но я почти выпустил свое решение :) https://github.com/cloudnc/ngx-observable-lifecycle

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

У меня все работает, просто нужно отсортировать CI и модульные тесты.

Возникает ли когда-либо во внутренних обсуждениях тот факт, что обычно существует 2500 открытых вопросов в любой момент времени?

Лол, с середины 2019 года не было 2500 открытых проблем.

$ github_issue_stats history -i2m -n20 -sangular/angular

+-------------------------+--------------------+
|         period          |       issues       |
+-------------------------+--------------------+
| This month (2020-05)    | 2855 (+137, -112)  |
| Last month (2020-03)    | 2830 (+495, -550)  |
| 2 months ago (2020-01)  | 2885 (+601, -575)  |
| 3 months ago (2019-11)  | 2859 (+437, -352)  |
| 4 months ago (2019-09)  | 2774 (+411, -305)  |
| 5 months ago (2019-07)  | 2668 (+441, -369)  |
| 6 months ago (2019-05)  | 2596 (+488, -349)  |
| 7 months ago (2019-03)  | 2457 (+425, -373)  |
| 8 months ago (2019-01)  | 2405 (+428, -330)  |
| 9 months ago (2018-11)  | 2307 (+425, -391)  |
| 10 months ago (2018-09) | 2273 (+515, -466)  |
| 11 months ago (2018-07) | 2224 (+641, -541)  |
| 12 months ago (2018-05) | 2124 (+690, -624)  |
| 13 months ago (2018-03) | 2058 (+605, -444)  |
| 14 months ago (2018-01) | 1897 (+773, -679)  |
| 15 months ago (2017-11) | 1803 (+815, -979)  |
| 16 months ago (2017-09) | 1967 (+671, -431)  |
| 17 months ago (2017-07) | 1727 (+664, -518)  |
| 18 months ago (2017-05) | 1581 (+854, -548)  |
| 19 months ago (2017-03) | 1275 (+987, -796)  |
| 20 months ago (2017-01) | 1084 (+671, -505)  |
+-------------------------+--------------------+

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

@agalazis Эта проблема открыта уже 4 1/2 года и практически игнорируется последние 3.

@agalazis Эта проблема открыта уже 4 1/2 года и практически игнорируется последние 3.

Член команды Angular объяснил, почему он все еще открыт всего 5 дней назад, так что вы просто не правы.

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

@beeman

Член команды Angular объяснил, почему он все еще открыт всего 5 дней назад, так что вы просто не правы.

Тебе действительно нравятся эти смайлики с опущенными пальцами, да? Но было ли это действительно объяснение? Спустя 4 с лишним года он сказал, что они не хотят торопиться с решением.

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

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

@agalazis Вы правы, полагаю, я (ошибочно) ожидал большего от проекта с открытым исходным кодом, поддерживаемого Google, чем от меньшего проекта.

@beeman Вставьте смайлики вниз: -------->

@ etay2000 Вы всегда должны помнить, что каждое такое важное решение влияет на сотни тысяч вещей, проектов и людей. И что еще более важно, неидеальное решение и введение общедоступных API-интерфейсов, которые вскоре после этого могут привести к критическим изменениям, - это просто кошмар. Почти на каждом PR вы можете видеть, как рассматривается каждый шаг, и если он не идеален, он просто ждет, недели, месяцы или даже годы.

@agalazis Вы правы, полагаю, я (ошибочно) ожидал большего от проекта с открытым исходным кодом, поддерживаемого Google, чем от меньшего проекта.

Я не знаю, посмотрите также на Go и dart. Google на самом деле довольно известен тем, что игнорирует чрезвычайно популярные запросы сообщества в течение полувека: D В целом их подход к языкам / фреймворкам / и т. Д. очень консервативен . Вы можете видеть, как появляются новые языки и идеи, которые революционизируют области, а Google все еще не принимает их в течение многих лет, например, нулевая безопасность поразила Kotlin, TypeScript и Scala задолго до Dart. Я предполагаю, что у такого подхода есть свои преимущества и недостатки, но, по крайней мере, я стараюсь избегать разработок Google там, где это возможно, потому что это действительно не соответствует моему духу.

(Извините за это, но я должен это сделать.)

@beeman Вставьте смайлики вниз: -------->

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

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

@brunojcm Думаю, вечеринка окончена, так как полиция комментариев здесь. Дело в том, что он записал все мои комментарии, но я не осознавал, что сарказм был нарушением поведения.

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

То, как я действительно хочу на это отреагировать, определенно нарушит кодекс поведения здесь.

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

@ tonivj5 @zakhenry Приятно слышать, что это может быть проспект.

@mgechev Я понимаю, что это даже не предварительное обсуждение, но хотел бы услышать ваши мысли по

  • реактивное ядро ​​+ нереактивное расширение против наоборот.
  • и, более конкретно, для этой проблемы, есть ли реальный шанс каким-либо образом раскрыть api функции.

    • даже если это просто предупреждение о нарушении изменений в будущем, пока общая функция все еще будет доступна.

    • Как @zakhenry сделал для событий жизненного цикла, я вижу один или очень ограниченное количество проектов,

    • Затем вы можете работать с этими командами-оболочками, чтобы сообщить им о предстоящих критических изменениях на раннем этапе (очень похоже на ваше предложение о реактивных расширениях)

Я думаю, вы, ребята, можете напрямую применить реактивный модуль Vue 3.0 (ref или reactive) и решить эту проблему.

@AnonymousArthur, если вы говорите о пакете @vue/reactivity то он совершенно не связан с тем, что мы здесь обсуждаем, поскольку он обеспечивает реактивность свойств и не имеет ничего общего с реактивными потоками (что и есть RxJs).

@gund Да, согласен. Однако этот разговор занимает довольно много времени (4,5 года) и еще не закончен, поэтому я просто очень быстро всплываю (а может и нет) идею, для кого не нужно писать подписку / отписаться или обработчик ngOnChange. RxJS действительно обеспечивает функцию реактивности, и этот разговор (не читал его полностью) говорит об упаковке значения Input с Observable в качестве синтаксического сахара, чтобы сделать его доступным для просмотра, и я думаю, что это отличная идея.

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

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

Angular будет определять декоратор @OInput() и тип EventReceiver<T> который расширяет Observable<T> но также добавляет .value getter (например, BehaviorSubject<T> ).

На стороне родительского компонента , как в примере @robwormald , ничего не меняется. Если вы хотите передать туда значение Observable, вам все равно понадобится | async . Или вы можете передать ему ненаблюдаемый тип, это тоже нормально (как всегда).

Что касается дочернего компонента , то вот что я предлагаю (небольшое отклонение от этого предложения):

@Component({ selector: "child" })
class Child {
  // Notice, this parallels the patterns of `@Output()`.
  @OInput() foo = new EventReceiver<MyType>();

  constructor() {
    // The reactive way to listen to input changes in the class.
    this.foo.subscribe((v) => {
      console.log('foo changed', v);
    });
    // Or you can bind to `foo | async` in the template.
  }

  // But this would also support less reactive patterns in parallel,
  // both for ease of migration and for cases where developers don't
  // want to migrate fully. 
  ngOnChanges(changes: SimpleChanges) {
    if (changes['foo']) {
      console.log('foo changed', changes['foo'].currentValue); // Unchanged
      console.log('foo changed', this.foo.value);  // Previously this would have been just `this.foo`
    }
  }
}

Вот преимущества этого подхода, которые, как мне кажется, были немного недооценены:

  • При желании это позволяет эффективно использовать полностью реактивные конструкции как в родительском, так и в дочернем компонентах.
  • В родительских компонентах поддерживает существующие шаблоны проектирования ввода Angular, так что ни один компонент не принудительно вводится в это и не должен проектировать вокруг него.
  • Родительский и дочерний контекст полностью независимы, родителю не нужно знать, использует ли дочерний элемент Input или OInput , что устраняет риск возникновения межкомпонентных ошибок из-за этого изменения.
  • При желании относительно легко частично перенести один дочерний компонент, потому что Angular сохраняет все это связанными с существующими событиями жизненного цикла, как и раньше.
  • Поскольку Angular реализует эту функцию, все EventReceiver могут внутренне включать канал через takeUntil(ngOnDestroyEvent) , поэтому в большинстве случаев не нужно помнить об отмене подписки при уничтожении их компонента, потому что эти наблюдаемые будут автоматически завершены. . (Ура, уменьшились утечки памяти!)
  • В этом дочернем компоненте это выглядит и функционирует очень похоже на шаблон @Output() сегодня, поэтому дает хороший параллелизм и потенциальную возможность их красиво соединить.

    • Боковое примечание: в качестве продолжения, я думаю, было бы здорово предложить @InputOutput() который использует ReplaySubject<T>(1) для более плавного и последовательного соединения поведений для двусторонней привязки. Но здесь есть свои проблемы и аргументы, поэтому я НЕ предлагаю их здесь.

  • Никаких новых типов шаблонов для этой работы нет, это просто @Output() .
  • Angular будет без проблем switch() при изменении Observable , вводимого родителем, поэтому более слабые реактивные шаблоны, подобные этому, не привязанные к одному и тому же экземпляру Observable, не нуждаются в особом регистре ( switch() ed) в дочерних компонентах.

Замечание о выбранном мной названии OInput : очевидно, это открыто для обсуждения. Однако мне лично нравится это имя, потому что оно является сокращением от «Observable Input» И потому, что оно похоже на «Output», которое это отражает.

Уважаемая команда Angular. Пожалуйста, дайте нам что-то, чего мы будем ждать в 2020 году :-)

Также решение @jcomputer - это именно то, что мне нужно. Не большой поклонник другого имени декоратора, но, возможно, можно добавить параметр, аналогичный тому, как @ViewChild имеет { read } . например:

@Input({ observable: true }) 
@Input({ asObservable: true }) 
@Input({ asSubject: true })

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

https://twitter.com/ThomasBurleson/status/1283902827467886592
image

@fxck У меня может быть непопулярное мнение здесь, но, честно говоря, если 2020 год станет годом, когда команда Angular решит устранить множество ошибок в формах, маршрутизаторе и т. д., я бы вообще не злился на 0 функций : shrug :.

image

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

Извините за оффтоп. Улетает

@ maxime1992 Мне тоже было бы хорошо.

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

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

С моей точки зрения, они исправляют проблемы, в основном, закрывая их через BOT - оставляя без ответа и закрывая бот., ..: - /

@ montella1507 Нет, это не совсем так. Бот блокирует только уже закрытые выпуски. И это уже правда, что члены команды Angular прилагают много усилий во многих случаях, когда они пытаются объяснить, что необходимо описывать и воспроизводить при вводе новых проблем. Это очень трудоемкий процесс и требует большого терпения.

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

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

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

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

Люди @manfreed не просят новую блестящую игрушку, они просят исправить недосмотр в дизайне фреймворка. В настоящее время мы иногда вынуждены использовать наблюдаемые объекты, а иногда не можем использовать наблюдаемые объекты для ключевых функций. Те, кто ненавидит наблюдаемое, разочарованы. Те, кто любит наблюдаемое, разочарованы. И многие из нас были настолько разочарованы ситуацией, что отказались от нее и перешли на другие фреймворки. Я бы с удовольствием продолжил использовать Angular, небольшое направление, и это могло бы стать действительно отличным фреймворком. Но сообщения в блогах о бесхозяйственности, отсутствии прагматизма, упущениях - все они объективно разочаровывают.

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

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

image

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

image

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

Я закончил попытки донести свою точку зрения, но позвольте мне попробовать в последний раз ... Я не прошу, чтобы Angular был преобразован в Cycle.js , заменив текущие API, все, что я прошу, это три маленьких реактивных вишенки поверх текущих API.

  • наблюдаемый жизненный цикл
  • наблюдаемый ввод
  • наблюдаемые события шаблона

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

@fxck : +1: точно.

  • наблюдаемый жизненный цикл
  • наблюдаемый ввод
  • наблюдаемые события шаблона

@insidewhy Будьте терпеливы

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

@ insidewhy Это имелось в виду в более общем плане.

@fxck У Google (по моим последним подсчетам) 4000 приложений, построенных на angular и очень похожих по своей природе, переключение между этими проектами и рецензированием (я полагаю) довольно плавным. Даже в моей компании одно из огромных преимуществ Angular заключается в том, что я знаю, что, даже если я не просматриваю код другой команды, он находится в состоянии, когда экспертная оценка не приводит к завершению расследования.

Теперь предположим, что мы внедрили в ядро ​​каждый из этих полезных ярлыков RxJS, что тогда происходит? Возможно, мы получим процедурное смещение по сравнению с реактивным, без четких указаний о том, какое смещение является правильным для каждого конкретного случая. После прочтения обсуждений, ответ от команды angular не «Это низкий приоритет» (как подсказывает ваш поток), на самом деле он кажется более близким к «Мы ​​не хотим принимать чью-то сторону».

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

Цель Angular (как я ее вижу) - сократить и приглушить разговоры от «Используйте технологию X, потому что так лучше, вот короткая новелла, почему» и поддерживать разговоры в экспертных обзорах о внедряемой бизнес-логике. Неужели мы действительно хотим разделить наши компоненты между "Advanced" angular и "Beginner" angular больше, чем мы уже сделали?

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

Позвольте мне просто процитировать вам одного из членов команды angular.

image

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

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

Разница между управлением состоянием и этим заключается в том, что управление состоянием может осуществляться сообществом, внутри ядра angular нет ничего, что могло бы этому помешать. К сожалению, Angular не предоставляет способов должным образом реализовать ни один из трех упомянутых мною. (править: исправлена ​​ссылка на комментарий)

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

После прочтения обсуждений, ответ от команды angular не «Это низкий приоритет» (как подсказывает ваш поток), на самом деле он кажется более близким к «Мы ​​не хотим принимать чью-то сторону».

Да и это страшно.

@fxck Я очень думаю, что мы находимся на одной странице по этому поводу. Я бы сказал, что каждый раз, когда я поднимаю тему RxJS на форумах или даже с моими коллегами-инженерами, большинство цитат, которые я могу процитировать, звучат так: «Я все еще не понимаю этого, как мне узнать больше?» или «Меня подавляет количество операторов». или «У меня проблемы с чтением этого конвейера в этом PR». На каждого хорошо разбирающегося в RxJS инженера приходится 15 хорошо разбирающихся в Angular инженеров с нахмуренными бровями.

Да и это страшно.

Это немного гиперболично, нам не «нужен» @angular/core чтобы иметь эти шаблоны, на самом деле в этом выпуске есть МНОЖЕСТВО вариантов и библиотек, которые можно использовать сегодня в любом проекте. Единственная сдержанность в использовании ранее упомянутых опций заключается в том, что в будущем вам, возможно, придется перейти на что-то, что Angular предоставляет в качестве стандартной замены @angular/core . Неужели нам так сложно npm uninstall исправить все ошибки машинописного текста?

Основные архитектурные решения, которые влияют на все проекты angular и требуют бесчисленных часов на документирование и перенос, если они не работают, мне это кажется еще более пугающим, и мы уже были в этом раньше:

Это немного гиперболично, нам не «нужен» @ angular / core, чтобы иметь эти шаблоны, на самом деле в этом выпуске есть МНОЖЕСТВО вариантов и библиотек, которые можно использовать сегодня в любом проекте.

Нет, на самом деле нет, каждое решение требует взлома или полагается на внутренние API, которые могут измениться. В этом весь смысл ... прочтите, что сказал @insidewhy https://github.com/angular/angular/issues/5689#issuecomment -630661006 и что я сказал ниже о потоках событий шаблона.

// редактируем исправленную ссылку на комментарий

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

Какие внутренние API или типы, по вашему мнению, следует сделать общедоступными / общими, чтобы сообщество могло решить эту проблему? Если этот дизайн находится в схеме удержания, потому что нет четкого пути вперед, то кажется уместным спросить, что нам разрешено создавать свои собственные, а не постоянно стучать в один и тот же барабан.

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

image

@fxck Я не собираюсь обсуждать историю попыток реализовать это в ядре или то, как эта проблема

Эй, @insidewhy , мне интересно, это хак для проверки типов, на который опиралась ваша библиотека. Судя по всему, с TS 4.0 больше не работает

Свойство serviceStackId $ используется перед его инициализацией. Ts (2729)

image

Эй, @insidewhy , мне интересно, это хак для проверки типов, на который опиралась ваша библиотека. Судя по всему, с TS 4.0 больше не работает

Нет, это было в компиляторе шаблонов. Это другое дело. Черт. Ах хорошо. Я могу добавить вас в список сопровождающих, если вы хотите попробовать исправить это.

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

@insidewhy Я определенно работал до TS4. И проверьте это ,

function ObservableInput() {
  return (target: any, propertyKey: any) => {
    Object.defineProperty(target, propertyKey, {
      set(value: any) {
        console.log(target, propertyKey, value);
      },
      get() {
        return 'ObservableInput modified value';
      },
    })
  }
}

class Foo {
    @ObservableInput()
    bar = 'original bar value';

    baz = this.bar;

    constructor() {
        console.log('loggging this.baz', this.baz);
    }
}

new Foo();

это журналы

регистрация измененного значения this.baz ObservableInput

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

Я использую декоратор, чтобы почувствовать изменение свойства Input и создать наблюдаемую версию свойства Input. См. Эту демонстрацию codeandbox .

Вот как это работает:

// subjectize.ts
export function Subjectize(keyToWatch: string): PropertyDecorator {
  return (proto: any, propKey: string) => {
    const internalKey = Symbol(keyToWatch);
    Object.defineProperties(proto, {
      [keyToWatch]: {
        get() {
          return this[internalKey];
        },
        set(value) {
          this[internalKey] = value;
          this[propKey].next(value);
        }
      }
    });
  };
}
// counter.component.ts
import { Component, Input } from "@angular/core";
import { ReplaySubject } from "rxjs";
import { Subjectize } from "./subjectize";

@Component({
  selector: "app-counter",
  templateUrl: "./counter.component.html",
  styleUrls: []
})
export class CounterComponent {
  @Input()
  count: number;

  @Subjectize("count")
  count$ = new ReplaySubject(1);
}

Как заметил @wmaurer , @Subjectize можно рассматривать как «сахар» для достижения цели.

Стоит прочитать официальное руководство angular Перехват изменений свойств ввода с помощью установщика , в котором объясняется, что мы можем определять изменения ввода с помощью getter/setter .

@hankchiutw Это решение похоже на мой декоратор @BindObservable : https://github.com/PSanetra/bind-observable#usage

Спасибо @hankchiutw

Поскольку вы инициализируете ReplaySubject с 1, я решил вместо этого использовать BehaviorSubject.
Также я инициализировал значение прямо в Subjectize.

export function Subjectize<T>(keyToWatch: string): PropertyDecorator {
  return (target: Object, propKey: string) => {
    const internalKey = Symbol(keyToWatch);
    Object.defineProperties(target, {
      [keyToWatch]: {
        get(): T {
          return this[internalKey];
        },
        set(value: T) {
          this[internalKey] = value;

          if (this[propKey]) {
            this[propKey].next(value);
          } else {
            this[propKey] = new BehaviorSubject(value);
          }
        }
      }
    });
  };
}

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: 'rol-bla',
    templateUrl: 'bla.html',
    styleUrls: [ 'bla.scss' ]
})
export class BlaComponent implements OnInit {
    @Input() world: World;
    @Subjectize<World>('world') world$: BehaviorSubject<World>;

    // ...
}

Я хотел бы избежать записи типа в свойстве "Subjectized", поскольку он должен уметь угадывать его по связанному свойству :( Есть идеи, как это сделать?

Мечтой было бы иметь возможность сделать это и автоматически создать соответствующую опору Subject (world $ в моем случае) как BehaviorSubjectи правильно инициализирован.

export class BlaComponent implements OnInit {
    @Input() @Subjectize() world: World;

    // ...
}

@mparpaillon Предлагаемый похож на то, что сделано на https://github.com/PSanetra/bind-observable
Единственная разница в том, что декоратор @BindObservable() использует ReplaySubject под капотом. Поэтому, если вы хотите, чтобы этот Subject содержал начальное значение, вам также необходимо явно инициализировать привязанное свойство (также, если оно просто не определено, поскольку возможно, что тип свойства не допускает неопределенные или нулевые значения).

Пример Stackblitz

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponentComponent {
  @Input()
  @BindObservable()
  counter: number;
  counter$: ReplaySubject<number>;
}

Спасибо @PSanetra, но я предпочитаю свое решение (которое на самом деле является решением Хэнка)

@mparpaillon Я пробовал кое-что для твоей мечты (ха) в другом демо .

Использование выглядит как

export class CounterComponent {
  @Input()
  @Subjectize()
  count: number;

  @Input()
  @Subjectize("myCount$")
  anotherCount: number;
}

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

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

Спасибо @hankchiutw ! Хотя Typescript не позволяет мне использовать count $ или myCount $.

Capture d’écran 2020-11-12 à 10 11 50

Также вы можете быть правы насчет двусмысленности ... Еще раз спасибо

Хотя Typescript не позволяет мне использовать count $ или myCount $.

Вы объявили членов своего класса как «count» и «anotherCount», поэтому вы не можете получить доступ к «myCount $» и «count $». Их просто не существует, потому что вы их нигде не декларировали.

Я знаю ... в том-то и дело. Я искал способ объявить их из декоратора. @hankchiutw предложил решение, и я просто говорю, что оно не работает как есть

@mparpaillon взгляните на мое решение: https://github.com/Futhark/ngx-observable-input

@Futhark О, это

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