Angular: Vorschlag: Input als Observable

Erstellt am 8. Dez. 2015  ·  183Kommentare  ·  Quelle: angular/angular

Entschuldigung, ich bin nicht gut in Englisch.

@Input Eigenschaftswerte werden von der übergeordneten Komponente bereitgestellt. Die Änderungen kommen asynchron.
Und wenn die Input-Eigenschaft in der untergeordneten Komponente geändert wurde (sie hat die Eigenschaft als eigene Eigenschaft), bemerkt der Änderungsdetektor dies nie.

Ziel

  • Die Eingabedaten des Elternteils und die Eingabeeigenschaft des Kindes sollten synchronisiert werden.
  • Entwickler sollten wissen, dass Eingabeeigenschaften asynchron geändert werden.

    Vorschlag

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

Der obige Code funktioniert nicht. Um Eingaben als Observable<T> , muss ich es derzeit wie unten beschrieben schreiben.

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

Beispiel: http://plnkr.co/edit/BWziQygApOezTENdTVp1?p=preview

Das funktioniert gut, ist aber nicht unbedingt erforderlich. Die Eingabedaten der Eltern sind ursprünglich einfache Daten.

Ich denke, dieser Vorschlag macht uns glücklich.

Danke.

core inputs / outputs feature Needs Design

Hilfreichster Kommentar

Liebes Angular-Team. Bitte geben Sie uns etwas, worauf wir uns im Jahr 2020 freuen können :-)

Auch die @jcomputer- Lösung ist genau das, was ich mir wünschen würde. Ich bin kein großer Fan eines anderen Dekorateurnamens, aber vielleicht ist es machbar, einen Parameter hinzuzufügen, der dem ähnlich ist, wie @ViewChild { read } . z.B:

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

Alle 183 Kommentare

Hallo @laco0416 - dein Englisch ist in Ordnung, keine Sorge!

Diese Idee gefällt mir sehr gut, und wir haben sie schon einmal besprochen. Es passt auch gut zu https://github.com/angular/angular/issues/4062 (Beobachten von Ansichtsereignissen) und https://github.com/angular/angular/issues/5467 (Beobachtbare Kinderereignisse von Eltern)

Es ist wichtig, sich daran zu erinnern, dass nicht jeder Observables verwenden möchte (diese Leute verpassen etwas!), also müssen wir Optionen für beide Anwendungsfälle bereitstellen, und daher ist es unwahrscheinlich, dass wir @Input() direkt in ein Observable umwandeln. Ich denke, dass es funktionieren könnte, so etwas wie @ObserveInput() , und wir werden _nach__ der Auslieferung der Beta-Version eine Diskussion über einige dieser interessanteren Funktionen führen, denke ich.

In der Zwischenzeit ist hier eine grundlegende (und _sehr_ experimentelle!!! Tun Sie dies NICHT in der Realität) dieser Idee. Ist das konzeptionell das, was Sie dachten? http://plnkr.co/edit/Nvyd9IPBZp9OE2widOcW?p=preview

Ich halte es für eine sehr schlechte Idee, Eingabeeigenschaften in einer untergeordneten Komponente zu ändern. Eingabeeigenschaften sollten "schreibgeschützt" sein. Ihre Daten sollten immer vom Elternteil zum Kind fließen (und niemals in umgekehrter Richtung).

@alexpods Ich glaube, die Idee hier ist genau das - es _hört_ auf die Änderung der Eingabeeigenschaften _als_ ein Observable, das keine Werte im Upstream ausgibt, was für mich absolut in Ordnung ist.

@robwormald

Ihr Englisch ist in Ordnung, keine Sorge!

Danke schön! Ich bin so erleichtert.

Dein @ObserveInput ist das, was ich will!
Außerdem hat @Input keine Breaking Changes. Ich denke, es ist eine sehr gute Lösung.

@alexpods Ich auch überhaupt.

Es hört auf die Änderung der Eingabeeigenschaften als Observable und gibt keine Werte im Upstream aus, was für mich absolut in Ordnung ist.

Ich denke genauso wie Rob.

@laco0416 Oh , sorry für das Missverständnis. Der Satz "wenn die Input-Eigenschaft in der untergeordneten Komponente geändert wurde" hat mich verwirrt.

Ich weiß nicht, ob ich hier einen Kommentar abgeben soll oder ob ich ein neues Thema eröffnen soll. Bitte lassen Sie es mich wissen, wenn ich eine Anfrage an der falschen Stelle hinzufüge.

Ich habe versucht (aber bis jetzt gescheitert), einen solchen Dekorateur zu schreiben, und dann bin ich auf plunkr von gestoßen , der _fast_ perfekt (aber nicht ganz) funktioniert.

Was mich von diesem Ansatz begeistert hat, war die Tatsache, dass er in den ngOnChanges Lebenszyklus-Hook eingreift.
Was ich gerne sehen würde, ist eine Möglichkeit, wie _alle_ Lebenszyklus-Hooks als Observables verfügbar gemacht werden, dh als onChanges$: Observable<{[key: string]: SimpleChange}> , onInit$: Observable<{}> usw.

Alle Lebenszyklus-Hooks als Observables verfügbar zu haben, wird mir helfen, all die Dinge zu empfangen ;-)

Irgendwelche Updates dazu?

AFAIK, Nr.
@robwormald hast du Neuigkeiten?

Ich weiß, das ist alt, aber das wäre großartig! @robwormald Irgendein Wort dazu?

Ich würde gerne ändernde @Input Eigenschaftswerte als Observable bereitstellen , genau wie der @ObserveInput Dekorator von @robwormald . Es ist nicht immer möglich, dass übergeordnete Komponenten Observables passieren, insbesondere wenn Sie eine vorhandene (Angular 1)-Anwendung migrieren. Die Tatsache, dass Observables nicht in einer einzigen Komponente "enthalten" werden können, macht es jedoch viel schwieriger, die Kraft und Eleganz von RxJS zu nutzen.

Leider machte Rob keine Witze, als er sagte, diese Version von @ObserveInput nicht zu verwenden. Das Problem, auf das ich stoße, ist, dass die Observables auf "Klassenebene" erstellt werden (wenn diese Terminologie sinnvoll ist) und daher von allen Instanzen der Komponente gemeinsam genutzt werden. Das ist offensichtlich nicht gut. Das Erstellen der Observables zum Zeitpunkt der Instanziierung hat bei mir auch nicht funktioniert. Es scheint, dass Angular die Änderungserkennung in diesem Fall nicht richtig verdrahtet.

Hat jemand eine bessere Implementierung von @ObserveInput oder gibt es Neuigkeiten zum offiziellen Support?

@lephyrus Während ein offizieller @ObserveInput Dekorator sehr nett wäre, ist es nicht unbedingt notwendig, um ein Observable der Änderung von @Input Eigenschaftswerten zu erhalten. Der Dekorateur wäre einfach sehr elegant "Zucker".

Es gibt bereits ein Lebenszyklusereignis ngOnChanges . Innerhalb von ngOnChanges wir ein rxjs Subject , um ein Observable von Änderungen zu erstellen, dh:

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

Oder, wenn Sie etwas wiederverwendbareres möchten, können Sie eine Basisklasse erstellen, die Ihre Komponente 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);
    }
}

... die wie folgt verwendet werden könnten:

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

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

Ich wende diesen Ansatz an, bis ein offizieller @ObserveInput Dekorateur verfügbar ist.

Danke, @wmaurer. Ihr ReactiveComponent ist sehr willkommen, und zum Booten tadellosen Code und sicheres Tippen zu verwenden - wirklich nett! Wichtig ist, dass es sich auch im Test gut verhält und immer noch die Verwendung der Strategie zur Änderungserkennung OnPush . Jetzt warte ich gerne auf den "Amtszucker". (Außerdem werde ich sicher etwas lernen, wenn ich herausfinde, warum Sie die Observable.create() -Logik verwenden mussten - ich habe noch keine Zeit gefunden, mich damit auseinanderzusetzen.) Nochmal: merci gäll! :zwinkern:

@lephyrus gern geschehen, gärn gescheh ;-)

Ich habe Observable.create() , um ein Observer zu bekommen, um ein next() . Ich hätte ein Subject das sowohl ein Observable als auch ein Observer , aber ich glaube, es ist im Allgemeinen eine schlechte Praxis, ein Subject ( Observer ).

@laco0416 schließen zu Gunsten von https://github.com/angular/angular/issues/13248 ?

@DzmitryShylovich Nein. Die in dieser Ausgabe vorgeschlagene Funktion ist die schreibgeschützte und ereignisgesteuerte Datenweitergabe.

@ObserveInput wird super cool! :+1:

Danke @wmaurer für ein gutes Beispiel. Ich habe jedoch eine Frage. Ich möchte ein Objekt anstelle eines Strings als Observable verwenden können.

Z.B

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

Allerdings wird das this.updateChart und das ngOnChanges nicht aufgerufen. Wie können Sie Ihr Sample von einer einfachen Zeichenfolge erweitern, um stattdessen ein Objekt zu beobachten?

@ChrisWorks sollte auch mit Objekten funktionieren:

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

Ich mache dies sehr oft. Wenn dies nicht funktioniert, vermute ich, dass irgendwo ein Problem mit der Eingabe in Ihre Komponente vorliegt.

Hallo @wmaurer , danke für die Antwort. Könnten Sie Ihr Beispiel mit einer funktionierenden Version erweitern, in der Sie ein "config" -Objekt verwenden? Ich bekomme meine einfach nicht zum Laufen. Ein Beispiel für ein Git-Repository? :)

@ChrisWorks es sollte wirklich so funktionieren, wie es ist. observePropertyCurrentValue unterscheidet nicht zwischen einer String-Eingabe und einem Objekt.
Hier ist ein wirklich altes ng2 Beta 0-Projekt, das ich gemacht habe, bei dem Eingaben von allen verschiedenen Typen sind, nicht nur Strings:
https://github.com/wmaurer/todomvc-ng2-reactive
zB https://github.com/wmaurer/todomvc-ng2-reactive/blob/master/src/app/todo-item/todo-item.component.ts

+1 So ein grundlegender Anwendungsfall, ich kann nicht glauben, dass er noch nicht sortiert wurde!

Ich habe endlich die beste Lösung und sie funktioniert ohne Wiederholung und mit AOT-Kompilierung :) Das Geheimnis ist, @Input() mit einem zweiten Dekorateur zu kombinieren.

Der Dekorateur:

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                                                                                                                             
      },                                                                                                                                           
    })                                                                                                                                             
  }                                                                                                                                                
}                                                                                                                                                  

Verwendung:

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

EDIT: Ich habe dies jetzt zu einer Bibliothek gemacht. Freue mich über Ideen zur Verbesserung. Hinzufügen einer neuen Methode, die ein vorhandenes @Input mit einem Observable nächstes ergänzt. Siehe https://github.com/ohjames/observable-input

Wenn ich so etwas machen müsste, würde ich lieber ein einzelnes Thema analog zu ngOnChanges wählen: Subject<SimpleChanges>
Sie können immer noch filtern und nur einer bestimmten Eingabe zuordnen, wenn Sie möchten.

1 Betreff pro Eingabe scheint viel zu sein, ohne darüber zu sprechen, eine Klasseneigenschaft zu löschen, um Getter und Setter zu erstellen, und dass der Typ Ihrer Eingabe falsch ist und input = value tatsächlich den Wert für das Observable ausgibt und Sie nicht Abschluss Ihres Faches.

Ein Implementierungsbeispiel meiner Idee finden Sie hier , der Decorator-Ansatz ist experimentell, aber ich denke, es sollte ziemlich sicher sein, den Vererbungsansatz zu verwenden (denken Sie daran, dass ich ihn jetzt hier gezeigt habe, er wird nicht verwendet).

@ghetolay es spielt keine Rolle, ob der Betreff abgeschlossen ist, wenn die Ansicht geschlossen ist, gibt es keine weiteren Abonnements für den Stream und er kann vom GC verworfen werden. Das Ausgeben des Wertes auf das Observable ist im Grunde der Sinn davon. Der Angular-Compiler überprüft derzeit keine Eingabeeigenschaftstypen, hoffentlich wird bis dahin etwas Offizielleres verfügbar sein ;)

changes$ leckt die BehaviorSubject Schnittstelle zur Komponente, idealerweise sollte sie als Observable<...> eingegeben werden, ansonsten erscheint es vernünftig, wenn auch etwas ausführlicher.

Was die Ausgabe vieler Fächer angeht... egal, ob Sie n Fächer oder 1 Sie haben immer noch n Abonnements. Wenn Sie 1 Thema haben, fügen Sie jedem Abonnement einen Kartenoperator und einen Filteroperator hinzu. Der Leistungsaufwand dafür wäre nicht viel geringer als nur die Verwendung von n Themen, es könnte sogar noch schlimmer sein.

Da die Eingabe der Eingabeparameter selbst ignoriert wird, bietet die Decorator-basierte Version den Nutzern der Observablen eine typsicherere API als die SimpleChange Typen, die auf any basieren.

@ohjames

Wenn die Ansicht geschlossen ist, gibt es keine Abonnements mehr für den Stream und er kann vom GC entsorgt werden

Sie gehen davon aus, dass alle Abonnements an die Ansicht gebunden sind und denselben Lebenszyklus wie die Ansicht erhalten. Ich mache keine Annahme darüber, wie das Observable konsumiert wird.

Das Ausgeben des Wertes auf das Observable ist im Grunde der Sinn davon. Der Angular-Compiler überprüft derzeit keine Eingabeeigenschaftstypen, hoffentlich wird bis dahin etwas Offizielleres verfügbar sein ;)

Ich meinte für den Benutzer, der Benutzer kann immer noch auf die Eigenschaft zugreifen und sie festlegen. Es wird die Eigenschaft also so eingestellt, als ob es eine Zahl wäre, außer dass sie als Observable eingegeben wurde, und dies wird die Eigenschaft nie setzen, sondern ausgeben lassen. Das ist für mich sehr verwirrend.

Was die Ausgabe vieler Fächer angeht... egal ob Sie n Fächer verwenden oder 1 Sie haben noch n Abonnements. Wenn Sie 1 Thema haben, fügen Sie jedem Abonnement einen Kartenoperator und einen Filteroperator hinzu.

Auf diese Art von Debatte möchte ich hier nicht eingehen, da wir bald den Fokus auf den Hauptzweck verlieren werden.

Ich habe aktualisiert, um Subject nicht verfügbar zu machen, und etwas aufgebaut, um Änderungen durch Eingaben zu ergänzen.
Ich verwende kein BehaviorSubject sondern ein einfaches Subject weil ich diese Observables nicht als Werthalter sehe, sondern als Veränderungen im Laufe der Zeit.
Ich habe gerade einen Fehler gefunden: Bei Verwendung der asynchronen Pipe wird der erste Wert nicht ausgegeben, da die asynchrone Pipe nach der ersten Ausgabe abonniert wird. Ich werde meinen Code später aktualisieren, um diesen Fall richtig zu behandeln.

Hier nochmal der Link: https://stackblitz.com/edit/angular-observableinput?file=observablechanges%2Fimpl.ts

Sie gehen davon aus, dass alle Abonnements an die Ansicht gebunden sind und denselben Lebenszyklus wie die Ansicht erhalten. Ich mache keine Annahme darüber, wie das Observable konsumiert wird.

Okay, ich verstehe Ihren Standpunkt, das Vervollständigen der Observables erzwingt das Schließen aller Abonnements, aber das ist nichts, was mich wirklich beunruhigt. In unserer App erfolgen 99% der Abonnements über die asynchrone Pipe und in den wenigen, die sowieso nicht manuell geschlossen werden müssen, da sie häufig externe Observables von Redux/etc über CombineLatest/switchMap beziehen.

Auf diese Art von Debatte möchte ich hier nicht eingehen, da wir bald den Fokus auf den Hauptzweck verlieren werden.

Nun, Sie haben eine ungültige Kritik geäußert, also war es notwendig, dieser zu widersprechen.

~Auch die Verwendung Ihrer Klasse durch Vererbung funktioniert nicht, der vom AOT-Compiler generierte Code ruft keine Lebenszyklusmethoden in übergeordneten Klassen auf, siehe https://github.com/angular/angular/issues/12756#issuecomment -260804139, you 'muss ngOnDestroy() { super.ngOnDestroy() } und ein weiteres für ngOnChanges zu allen Consumern der Klasse hinzufügen.~ <-- scheint ab Angular 4.4 mit gewissen Einschränkungen behoben worden zu sein.

Ich habe meine Bedenken bezüglich der Verwendung der asynchronen Pipe überprüft, und da Sie immer noch Zugriff auf die Eingabe haben, glaube ich nicht, dass die Verwendung sinnvoll war. Wenn Sie nur den Eingabewert an die Vorlage binden möchten, können Sie einfach direkt an die Eingabe binden, ohne dass hier ein Observable und Async verwendet werden müssen. Und wenn Sie daraus ein neues Observable zusammensetzen möchten, sollten Sie in der Lage sein, genau das zu bekommen, was Sie wollen (wahrscheinlich mit startWith irgendwo).

Also ich finde meine vorherige Aussage ok:

Ich verwende kein BehaviorSubject, sondern ein einfaches Subject, weil ich diese Observables nicht als Werthalter, sondern als Veränderungen im Laufe der Zeit sehe. Wenn Sie Zugriff auf einen Eingabewert benötigen, ist die Eigenschaft weiterhin vorhanden und Sie können synchron darauf verweisen.

Dieser Code ist sehr experimentell, es ist nur eine Art Poc und ich habe damit nur auf diesem Stackblitz gespielt.
Ich hätte also nicht sagen sollen, dass es ziemlich sicher war und es möglicherweise nicht mit AOT funktioniert, wie Sie es gesagt haben.
Habe es gerade ausprobiert und beide Ansätze funktionieren derzeit mit AOT (Angular v4.3.6, cli v1.4.1).

Mein Hauptpunkt hier ist, dass Sie ausgehend von einem changes Observable, das alle Eingabeänderungen enthält, die Möglichkeit haben, mit Operatoren alles zu tun, was Sie brauchen: Reagieren, wenn sich eine Eingabe ändert, wenn sich nur eine Eingabe ändert, wenn eine beliebige Anzahl von Eingaben geändert, wenn es von einem bestimmten Wert zu einem anderen geändert wurde usw...
Sie können das gewünschte Observable zusammenstellen.

Außerdem muss nur 1 Thema für die Implementierung verwaltet und 1 Eigenschaft für den Benutzer verwendet werden, im Gegensatz zu 1 pro Eingabe.

Die Sache, die ich ändern könnte, wäre, nur neue Werte auszugeben und kein SimpleChanges Objekt, da der Benutzer wahrscheinlich pair und map , um dieselbe Struktur wie SimpleChange . Aber derzeit haben wir SimpleChanges also wäre es albern, es zu zerlegen, nur um später etwas Ähnliches wieder zusammenzusetzen.

PS:

Nun, Sie haben eine ungültige Kritik geäußert, also war es notwendig, dieser zu widersprechen.

für dich ungültig .

Es ist kein persönlicher Standpunkt, wenn wir von Leistung sprechen, sondern objektiv messbare Fakten. Sie haben das Gefühl, dass 3 Probanden mehr Aufwand bedeuten als 6 zusätzliche Bediener. Sicher haben Sie vielleicht Recht, aber es gibt keine rationale Grundlage, dies zu glauben, bis Sie einige Messungen vornehmen.

Was das Reagieren auf viele Eingaben angeht, können Sie natürlich einfach switchMap oder CombineLatest oder einen der anderen Operatoren verwenden, die für die Arbeit mit mehreren Observablen entwickelt wurden. Sie machen diesbezüglich sehr kühne und pauschale Aussagen. Wenn Sie dieses Gespräch wirklich fortsetzen möchten, nehmen wir es aus diesem Issue-Tracker.

Hier ist eine Version mit verschiedenen Nachteilen und Vorteilen, die jedoch eine Basisklasse erfordert:

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()
  }
}

und zu verwenden:

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')
}

Ich bin mir nicht sicher, ob ich das Problem falsch verstanden habe, aber löst die asynchrone Pipe dieses Problem nicht?
[inputVar]="observableValue | async" ..

@najibla Sie haben falsch verstanden, Eingaben sind keine Observablen, daher hilft die asynchrone Pipe nicht.

@ohjames Nun, in meinem Fall hat es mit der asynchronen Pipe für ein Observable funktioniert. Und wenn ich den beobachtbaren Wert der übergeordneten Komponente aktualisiere, wird der Wert in der untergeordneten Komponente widergespiegelt.

@najibla Bei diesem Github-Problem geht es darum, @Input Eigenschaften in Observables zu verwandeln.

dh Sie sollten in der Ansicht keine Eingabeeigenschaften in ein Observable umwandeln müssen, ob eine Komponente auf die Änderung der Eingabeeigenschaft mit einem Observablen reagiert oder nicht, sollte in einer Komponente selbst isoliert werden. Andernfalls müssen Sie die Schnittstelle Ihrer Komponente ändern, wenn Sie sich entscheiden, eine Eigenschaft als Observable zu konsumieren, was im Widerspruch zum üblichen Ansatz von angle "observable first" steht.

@icepeng Eigentlich hast du das nicht ganz richtig, hier geht es darum, eine Standardeingabe in eine Observable zu verwandeln. Das neue Muster wäre also eigentlich:

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

... dann bietet es eine Möglichkeit, auf prop innerhalb von AppChildComponent als Observable zuzugreifen, obwohl es keine Observable ist (oder wenn es eine Observable wäre, würden Sie eine Observable von Observablen erhalten ). Wenn Sie nun wie in Ihrem Beispiel zuerst prop$ erscheint es möglicherweise nicht sinnvoll (Sie können das Observable jetzt bereits mit Eingaben übergeben). Es bietet jedoch viel Wert, wenn die übergebene Eingabe nicht bereits ein Observable ist (zB ein index von einem ngFor ).

Das Problem beim Übergeben einer Observablen mit einer Eingabe (was im Moment durchaus möglich ist) besteht darin, dass es mit OnPush nicht ganz funktionieren würde.

@fxck Nun, Sie haben Recht, dass ngOnChanges nicht aufgerufen wird, wenn das Observable ausgibt (weil die Eingabe gleich bleibt), sondern solange Sie die asynchrone Pipe verwenden, um ein durch @Input Observable zu abonnieren OnPush funktioniert gut, da die asynchrone Pipe den Änderungsdetektor der untergeordneten Komponente manuell auslöst.

Ja, es war an @icepeng gerichtet.

@ohjames @fxck Ich wusste nicht, dass die Weitergabe von Observables im

Da das direkte Passieren von Observablen möglich ist, bin ich mir nicht sicher, ob @ObserveInput nützlich wäre.
Ich denke, wenn der Wert, der geändert werden kann, nicht beobachtbar ist, ist dies bereits ein Problem.
Nur eine persönliche Meinung.

@icepeng Betrachten Sie

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

Wie kann man index als Observable konsumierbar machen, ohne durch Reifen zu springen?

Oder denken Sie auch daran, dass Sie eine Drittanbieterbibliothek schreiben und die Benutzer Ihrer Bibliothek nicht dazu zwingen möchten, Observables an Ihre Komponente zu übergeben (viele Benutzer sind mit Streams nicht vertraut und vermeiden rxjs).

Es gibt viele andere Fälle, in denen dies nützlich ist.

@ohjames index wäre ein statischer Wert für jedes child-component , daher glaube ich nicht, dass es beobachtbar sein muss. Jetzt verstehe ich jedoch, warum die Leute diese Funktion wollen. Und Ihre Lösung scheint gut zum Schreiben von Bibliotheken von Drittanbietern zu sein.

BehaviorSubject Ansatz scheint besser zu sein, wäre schön, wenn Angular-Kern einen solchen @NgChanges() Dekorator bereitstellen würde.

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

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

Ist dies umsetzbar?

Ein ReplayObservable mit einer Pufferlänge von 1 wäre vorzuziehen, die Wertsemantik von BehaviourSubject ist nicht erforderlich, wenn Sie auch Zugriff auf die Eigenschaft haben.

Ob eine Implementierung möglich ist, können Sie in der Problemhistorie für viele verschiedene Implementierungen und Optionen überprüfen. Keine ist großartig und einige sind völlig kaputt, um es richtig zu machen, brauchen wir die verlinkte PR oder etwas Ähnliches.

meine 2 Cent: da object.observe zugunsten der Proxys abgewertet wurde, war meine Lösung, einen Proxy zu erweitern (ja, ich kann nicht wissen, warum ich ihn vom Konstruktor zurückgegeben habe) und dann auf jeden dazu gehörenden Schlüssel zu hören -Objekt als Observable über die $get(keyName)-Methode. Sie können es mit jedem Objekt verwenden, nicht nur mit Winkelklasse 1.

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

Beispiel:

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 , gibt es zu diesem Thema eine

@bryanrideshark Die beste Chance, dass dies unterstützt wird, ist über https://github.com/angular/angular/issues/10185 Ich denke, überrascht, dass PR nicht mit diesem Problem verbunden ist.

Dies wird erst passieren, nachdem wir Ivy versendet haben
Am Mittwoch, den 21. Februar 2018 um 7:56 Uhr schrieb James Pike [email protected] :

@bryanrideshark https://github.com/bryanrideshark Die beste Chance auf
dies wird unterstützt durch #10185
https://github.com/angular/angular/issues/10185 Ich denke, überrascht, dass
PR ist nicht mit diesem Thema verbunden.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/angular/angular/issues/5689#issuecomment-367372931 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAgpkvtGA4w8uHgiz0QsdYwBgqgM2EpAks5tXDyWgaJpZM4Gwr8f
.

Ihr Englisch ist großartig und Ihr Winkel ist größer.

@pldin601 Ihre Methode unterstützt keinen AOT-kompilierten Code, daher führt dies zu großen Speicherlecks für den Produktionscode der meisten Leute. Schauen Sie sich stattdessen mein observable-input Paket an, das gut mit AOT funktioniert.

@pldin601 Das Problem mit Ihrem Code besteht darin, dass er die Lebenszyklusmethode ngOnDestroy dynamisch hinzufügt. Der von AOT kompilierte Code ruft nur ngOnDestroy wenn der Compiler statisch auf seine Existenz schließen konnte. Ihre Methode funktioniert also nur, wenn jede Komponente, die den Dekorator verwendet, auch ein ngOnDestory (es kann leer sein, wenn es nicht benötigt wird). In allen anderen Fällen werden Abonnements durchgesickert, wodurch verhindert wird, dass Komponenten von der Garbage Collection erfasst werden.

Ich denke, das wird passieren, nachdem Abschnitt 3.2 abgeschlossen ist (und hoffentlich wird dieser Bedarf berücksichtigt) ?
https://is-angular-ivy-ready.firebaseapp.com/#/status

Wird Ivy Teil von 7.0.0 sein?

Ich habe einen Dekorator implementiert, der eine Eigenschaft an eine beobachtbare Begleiteigenschaft binden kann. Es kann für Winkeleingabeeigenschaften verwendet werden, aber auch für jede andere Eigenschaft. Es ist inspiriert vom @ObservableInput() Dekorator von @ohjames , vermeidet jedoch mögliche Probleme, die durch -Settern verursacht werden, indem eine andere Eigenschaft verwendet wird, um das Observable bereitzustellen.

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

Beispiel:

class MyClass {

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

}

const myInstance = new MyClass();

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

myInstance.myProp = 'newValue'

Dieser Code gibt die Werte 'initialValue' und 'newValue' an die Konsole aus.

Jedes Update, wann dieses veröffentlicht wird, das observable-input Paket scheint das eleganteste zu sein, ohne etwas zu beschädigen + keine Unterklassen. @ohjames Wie stabil / gut getestet ist das zu diesem Zeitpunkt?

Ich denke, der offizielle Support wäre ausgereifter, garantiert kontinuierliche Unterstützung über mehrere Versionen hinweg und eine reibungslosere Entwicklungserfahrung / ermutigt Entwickler, vollständige rxjs * zu verwenden und mit der Erkennung von Push-Änderungen zu optimieren (dies sollte meiner Meinung nach eine bahnbrechende Kernfunktion sein).

*ohne die Kompatibilität mit nicht beobachtbaren Eingaben zu beeinträchtigen oder zusätzliche Boilerplate für Hybrideingaben zu benötigen, dh: Setter ruft als nächstes zum Thema an

Verwendete Observable-Eingabe in Winkel 4, 5 und 7 mit und ohne aot. Es scheint gut zu funktionieren. Ich bin mir ziemlich sicher, dass ich vage wusste, was ich tat, als ich es schrieb.

Ich hoffe, sie werden es in das Framework aufnehmen und seine Nutzung fördern 2 wöchentliche Downloads npm ist nicht genug im Vergleich zu den Vorteilen, die es bietet xD Wenn sie es hinzufügen, werden die Leute sicher sehen, dass es einfach ist, diesem Ansatz zu folgen

Ich schlage folgende API für asynchrone Eingaben mit benutzerdefinierten observer

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

Benutzer könnten es einfach so verwenden

@AsyncInput()
asynchronusProperty1 = new Subject();

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

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

Angular Internal kann immer observer.next(newValue) aufrufen, wenn sich der Wert ändert.

Vergessen Sie auch nicht die Unterstützung von @HostBinding !

Dies sollte mit der @Input- Injektion des Konstruktors beeindruckender zu machen. Auf diese Weise könnten wir "strictPropertyInitialization" auf sehr elegante Weise beheben:

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

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

}

@benneq nur erwähnenswert, es könnte so klein sein wie:

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

@maxime1992 yep, obwohl Sie einen separaten Dekorator für Eingaben als Observablen benötigen, um zu unterscheiden, ob Observablen von einer Komponente an eine andere übergeben werden.

@benneq @maxime1992 Parameternamen sind nicht Teil der Decorator-Metadaten. Wie wird sie zugeordnet?

@trotyl Ich denke du könntest dann @Input('paramName') private myParam: Observable<Data>

@trotyl @benneq ja mein schlecht. Egal :zipper_mouth_face:

Ich weiß nicht, ob jemand diese Lösung bereits gepostet hat, aber dies ist ein ziemlich guter Workaround

@ElianCordoba Hier geht es nicht um HTML <input> . Es geht um eckige @Input()

Das ist ein anderes, aber ähnlich schmerzhaftes Problem @ElianCordoba. https://github.com/angular/angular/issues/13248

Ich denke, das ist eine Pseudo-Anforderung. Erstens kann der Eingabedekorator einen Observable-Typwert akzeptieren, zweitens sollte die Komponente, wenn die Komponente eine Observable als Eingabe erfordert, beim Empfang eines nicht beobachtbaren Werts explizit einen Fehler auslösen, anstatt ihn stillschweigend in einen Observable-Typwert zu konvertieren.

Es ist der impliziten Typkonvertierung in Javascript sehr ähnlich, kann verwechselt werden, sogar Fehler verursachen und schwer zu finden sein.

Es geht nicht darum, falsche Eingaben zum Schweigen zu bringen. Es geht darum, eine gemeinsame Schnittstelle für alle Komponenten bereitzustellen (die eine nicht beobachtbare Eingabe ist). Dies gibt Ihnen die Freiheit, rx-Funktionalität einzuführen, ohne die Schnittstelle in der Außenwelt zu beschädigen. Ein weiterer Vorteil besteht hauptsächlich darin, die Veränderlichkeit und den internen Zustand aufzuheben, da alles eine Transformation der Eingabe ist, was die Erkennung von Push-Änderungen von diesem Zeitpunkt an zu einem Kinderspiel macht.

Im Gegenteil, eine Schnittstelle, die Observables erfordert, klingt klobig und zwingt die Leute, einen (Wert) bereitzustellen, nur weil Ihre Komponente dies sagt, klingt für mich seltsam.

Außerdem geht es nicht um eine stille Konvertierung, sondern um eine API zum Abonnieren von Änderungen über rxjs. Angesichts der Tatsache, dass angle.http und der Router Observables bereitstellen, ist es sehr umständlich, dass die Handhabung von Eingabeänderungen dies nicht tut. Die Vereinheitlichung der Welten der Callbacks und RxJs erfordert zu viel Boilerplate.

Nicht, dass ich einige der oben genannten cleveren Lösungen nicht liebe, aber manchmal reicht nur eine leichte Neuorganisation der "Standard" -Methode, um das eigentliche Problem hier zu lösen, das Mangel an Klarheit / Ungeschicklichkeit ist. Außerdem hoffe ich immer noch auf einen "offiziellen" Post-Efeu-Weg, dies eines Tages zu tun.

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

Dann können Sie einfach etwas wie combineLatest(this.service.magicInput$, this.inputs, config$)...... eingeben, um Eingaben mit RxJS zu kombinieren.

Entweder BehaviorSubject oder ReplaySubject funktioniert. BehaviourSubject ist normalerweise sicherer und vorhersehbarer.

  • BehaviorSubject - verwenden, wenn Sie eine Standardeinstellung haben
  • ReplaySubject - Observable wird nicht ausgegeben, wenn Sie vergessen, den Eingabewert festzulegen

Dies hilft nicht nur bei der Codeklarheit, sondern weil ich alle Eingaben zusammen gruppiere, kann ich leicht erkennen, was eine "reine" beobachtbare Eingabe ist, indem ich einfach this.inputs. eintippe und die automatische Vervollständigung erhalte.


Damit können Sie mit der Typsicherheit weiter gehen (meistens ist dies nur zum Spaß).

// 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>;

Dann müssen Sie den Typ der @Input- Eigenschaft nicht explizit angeben.

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

Ich hätte eine ObservableInputs-Schnittstelle für die Komponente erstellen können, um inputs zu erzwingen, habe mich aber dagegen entschieden, da sie sowieso nicht kompiliert wird, wenn Sie dies vermasseln.

@simeyla Zu viel Boilerplate.

Ich beschloss, meinen eigenen Dekorateur da draußen zu stellen. Es ist mein erstes npm-Paket, also vermisse ich sicher etwas, aber hier ist es: https://www.npmjs.com/package/@ng-reactive/async -input

Installation

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

Verwendung

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 wirklich nett, ich sehe keinen Grund, warum so etwas nicht eingebaut werden sollte. Zu Ihrer Information, der Github-Link auf npm für das Paket ist veraltet, er geht hierhin:

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

Ich sehe, dass dies ein ziemlich altes Problem ist, aber die Funktion ist ziemlich erstaunlich und ich bin wirklich gespannt, sie in Angular zu sehen.

Was noch cooler ist, ist, dass Sie bei beobachtbaren Eingaben keinen OnChanges -Hook benötigen - Sie können den pairwise rxjs-Operator verwenden, um vorherige und aktuelle Werte der Eingabeobservablen zu erhalten:

@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

Es ist meine persönliche Implementierung, es funktioniert perfekt und ziemlich genial, wenn wir es einbauen können, ist das wirklich cool.

Ich habe die Lösung, die ich persönlich in meinen Projekten verwendet habe, als npm-Paket veröffentlicht:

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

Installation

npm install ngx-observable-input

Verwendung

...
<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>;

    ...
}

Ich sehe, dass dies ein ziemlich altes Problem ist, aber die Funktion ist ziemlich erstaunlich und ich bin wirklich gespannt, sie in Angular zu sehen.

Was noch cooler ist, ist, dass Sie bei beobachtbaren Eingaben keinen OnChanges -Hook benötigen - Sie können den pairwise rxjs-Operator verwenden, um vorherige und aktuelle Werte der Eingabeobservablen zu erhalten:

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

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

Dies ist ein Problem, das mich auch seit einiger Zeit beschäftigt, daher habe ich ein wenig recherchiert und bin auf die gleiche Lösung gekommen, die Sie hier erwähnen (@gund).

Ich habe einen kleinen Dekorator-Helfer ( @ObservableInput ) implementiert, der den @Input Dekorator intern erweitert und diese Art der Komposition ermöglicht. Hier können Sie es sich ansehen (auch als npm-Paket ). Ich habe mit einfachen Beispielen herumprobiert, aber ich hatte nicht die Zeit, es für erweiterte Projekte zu verwenden. Jedes Feedback ist willkommen :)

Hier ein Anwendungsbeispiel:

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

Und diese Komponente kann wie folgt verwendet werden:

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

@aleics Sind Sie sicher, dass dies mit dem AOT-Compiler funktioniert?

@aleics Sind Sie sicher, dass dies mit dem AOT-Compiler funktioniert?

Nein, natürlich nicht sofort, da die Eigenschaft @Input nicht explizit definiert ist. Aber Sie könnten Ihr Modul mit CUSTOM_ELEMENTS_SCHEMA , wie bei der Verwendung von Webkomponenten, und dann sollte es kompiliert werden.

Diese Ausgabe ist seit 5 Jahren geöffnet 🤦‍♂ . Ich denke, es ist notwendig, dies zu haben, um einen reaktiven Programmieransatz zu ermöglichen

Ivy ist endlich da, also hat wohl jemand Zeit, daran zu arbeiten? Bitte bitte bitte!

Omg ich unterschreibe, dass dies sehr nötig ist. Eingabedaten sollten als reaktive Quelle ausgegeben werden, und Sie müssen einen Workaround verwenden, damit dies in einem ngOnChanges funktioniert

Freue mich schon sehr darauf

Mir ist klar, dass Angular Open Source ist, aber ist es falsch oder naiv von mir zu glauben, dass ein von Google durchgeführtes Projekt in der Lage sein sollte, in weniger als 5 Jahren stark markierte und angeforderte Probleme zu lösen? Gibt es einige mir nicht bekannte finanzielle Probleme, die Google daran hindern, weitere Entwickler für die Arbeit an Angular einzustellen?

@etay2000 Ich weiß es nicht, ich finde es irgendwie komisch, wie man 75% der Dinge in Angular mit rxjs machen kann und dann für etwas so grundlegendes und häufig verwendetes wie Komponenteneingaben plötzlich in die Prozedur gezwungen wird Welt. Sie haben immer diesen wichtigen Teil Ihres Projekts, der mit der Welt der Observables nicht funktionieren kann, also sind Sie immer gezwungen, Boilerplate zu verwenden, um sie wieder zusammenzukleben. Sie können nie einen voll funktionsfähigen Ansatz für Ihr Projekt erreichen. Diese Ausgabe, die seit 4 Jahren offen ist, erinnert mich an den Mangel an Pragmatismus, der mich von Angular weg und in andere Frameworks getrieben hat, dafür ist es ziemlich nützlich. Wenn Sie rxjs für alles verwenden möchten, ist vielleicht cycle.js die bessere Lösung, und wenn Sie nicht gezwungen werden möchten, rxjs zu verwenden, ist Vue vielleicht eine. Observables die Hälfte der Zeit verwenden zu müssen und die andere Hälfte nicht verwenden zu können, macht einfach keinen Sinn. Eine sehr mächtige Abstraktion mit einer hohen Lernkurve zu integrieren und sie dann nicht vollständig zu integrieren, ist einfach verwirrend.

Ich habe das Gefühl, dass die Priorisierungskette so verläuft

Anforderungen interner Google-Benutzer -> alles, was damit zu tun hat, dass der Compiler schneller ist -> alles, was damit zu tun hat, dass die App-Größe kleiner ist -> alles, was Neulinge nicht verärgert -> was Entwickler eigentlich wollen

Und obwohl die Tech-Leads sagen würden, dass sie sich einig sind, dass es wichtig ist, ist es so, dass Igor und Misko dazu neigen, über die meisten Probleme in Bezug auf Vorlagenkompilierung, Ansichtszuordnungen und Rendering nachzudenken. Egal, was die Verbraucher von Angular sagen, ist ihnen wichtig, die Lösung besteht immer darin, das Vorlagensystem zu ändern, einen neuen Renderer zu schreiben oder den Compiler zu verbessern.

Quelle: https://medium.com/@jeffbcross/jeffs-letter-to-the-angular-team-and-community-5367934a16c9)

Schauen Sie sich nur einige der am meisten empfohlenen Probleme an.

Vorschlag: Eingabe als Observable #5689

Erstellt vor 5 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 5 Jahren, aktueller Status unbekannt.

Unterstützen Sie kalte Ereignisstreams in den Vorlagen #13248

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 1 Jahren, aktueller Status - wartet auf die Landung von Ivy.

Vorschlag: Bereitstellung von Komponentenlebenszyklus-Hooks als Observables #10185

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 3 Jahren, aktueller Status unbekannt.

Vorschlag: Möglichkeit zum Hinzufügen von Direktiven zu Hostelementen in der Komponentendeklaration erforderlich. #8785

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 2 Jahren, aktueller Status unbekannt.

as local-val ohne *ngIf #15280

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 2 Jahren, aktueller Status unbekannt.

Unterstützung für dynamische Inhaltsprojektion #8563

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - vor 3 Jahren, aktueller Status unbekannt.

ng-content Standardinhalt #12530

Erstellt vor 4 Jahren, letzte Antwort von einem relevanten Teammitglied - nie, aktueller Status unbekannt.

Dann gibt es Dinge wie Komponentenfunktionen, die Komponenten höherer Ordnung ermöglichen würden, dann gibt es natürlich noch viele weitere am meisten empfohlene Probleme, aber ich hoffte, dass diese angegangen werden (das heißt, dass sie angegangen werden, nicht unbedingt erwarten, dass sie sofort nach Ivy implementiert werden ).

Meine App ist voll von halb gebackenen (einfach aufgrund technischer Einschränkungen, einige können nur im Kern richtig gemacht werden) „Polyfills“ und Hacks für die meisten dieser Probleme, in der Hoffnung, dass ich eines Tages in der Lage sein werde, einen eckigen Eingeborenen zu besuchen Ersatz. Aber irgendwie scheint es nicht zu kommen.

Also ja, sagen wir, dass ein Blog-Post, der sich mit dem Zustand einiger der größten Reaktivitäts-/Entwicklererfahrungsprobleme befasst, wirklich dankbar wäre.

Wie wäre es, wenn wir versuchen, eine erste Version dieser Funktion selbst zu programmieren? Ich bin
sterben vor Langeweile während des Covid-Dings, wer will mit?

Mehrere Leute haben es bereits getan, z. https://github.com/insidewhy/observable-input

Das Problem bei den meisten davon besteht darin, dass Sie den Compiler oder andere interne Teile von angle ändern müssen, um sie effizient auszuführen.

Das zählt nicht. Ich meine, lasst uns einen ordentlichen Beitrag zum Winkel leisten
Ader. Immerhin haben wir den Quellcode zur Verfügung. Eigentlich glaube ich nicht, dass wir in diesem Fall den Compiler anfassen müssen.

@ganqqwerty Ich habe versucht, es in Angular zu implementieren, bevor ich diese Bibliothek geschrieben habe. Angular ist jedoch extrem kompliziert. Um fair zu sein, der Code ist viel lesbarer und verständlicher als React und seine verrückten fünfhundert Zeilen langen Funktionen, aber er ist "ausgereift". Und ich hätte mich immer noch gerne um diese Implementierung bemüht, wenn ich dachte, dass es sich lohnt. Aber ich sehe es aus genau den Gründen, die @fxck oben iteriert hat, nicht als lohnenswert an. Das Angular-Team hört nicht auf die Community, es ist ständig besessen von Optimierungen und Leistung, ohne sich um die Benutzerfreundlichkeit von Angular im Allgemeinen zu kümmern. Ich interessiere mich nicht für ein Framework, das gut funktioniert, wenn es mich zwingt, Boilerplate für einfache Probleme zu implementieren, die vor fünf Jahren demonstriert wurden. Also beschloss ich, mich nicht mehr um Angular zu kümmern, den minimalen Aufwand zu implementieren, den ich brauchte, um die Projekte, an denen ich bereits arbeitete, zu unterstützen und ihn für alle zukünftigen Projekte wo und wann immer möglich zu vermeiden.

Das ist glaube ich nicht nur bei Angular ein Problem, sondern bei vielen Angeboten von Google. Dieses Problem und die anderen, die @fxck oben aufgelistet hat, sind nur weitere Beispiele für endemische Probleme bei Google. Wenn Sie sich Dart oder GoLang ansehen, werden Sie auch sehen, dass Entwickler sehr bekannte häufig auftretende Probleme ansprechen und dass die Probleme 5+ Jahre lang offen bleiben.

Ich stimme zu, dass dies hinzugefügt werden sollte, aber wow, der Hass auf diesen Thread ist ein bisschen viel, ich meine, wir reden darüber, etwas hinzuzufügen, das ein paar Zeilen Code spart. Sie können jetzt Observablen-Eingaben mit einem Setter haben, der mit @Input verziert

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

Wenn das zu viel Boilerplate ist, haben wir bereits einige einfache Optionen von Drittanbietern:

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

Ich bin mit der Entwicklung von Angular zufrieden und würde das erstaunlich voll funktionsfähige und zuverlässige Framework sicherlich nicht wegen einer so kleinen (wenn auch wünschenswerten) Funktion aufgeben

Das allgemeine Problem besteht hauptsächlich aus der Perspektive der Menschen. Für jemanden sind es ein paar Codezeilen und es sieht ziemlich einfach aus, alles zu ändern/hinzuzufügen, aber in Wirklichkeit gibt es einen viel größeren Umfang und viele Nebenwirkungen. Sie alle müssen berücksichtigt werden und wie immer ist die Themenlinie lang und alles hat seinen Selbstkostenpreis, Mehrwert und Priorität.

Ich möchte darauf hinweisen, dass ich persönlich nicht unbedingt erwarte, dass alle diese Probleme sofort gelöst werden.

Aber ich würde hoffen, dass jetzt, da Ivy aus dem Weg ist und eine Weile in freier Wildbahn war, eine Art offizielles Update zu den beispielsweise Top 25 der positiv bewerteten Ausgaben veröffentlicht wird.

Ich meine, ich finde es nicht möglich, dass ein Projekt dieser Größe im Projektmanagement keine Priorität hat und eine Art Plan für alle der 25 (oder was auch immer) Top-Upvoted-Themen. Die meisten davon haben sogar ein effort Tag. Machen Sie einfach einen Blog-Beitrag, lassen Sie die Community wissen, dass Sie davon wissen und Sie einen Plan dafür haben.

Auf Angular würde ich auch nicht verzichten, mir gefällt es trotz all seiner Mängel immer noch viel besser als alle anderen Alternativen. Aber ich denke, es ist fair zu sagen, dass es an "Community-Relations-Management" (insbesondere auf Github) gefehlt hat.

// bearbeiten

Würden Sie guten Leuten etwas ausmachen, diese Umfrage auszufüllen? Welches dieser Probleme betrifft Sie angesichts Ihrer aktuellen Situation und aller Faktoren am meisten / würde Ihre Entwicklererfahrung am meisten verbessern https://forms.gle/cprhx239kuqwWd5M8

@fxck Danke, dass

Auf Angular würde ich auch nicht verzichten, mir gefällt es trotz all seiner Mängel immer noch viel besser als alle anderen Alternativen. Aber ich denke, es ist fair zu sagen, dass es an "Community-Relations-Management" (insbesondere auf Github) gefehlt hat.

Ich denke, dieser Satz fasst meine Gedanken perfekt zusammen.

@chriszrc Ich habe in diesem Thread nichts wirklich als "Hass" interpretiert. Eher wie Leute, die endlich ihre Frustration über Angular auslassen und Probleme regelmäßig über Jahre hinweg ignorieren. Es geht nicht einmal speziell um dieses Thema, es geht vielmehr um das Prinzip, eine Form der Interaktion mit der Gemeinschaft aufrechtzuerhalten. Wird das Angular-Team als allen anderen so weit überlegen angesehen, dass es das Gefühl hat, Entwickleranfragen ignorieren zu können, weil es weiß, was für alle das Beste ist?

@chriszrc Ich sehe in diesem Thread keinen Hass, nur eine Menge verständlicher Frustration. Ich halte es für übertrieben, diese Bitte und die damit verbundene Enttäuschung mit "ein paar Zeilen Code sparen" gleichzusetzen. Es ist nicht nur dieses Problem, das die Community frustriert, sondern die bedeutende Sammlung beliebter Probleme, die @fxck oben

Hallo zusammen, entschuldigen Sie die Stille in diesem Thread. Es gibt zwei orthogonale Anfragen, die wir seit einiger Zeit erhalten:

  1. Bessere erstklassige RxJS-Unterstützung im Framework
  2. Weniger RxJS in Angular, was es möglicherweise optional macht

Beide Anfragen sind auf unserem Radar, und beide haben ihre Vor- und Nachteile. Wenn wir beispielsweise die erste Richtung einschlagen, machen wir das Framework für Ingenieure, die mit der ausdrucksstarken, semantisch reichhaltigen API von RxJS noch nicht vertraut sind, weniger zugänglich. Viele Leute haben Bedenken, RxJS überall in ihren Angular-Apps zu verwenden, was es schwierig macht, den Quellcode von Teammitgliedern mit unterschiedlichen Erfahrungsstufen zu lesen.

Gleichzeitig haben wir bereits viele reaktive APIs, aber einige der von Angular angebotenen Primitiven sind absolut unerlässlich, und die Dinge lassen sich nicht ganz gut verkabeln. Trotzdem ist es sinnvoll, die Reaktivitätsunterstützung zu verbessern, aber sollte dies Teil des Kerns von Angular sein oder an ein Community-Projekt (z. B. ngrx - die reaktive Erweiterung von Angular) delegiert werden, mit dem wir eng zusammenarbeiten?

Es gibt viele Möglichkeiten, dieses Problem zu lösen, aber wir müssen Folgendes berücksichtigen:

  • Abwärtskompatibilität – nicht nur für Quellcode, sondern auch für Schulungsressourcen
  • Lernkurve
  • Konsistenz mit aktuellen APIs
  • Konsistenz über Projekte hinweg
  • Leistung - sowohl Laufzeit als auch anfängliche Ladezeit

Wir sind dabei, einige der wichtigsten GitHub-Probleme zu priorisieren und uns die am häufigsten gewünschten und wirkungsvollsten Verbesserungen anzusehen, die wir angehen können. Ich würde sagen, dass dies eine der schwierigeren ist, daher ist es schwierig, sich auf ein Date festzulegen.

@mgechev Danke für die Antwort. Wenn die rxjs und die reaktiven APIs in eine andere Erweiterung aufgeteilt werden (nicht meine persönliche Stimme), wäre es möglicherweise sinnvoller, dies nicht mit einer bestimmten State-Store/Redux-Implementierung zu verbinden? Ich wechselte schnell von ngrx zu ngxs (was sich wie viel weniger Boilerplate und viel "eckiger" mit Dekorateuren anfühlte) und dann schließlich zu Akita, das mein derzeitiger Favorit ist und mit dem ich am meisten entwickelt habe. Oder wenn es mit ngrx in einen Topf geworfen wird, machen Sie es zumindest wirklich einfach, nur die benötigten Teile hinzuzufügen, damit wir nicht darauf beschränkt sind, ngrx zu verwenden oder diese Abhängigkeiten einzubeziehen.

Wenn die rxjs und die reaktiven APIs in eine andere Erweiterung aufgeteilt werden (nicht meine persönliche Stimme)

Ich sage nicht, dass das passieren wird. In meinem Kommentar teile ich nur eine unvollständige Liste von Alternativen, damit ich den Umfang des Projekts und die verschiedenen Überlegungen, die wir haben, aufzeigen kann.

@mgechev in der Tat, danke für die Antwort.

Ich frage mich jedoch, wenn der reaktive Teil von Angular irgendwie in das Gemeinschaftsprojekt "degradiert" wird, würde das nicht bedeuten, dass reaktiv ein Bürger zweiter Klasse von Angular wird?

@mgechev Ich fühle, wie dein Schmerz gleichzeitig in zwei Richtungen gerissen wird. Unser Team ist eigentlich nicht dagegen, die zwingenden / reaktiven Teile aufzuteilen.

Hier wären unsere Anforderungen für eine solche Aufteilung:

  • Verwenden Sie sowohl das zwingende als auch das reaktive Bedürfnis, sich heimisch zu fühlen, und keines von beiden sollte sich angeschnallt fühlen
  • Keine Verbindung mit einer bestimmten State-Management-Lösung, um reaktive zu ermöglichen (vollständige Offenlegung, wir haben inzwischen alle über 50 Projekte auf Akita migriert)
  • Beide Optionen müssen gleichzeitig in einer einzigen Version veröffentlicht werden (kein Lag / Delay)
  • Es kann keinen "Favoriten" geben, alles, was kantig ist, müsste in beiden Welten funktionieren, während man sich heimisch fühlt
  • Vollständige offizielle Unterstützung für beide Ansätze, unterstützt durch das Angular-Team (Basierend auf unserer Erfahrung ist dies eine harte Kundenanforderung des Kunden)

Basierend auf dem oben genannten:

  • Es gibt 2 Hauptoptionen:

    • Kern-Imperativ + Add-On reaktiv

    • Core Reaktiv + Add-On Imperativ

  • Reaktiv zu verpacken, um es zwingend erscheinen zu lassen, ist ziemlich einfach, nicht umgekehrt
  • Daher würden wir dafür stimmen, im Kern reaktive zu verwenden und das Add-On die zwingenden APIs zu enthalten
  • Aufgrund der Nullverzögerung + keine Favoritenanforderung sowie erforderlicher offizieller Support sehe ich nicht, wie das Addon ein Community-Projekt sein kann

Ich verstehe, dass das oben Genannte unsere Sicht der Welt ist und es noch viele andere gibt. Der Grund, warum ich dies schreibe, ist:

  • Wenn Sie reaktiv in ein Community-Projekt extrahieren, müssen wir über 50 Lösungen in ein anderes Framework migrieren (auch dies wird kundenorientiert sein, nicht unsere Wahl).
  • Daher möchte ich Sie bitten, uns (der Community) so schnell wie möglich mitzuteilen, wo Sie hier landen, damit wir Zeit haben, unsere Entwickler auf ein anderes Framework umzuschulen und diese Projekte zu migrieren

füge die Funktion bitte hinzu

@mgechev Ich verstehe deine Bedenken nicht. Bei diesem Vorschlag geht es darum, die beiden Welten mit einer einheitlichen und unkomplizierten Benutzeroberfläche für Anfänger zu kombinieren. Es geht nicht darum, das eine oder andere auszuwählen, sondern die Kombination zu ermöglichen. Zum Beispiel beschließt Entwickler x, eine großartige reaktive Komponente zu bauen. Und Entwickler y beschließt, es in seinem nicht so reaktiven Projekt zu verwenden. Warum nicht? Warum muss er auf irgendeinen ngrx-Kleber angewiesen sein?
Der Unterschied zwischen den beiden Welten besteht darin, ob Sie den Zustand in Ihrer ultimativen intelligenten Komponente oder im zentralen Zustandsspeicher speichern/verwalten, und darum sollte es bei ngrx gehen, aber für Komponenten denke ich, dass das Framework selbst der Enabler sein sollte.

Es gibt zwei orthogonale Anfragen, die wir seit einiger Zeit erhalten:

  1. Bessere erstklassige RxJS-Unterstützung im Framework
  2. Weniger RxJS in Angular, was es möglicherweise optional macht

Mir wäre so oder so gut, aber manchmal, manchmal, gibt es Angular ein unzusammenhängendes Gefühl, was das Letzte ist, was Sie von einem Rahmen mit Batterien abgesehen haben würden.

Persönlich bin ich gespannt, wie Sie für alle Angular-Pakete (HTTP, Router, Forms) sogar Nicht-RxJS-Versionen haben würden. Ich vermute, dass es keine guten Nicht-RxJS-Versionen davon gibt, weshalb sie überhaupt RxJS haben.

Das heißt .... es sei denn, ich übersehe etwas, (2) ist nicht machbar.


PS Ich würde diese Anfragen nicht als "orthogonal" bezeichnen; eher "gegenüber".

Weniger RxJS in Angular, was es möglicherweise optional macht

Aus Neugier @mgechev , gibt es dafür Github-Probleme? (Ich habe keine gesehen.) Oder ist das eher eine Google-Sache?

@pauldraper Ich habe mindestens ein Problem auf github gesehen, bei dem sich jemand darüber beschwert, wie schrecklich komplex rxjs ist und möchte, dass es vollständig optional ist. Persönlich liebe ich rxjs, aber ich habe jetzt mit zwei Teams gearbeitet, wo es sowohl Junior- als auch Senior-Entwicklern Angst und Abscheu brachte. Außerdem ist orthogonal der bessere Begriff als umgekehrt, da es möglich ist, beide Anforderungen gleichzeitig zu implementieren (vorausgesetzt, jede Lösung kann bearbeitet werden, ohne dass eine von der anderen abweicht, indem mehrere API-Optionen bereitgestellt werden, um Dinge reaktiv und zwingend zu konsumieren).

Für jeden Kommentar, der sich über rxjs auf github beschwert, gibt es wahrscheinlich Tausende von Entwicklern, die es problemlos verwenden und genießen.

image

image

Hier sind die Ergebnisse aus diesem Formular, das ich oben gepostet habe (fast 200 Leute haben geantwortet), als ich sie auf Angular Discord diskutierte.

Wenig überraschend Formen sind die größte Nervensäge, aber anscheinend @brandonroberts und @MikeRyanDev könnte kocht etwas, endlich.

Für jeden Kommentar, der sich über rxjs auf github beschwert, gibt es wahrscheinlich Tausende von Entwicklern, die es problemlos verwenden und genießen.

Obwohl ich rxjs liebe, bin ich nicht so optimistisch. Ich habe mit vielen Entwicklern zusammengearbeitet, die so ausgebrannt sind, dass der Gedanke, Zeit investieren zu müssen, um etwas mit einer steilen Lernkurve zu lernen, ein Albtraum ist. Und viele, denen es viel wichtiger ist, Geld zu verdienen als zu programmieren :D Oder die aggressiven Junior-Entwickler, die denken, dass alles, was sie nicht an einem Tag lernen können, Müll sein muss.

Ich habe mit vielen Entwicklern zusammengearbeitet, die so ausgebrannt sind, dass der Gedanke, Zeit investieren zu müssen, um etwas mit einer steilen Lernkurve zu lernen, ein Albtraum ist. Und viele, denen es viel wichtiger ist, Geld zu verdienen, als zu programmieren

Das sind die Entwickler, denen Angular dann gerecht wird, ausgebrannt und ohne lernen zu wollen? :) Und wen interessiert das zu diesem Zeitpunkt sowieso schon. Angular gibt es schon eine Weile, es geht nirgendwohin und es wird absolut nicht an Zugkraft verlieren, wenn Sie beobachtbaren Lebenszyklus, beobachtbaren Input, beobachtbare Ereignisse hinzufügen. Fügen Sie einfach diese drei kleinen Dinge hinzu und die Leute werden eine Weile glücklich sein, das war's (und folgen Sie dem mit https://indepth.dev/component-features-with-angular-ivy/, um das Basispaket zu vervollständigen).

angular_rxjs

Dieser sagt alles. IMHO Angular sollte konsistent bleiben und mehr RxJS verwenden: Ohne RxJS wäre es nicht Angular.

Das sind die Entwickler, denen Angular dann gerecht werden will? :)

Ja, es wäre anmaßend, nur Entwicklern anzubieten, die Code mit rxjs schreiben möchten. Obwohl ich es vorziehe, rxjs zu verwenden, möchte ich, dass Angular beide Entwicklergruppen bedient. Warum sollte Angular nur auf uns eingehen und nicht auf Andersdenkende? Vor allem, wenn ich glaube, dass wir in der Minderheit sind, nicht in der Mehrheit.

Nochmals, „voll reaktiv“ zu gehen, wie das Hinzufügen von beobachtbaren Lebenszyklen, Eingaben und Ereignissen, würde die von Ihnen Gesprochenen in keiner Weise beeinflussen, aber die andere Gruppe würde sehr glücklich machen.

Und Komponentenfunktionen sind nützlich, egal ob Sie reaktive Programmierung mögen oder nicht.

@fxck Ich habe dem keine Sekunde widersprochen. Ich habe nur auf Ihren früheren Kommentar geantwortet, um darauf hinzuweisen, dass es viele Leute gibt, die rxjs nicht verwenden möchten, und viele von ihnen haben Github-Probleme geöffnet, um sich darüber zu beschweren.

Unabhängig davon, wie eckig sich entscheidet, den Kern zu entwickeln - reaktiv oder nicht, in der idealen Welt würde das entgegengesetzte Paket darauf aufbauen, um die entgegengesetzten Bedürfnisse zu erfüllen (zB @angular/reactive oder @angular/imperative - mit besseren Namen .) hoffnungsvoll).

Beides, in die Community zu gehen, ist für mich eine Herabstufung für einige Leute, und für mich war die Perspektive, ein großartiges reaktives Framework zu sein, ein Grund, sich überhaupt daran zu beteiligen.


Nebenbei bemerkt, ich denke, es wäre einfacher, winkelig reaktiv zu halten und zwingende Erweiterungen zu verwenden, da dies viel einfacher zu überbrücken ist, als zwingende zu reaktiv zu überbrücken – was für die Einfachheit sowohl des Kerns als auch des Erweiterungspakets spricht.

Haftungsausschluss: Der letzte Punkt, den ich basierend auf Annahmen formuliert habe – wäre nicht überrascht, wenn es viel einfacher wäre, den Kernimperativ zu schreiben – Extension Reactive wäre jedoch komplexer.

Aus Neugier @mgechev , gibt es dafür Github-Probleme? (Ich habe keine gesehen.) Oder ist das eher eine Google-Sache?

Keine interne Google-Sache. Sie werden überrascht sein (so wie ich es war, als ich ins Team kam), wie groß die Schnittmenge zwischen externen und internen Anforderungen ist. Der Hauptunterschied liegt im Build-System und im Abhängigkeitsmanagement, abgesehen davon, dass Google-Mitarbeiter ziemlich dieselben Anforderungen haben wie Nicht-Google-Mitarbeiter.

Wir stehen in Kontakt mit Tausenden von Entwicklern – vielen externen Unternehmen, internen Teams und einzelnen Mitwirkenden. In beiden Fällen gibt es Leute, die gerne voll auf RxJS einsteigen würden, und andere, die denken, dass es nicht die richtige Wahl für sie ist. Beide Lager haben ausgezeichnete Argumente.

Dies ist keine Entscheidung, die wir überstürzen möchten, insbesondere angesichts der Tatsache, dass es gut etablierte Problemumgehungen/Community-Lösungen gibt. Die Arbeit in der Community hilft uns, zusätzliche Datenpunkte zu sammeln und eine optimale Lösung für den aktuellen Satz von Variablen zu finden.

Ich denke, bei der Entwicklung einer eckigen App wäre es sehr von Vorteil, einen einheitlichen reaktiven oder zwingenden Ansatz (der eine Wahl pro Projekt ist) zu haben. Die Möglichkeit zum Mischen und Anpassen hilft nicht bei der Entwicklungserfahrung und beim Erstellen von nicht DRY-Code (z. B. nicht reaktiven Eingaben).

Nichts geschieht isoliert, daher kann ich völlig verstehen, dass Unternehmensumgebungen Schwierigkeiten haben, große Mengen von Entwicklern auf reaktive Programmierung umzuschulen. Das Aufgeben von Imperativ würde also wirklich aus dem Unternehmens-Sweet-Spot herausrücken, was realistisch sein wird, wird einfach nicht passieren, da es eine große Schlüsselbenutzerbasis für ein Framework wie angle ausmacht.

Was ich jedoch nicht für realistisch halte, ist der Aufbau einer reaktiven Schnittstelle auf einer zwingenden. Die andere Richtung ist ziemlich einfach, da Sie die Ausgabe einer Observablen immer in eine Variable schreiben können, die dann zwingend verwendet werden kann. Das macht angle sogar schon an vielen Stellen unter dem Deckmantel.

Daher stimme ich dafür, Winkel im Kern vollständig reaktiv zu machen und dann zwingende "Wrapper" obendrauf zu erstellen.

Das Hauptproblem bei diesem Ansatz wären sehr wahrscheinlich größere Migrationsschritte für zwingende Benutzer. Was in Unternehmensumgebungen ein Nono ist und genau das sein könnte, was das kantige Team zu verhindern versucht, daher der Vorschlag, im Kern zwingend zu tun.

@mgechev Da dies ein paar Mal zur Sprache gekommen ist, wäre es interessant, Ihre Gedanken zur reaktiven Kern- / Imperativerweiterung zu hören und ob sie ein Bein zum Stehen hat?

In beiden Fällen gibt es Leute, die gerne voll auf RxJS einsteigen würden, und andere, die denken, dass es nicht die richtige Wahl für sie ist. Beide Lager haben ausgezeichnete Argumente.

Super, gut zu wissen. Definieren Sie voll und ganz mit RxJS? Wie passt das Hinzufügen von beobachtbarem Lebenszyklus, beobachtbarem Input und beobachtbaren Ereignissen dazu? Und nein, keiner davon hat wirklich eine "gut etablierte Workarounds/Community-Lösung".

@fxck keines davon hat wirklich eine "gut etablierte Problemumgehung / Community-Lösung".

Es ist wahr. Ich habe eine dieser Lösungen geschrieben und sie funktioniert nur aufgrund eines großen Hacks, der auf einer schlechten Typprüfung in Vorlagen beruht. Ich habe mir auch einige der anderen in diesem Thread geposteten Lösungen angesehen und jede von ihnen hat mindestens eines der folgenden Probleme:

  • Abo-Lecks
  • Boilerplate-Anforderungen an den Benutzer
  • Hacks genauso schlimm, wenn nicht sogar schlimmer, als der, den ich in meiner Bibliothek verwendet habe.

Soweit es mich betrifft, ist es unmöglich, dies schön zu machen.

Beobachtbare Ereignisse sind noch schlimmer, es gibt überhaupt nicht viele Community-Lösungen, sie erfordern normalerweise zusätzliche Build-Schritte (was in einigen Fällen SSR in Monorepo-Setups unterbricht) und sogar noch Hacks (wenn Sie beispielsweise eine Klassenerweiterung verwenden, um beobachtbare Ereignisse im Lebenszyklus abrufen, weil hey, angle unterstützt das nicht nativ) https://github.com/typebytes/ngx-template-streams/issues/8

Lebenszyklusereignisse sind wohl die "einfachsten", müssen sich aber dennoch auf eine Klassenerweiterung oder benutzerdefinierte Dekorateure verlassen, von denen keines ideal ist.

@fxck Soweit mir bekannt ist, ist es nicht möglich, Lifecycle-Ereignisabonnements zu bereinigen, ohne eine übergeordnete Klasse (eugh) oder eine Methode verwenden zu müssen, die der Benutzer von seinem eigenen Destroy-Lifecycle-Ereignis aus aufrufen muss (noch schlimmer).

Lebenszyklusereignisse sind wohl die "einfachsten", müssen sich aber dennoch auf eine Klassenerweiterung oder benutzerdefinierte Dekorateure verlassen, von denen keines ideal ist.

Ich hatte versucht, Lebenszyklusereignisse (um es reaktiv zu machen) auch mit benutzerdefinierten Dekorateuren zu implementieren, und es ist mühsam. ~Ohne Klassenerweiterung weiß ich nicht, ob es ohne 100 Hacks geht~. Die Benutzer-Möglichkeit, eckig zu verlängern, ist bisher sehr schlecht und es ist auf Hacks oder viel Boilerplate angewiesen, um dies zu tun.

@tonivj5 Wenn die Komponentenfunktionen eine öffentliche API wären, sehen Sie dies als eine Möglichkeit, Lebenszyklen ohne Vererbung zu implementieren?

@ntziolis hah lustig Sie sollten Funktionen erwähnen, ich arbeite tatsächlich am Lebenszyklusteil von ngx-sub-form und Funktionen sind genau etwas, von dem ich denke, dass es helfen würde. In der Zwischenzeit ist es durchaus machbar, die Komponentenfabrik mit Efeu zu patchen. Ich halte dies außerhalb von ngx-sub-form für sehr nützlich, daher denke ich, dass ich diese Logik in eine separate Lib aufteilen werde

@ntziolis Zu diesem Zeitpunkt bin ich mir nicht sicher, ob die Ivy-Versprechen jemals tatsächlich geliefert werden.

Hast du den Winkeleffekt überprüft? (nicht ngrx/effects) https://dev.to/stupidawesome/reactive-adventures-in-angular-introducing-angular-effects-1epf Mit diesem Tool können Sie vollreaktive Anwendungen schreiben.
In beide Richtungen beobachtbarer Zustand zwischen Eltern- und Kinderkomponenten enthalten
https://dev.to/stupidawesome/exploring-the-angular-effects-api-2gol
Version 9.1.0 wird ein Kompositions-/Hooks-Modell basierend auf der Kompositions-API von Vue 3 einführen.
Ich denke, es ist ein wirklich nächster Schritt für Angle, mit Reaktivität zu arbeiten.

@mchev

Dies ist keine Entscheidung, die wir überstürzen möchten, zumal es gut etablierte Workarounds/Community-Lösungen gibt

Nur neugierig, wer sind wir und wie viele Google-Mitarbeiter tragen aktiv zum Entscheidungsprozess von Angular bei?

Sie geben an, dass dies keine Entscheidung ist, die überstürzt werden sollte, aber ich frage mich, was Ihre Definition von nicht überstürzt ist? Ist dies einer von denen, die mit einem "Fixed by Ivy"-Tag versehen und ignoriert werden, bis mehr Entwickler anfangen, wieder Lärm zu machen, um Situationen zu schreiben? Gibt es eine gezielte Version für reaktive Arbeiten oder müssen andere neuere Compiler-Versionen zuerst veröffentlicht werden?

Kommt die Tatsache, dass es in der Regel 2500 offene Fragen zu einem bestimmten Zeitpunkt gibt, jemals in internen Diskussionen zur Sprache?

@ntziolis , wie @zakhenry sagte, ich denke, features würde helfen

@ntziolis Ich habe andere Versuche mit dem Lebenszyklus habe einen funktionierenden POC (ohne Klassenerweiterung noch implementiert Lebenszyklusschnittstellen). Es basiert auf einer privaten API (:Ausrufezeichen:)

@tonivj5 hah Ich hatte noch keine Gelegenheit, deine zu lesen, aber ich habe meine Lösung auch fast veröffentlicht :) https://github.com/cloudnc/ngx-observable-lifecycle

Die Idee mit der Bibliothek, an der ich arbeite, besteht darin, eine gemeinsame Basis zu haben, an der sich andere Bibliotheken anschließen können, um ihre eigenen lebenszyklusbewussten Funktionen zu erstellen. Es sollte in der Lage sein, so zu funktionieren, dass, wenn mehrere Funktionen auf denselben Hook zugreifen möchten, nur der eine Hook auf der Komponente def dekoriert ist.

Ich habe alles zum Laufen gebracht, ich muss nur CI- und Unit-Tests sortieren.

Kommt die Tatsache, dass es in der Regel 2500 offene Fragen zu einem bestimmten Zeitpunkt gibt, jemals in internen Diskussionen zur Sprache?

Lol, seit Mitte 2019 gab es keine 2500 offenen Probleme mehr.

$ 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)  |
+-------------------------+--------------------+

Nach meinem Geschmack bevorzuge ich Open-Source-Projekte, die Themen offen halten, bis es eine klare Diskussion/Konsens in der Community gibt, anstatt Projekte, die jedes ohne Diskussion geöffnete Thema schließen. Es ist auch ein Schritt für Betreuer, ihre Bedenken im Laufe der Zeit der Community zu erklären, bevor sie jede Möglichkeit zur Annahme eines Vorschlags schließen.

@agalazis Dieses Thema ist seit 4 1/2 Jahren offen und wurde in den letzten 3 Jahren so gut wie ignoriert.

@agalazis Dieses Thema ist seit 4 1/2 Jahren offen und wurde in den letzten 3 Jahren so gut wie ignoriert.

Vor nur 5 Tagen hat ein Angular-Teammitglied erklärt, warum dies noch geöffnet

@etay2000 Manche Entscheidungen sind manchmal schwierig, da sie die Entwicklung des gesamten Projekts beeinflussen und das ist akzeptabel. Entwickler können erkennen, dass sie sich im

@beeman

Vor nur 5 Tagen hat ein Angular-Teammitglied erklärt, warum dies noch geöffnet ist. Sie haben also einfach nicht Recht.

Du magst diese Daumen runter Emojis wirklich, oder? Aber war das wirklich eine Erklärung? Nach 4+ Jahren sagte er, dass sie die Entscheidung nicht überstürzen wollen.

@agalazis
Ich stimme zu, dass einige Entscheidungen schwierig sind, aber was sollte als akzeptabler Zeitrahmen angesehen werden, um diese schwierigen Entscheidungen hinauszuzögern? Nicht alle der 2855 offenen Themen beinhalten diese harten Entscheidungen, aber viele davon gibt es auch schon seit geraumer Zeit.

@etay2000 Akzeptiere es oder nicht, dies sind Open-Source-Leute, die offene Probleme haben, sind viel mehr als die Betreuer. Das Typoskript-Projekt zum Beispiel hat fast doppelt so viele offene Fragen und ein anderer Vorschlag, den ich dort gemacht habe, hat ebenfalls lange gedauert. Es macht mir nichts aus, da die Diskussion dort viele Alternativen gebracht hat, die nicht so ausgefallen sind wie das Feature, aber es geschafft haben, viele andere Perspektiven zu sehen

@agalazis Sie haben Recht, ich glaube, ich habe (fälschlicherweise) mehr von einem von Google betreuten Open-Source-Projekt erwartet als von einem kleineren Projekt.

@beeman Hier Daumen runter Emoji

@etay2000 Sie sollten immer daran denken, dass jede so wichtige Entscheidung Hunderttausende von Dingen, Projekten und Menschen betrifft. Und was noch wichtiger ist, eine nicht perfekte Entscheidung und die Einführung öffentlicher APIs, die in kurzer Zeit zu einigen Breaking Changes führen würden, ist nur ein Albtraum. Sie können fast auf jeder PR sehen, wie jeder Schritt überprüft wird, und wenn er nicht perfekt ist, wartet er einfach, Wochen, Monate oder sogar Jahre.

@agalazis Sie haben Recht, ich glaube, ich habe (fälschlicherweise) mehr von einem von Google betreuten Open-Source-Projekt erwartet als von einem kleineren Projekt.

Ich weiß nicht, schau dir Go und Dart auch an. Google ist eigentlich ziemlich berühmt dafür, seit einem halben Jahrzehnt äußerst beliebte Community-Anfragen zu ignorieren :D Im Allgemeinen ist ihr Ansatz zu Sprachen/Frameworks/etc. ist sehr konservativ . Sie können sehen, wie neue Sprachen und Ideen auftauchen, die Bereiche revolutionieren, und Google sie immer noch nicht übernimmt, zB null Safety Hit Kotlin, TypeScript und Scala lange vor Dart. Ich denke, diese Art von Ansatz hat Vor- und Nachteile, aber zumindest für mich neige ich dazu, von Google entwickelte Dinge nach Möglichkeit zu vermeiden, weil sie nicht wirklich zu meinem Ethos passen.

(Entschuldigung, alle, aber ich muss es tun.)

@beeman Hier Daumen runter Emoji

@etay2000 Ich weiß nicht, wie diese Art von Kommentar überhaupt hilft, wenn nicht sogar eine Verhaltensverletzung hier. Ich bin mir ziemlich sicher, dass jeder weiß, wie man Daumen drückt, also was soll der Sarkasmus?

Nur zur Erinnerung, niemand ist gezwungen, Angular zu verwenden. Sie können versuchen, ein anderes Framework zu finden, bei dem die Leute Ihnen mehr gefallen.

@brunojcm Ich denke, die Party ist jetzt vorbei, da die Kommentarpolizei hier ist. Der Punkt war, dass er alle meine anderen Kommentare niedergeschrieben hat, aber ich wusste nicht, dass Sarkasmus eine Verletzung des Verhaltens war.

Nur zur Erinnerung, niemand ist gezwungen, Angular zu verwenden. Sie können versuchen, ein anderes Framework zu finden, bei dem die Leute Ihnen mehr gefallen.

Die Art und Weise, wie ich darauf wirklich reagieren möchte, würde definitiv gegen den Verhaltenskodex hier verstoßen.

Ich bin fertig, jeder kann zu seinem regulären Programm zurückkehren. Ich schaue in 4-5 Jahren nochmal nach, um zu sehen, wie sich alles entwickelt hat.

@tonivj5 @zakhenry Toll zu hören, dass dies ein Weg sein könnte.

@mgechev Ich verstehe, dass dies nicht einmal eine vorläufige Diskussion ist, aber ich würde gerne Ihre Gedanken zu hören:

  • reaktiver Kern + nicht reaktive Erweiterung vs. umgekehrt.
  • und spezieller für dieses Problem gibt es eine realistische Chance, die Feature-API in irgendeiner Weise offenzulegen.

    • selbst wenn es nur mit dem Vorbehalt ist, in Zukunft Änderungen zu unterbrechen, solange die allgemeine Funktion noch zugänglich wäre.

    • Wie @zakhenry für Lifecycle-Ereignisse gesehen habe, sehe ich ein einziges oder eine sehr begrenzte Anzahl von Projekten, die darüber hinaus APIs erstellen, die von anderen verwendet werden können, anstatt direkt auf diese APIs zuzugreifen

    • Sie könnten dann mit diesen Wrapper-Teams zusammenarbeiten, um sie frühzeitig über bevorstehende Breaking Changes zu informieren (also sehr ähnlich wie Ihr Vorschlag zu reaktiven Erweiterungen).

Ich denke, Sie können das reaktive Modul von Vue 3.0 (ref oder reaktiv) direkt anwenden und dieses Problem lösen.

@AnonymousArthur Wenn Sie über das Paket @vue/reactivity sprechen, hat es nichts mit dem zu tun, was wir hier besprechen, da es Reaktivität für Eigenschaften bereitstellt und nichts mit reativen Streams zu tun hat (was RxJs ist).

@gund Ja, ich stimme zu. Dieses Gespräch dauert jedoch ziemlich lange (4,5 Jahre) und ist noch nicht abgeschlossen, also tauche ich nur sehr schnell eine Idee auf (möglicherweise nicht), für die nicht abonnieren/abmelden oder ngOnChange Handler schreiben möchten. RxJS bietet eine Reaktivitätsfunktion und in dieser Konversation (habe nicht alles gelesen) geht es darum, den Eingabewert mit dem Observable als syntaktischen Zucker zu verpacken, um ihn anschaubar zu machen, und ich denke, es ist eine großartige Idee.

Ich denke, diese Idee ist wirklich nützlich und der Prototyp von @robwormald sieht zu Beginn großartig aus, aber ich denke, er hat die potenziellen Vorteile unterschätzt und wie gering die Auswirkungen sein müssten.

Lassen Sie mich eine kleine Anpassung dieser Lösung vorschlagen, um einige Mängel zu beheben, aber im Wesentlichen der gleiche Ansatz:

Angular würde einen Dekorator @OInput() und einen Typ EventReceiver<T> , der Observable<T> aber auch einen .value Getter hinzufügt (wie BehaviorSubject<T> ).

Auf der Seite der @robwormald , nichts. Wenn Sie dort einen Observable-Wert übergeben möchten, benötigen Sie noch | async . Oder Sie können ihm einen nicht beobachtbaren Typ übergeben, das ist auch (wie immer) in Ordnung.

Auf der Seite der

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

Hier sind nun die Vorteile dieses Ansatzes, die meiner Meinung nach etwas unterbewertet sind:

  • Dies ermöglicht auf Wunsch effektiv vollständig reaktive Designs sowohl in den Eltern- als auch in den Kindkomponenten.
  • Behält in übergeordneten Komponenten die bestehenden Eingabeentwurfsmuster von Angular bei, sodass keine Komponente dazu gezwungen wird oder darum herum entwerfen muss.
  • Der Eltern- und Kindkontext sind völlig unabhängig, der Elternteil muss nicht wissen, ob das Kind Input oder OInput , wodurch das Risiko von komponentenübergreifenden Fehlern durch diese Änderung eliminiert wird.
  • Es ist relativ einfach, eine einzelne untergeordnete Komponente bei Bedarf teilweise zu migrieren, da Angular diese wie zuvor alle mit den vorhandenen Lebenszyklusereignissen verbunden hält.
  • Da Angular diese Funktion implementiert, können alle EventReceiver s intern eine Pipe bis takeUntil(ngOnDestroyEvent) , so dass die meisten Fälle nicht daran denken müssen, sich abzumelden, wenn ihre Komponente zerstört wird, da diese Observablen automatisch abgeschlossen werden . (Yay reduzierte Speicherverluste!)
  • In dieser untergeordneten Komponente sieht dies sehr ähnlich aus und funktioniert sehr ähnlich wie das Muster von @Output() heute, bietet also eine schöne Parallelität und die Möglichkeit, sie gut zu verbinden.

    • Randnotiz: Als Follow-up wäre es meiner Meinung nach cool, ein @InputOutput() vorzuschlagen, das ein ReplaySubject<T>(1) , um die Verhaltensweisen für eine Zwei-Wege-Bindung nahtloser und konsistenter zu verbinden. Aber das hat seine eigenen Herausforderungen und Argumente, also schlage ich das hier

  • Keine neuen Arten von Boilerplates, um dies zu ermöglichen, dies ist so einfach wie @Output() .
  • Angular würde nahtlos switch() über Änderungen an den Observable , die vom übergeordneten Element eingegeben werden, übergehen, sodass schwächere reaktive Muster wie diese, die nicht an derselben Observable-Instanz festhalten, nicht in Sonderbuchstaben geschrieben werden müssen ( switch() ed) in untergeordneten Komponenten.

Randnotiz zum Namen OInput , den ich gewählt habe: Offensichtlich ist das offen für Diskussionen. Ich persönlich mag diesen Namen jedoch, weil er für "Observable Input" steht UND weil er ein bisschen wie "Output" aussieht, was dies widerspiegelt.

Liebes Angular-Team. Bitte geben Sie uns etwas, worauf wir uns im Jahr 2020 freuen können :-)

Auch die @jcomputer- Lösung ist genau das, was ich mir wünschen würde. Ich bin kein großer Fan eines anderen Dekorateurnamens, aber vielleicht ist es machbar, einen Parameter hinzuzufügen, der dem ähnlich ist, wie @ViewChild { read } . z.B:

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

So viel dazu, dass Sie sich im Jahr 2020 auf etwas freuen können. :D Es sei denn, dies (und andere oben aufgeführte Probleme) zählen natürlich als Fehler und nicht als neues Feature. :)

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

@fxck Ich kann eine unpopuläre Meinung hier haben , aber zum Glück unwichtig , wenn 2020 ist das Jahr , waren Angular Team entscheidet , viele Fehler auf Formularen zu quetschen, Router usw. Ich würde überhaupt nicht verrückt mit 0 Eigenschaften: Achselzucken :.

image

Das heißt, es ist vielleicht eher ein Problem im Zusammenhang mit den jüngsten Ereignissen und ich gehe davon aus, dass im Moment im Angular-Team komplizierte Dinge passieren. Ich hoffe, dass sie es schaffen, die großartigen Leute zu halten, die Angular bisher aktiv aufgebaut haben : heart:. Aber das ist eine andere Geschichte.

Sorry für das Off-Topic. Fliegt weg

@maxime1992 Es wäre auch gut für mich.

Ich mag hier eine unpopuläre Meinung haben, aber ehrlich gesagt, wenn 2020 das Jahr ist, in dem das Angular-Team beschließt, viele Fehler in Formularen, Routern usw. zu beseitigen, wäre ich mit 0 Funktionen überhaupt nicht sauer

Aber was mich nervös macht, ist die Tatsache, dass es innerhalb des Angular-Teams langfristig ungesunde HR-Prozesse gibt, die uns ohne uns betreffen. Vor allem im Hinblick auf massive Investitionen in diesen Bereich.

Aus meiner Sicht beheben sie Probleme hauptsächlich, indem sie sie über BOT schließen - ohne Reaktion verlassen und per Bot schließen.,.. :-/

@montella1507 Nein, das stimmt nicht ganz. Der Bot sperrt nur bereits geschlossene Probleme. Und es stimmt schon, dass sich die Angular-Teammitglieder in vielen Fällen viel Mühe geben, wenn sie versuchen, zu erklären, was zu beschreiben und zu reproduzieren ist, wenn neue Themen eingegeben werden. Es ist ein sehr zeitaufwändiger Prozess und erfordert viel Geduld.

Für diejenigen, die das Angular-Team beschuldigen und sich darüber beschweren, dass Funktionen und Änderungen nicht schnell verfügbar sind:
Ich verstehe deinen Schmerz. Ich würde diese Funktion auch gerne in Angular sehen, ich würde auch viele Dinge ändern, die mir persönlich nicht gefallen.

Aber vielleicht ist Angular nicht als Framework gedacht, das all die glänzenden neuen Spielzeuge enthält und jede Menge Funktionen mit jeder Veröffentlichung erhält. Und das ist in Ordnung für mich. Es muss Frameworks geben, die auf mehr Unternehmensebene abzielen und Stabilität und Zuverlässigkeit bieten. Und das macht Angular gut, zumindest aus meiner Erfahrung.

Ich mag Vue mehr. Ich benutze es für meine persönlichen Projekte. Aber meine Projekte können sich schnell veraltet anfühlen und ich verspüre den Drang, auf einen neuen Komponentenstil umzusteigen. Auch wenn ich Upgrades mache, gehen die Dinge immer auf die seltsamste Art und Weise kaputt. Das Ökosystem scheint es auch schwerer zu haben, die Kompatibilität aufrechtzuerhalten.

Angular hingegen ist ausgereift und stabil. Es ändert sich nicht oft, aber das bedeutet auch, dass Sie weniger Arbeit beim Refactoring Ihres Codes haben, da Sie Ihre Abhängigkeiten auf dem neuesten Stand halten, und das ist für kommerzielle Produkte wertvoll. Ihr Wissen bleibt auch länger relevant und anstatt zu versuchen, Schritt zu halten, können Sie in die Tiefe gehen.

@manfreed- Leute fragen jedoch nicht nach einem glänzenden neuen Spielzeug, sondern nach einer Korrektur eines Versehens im Design des Frameworks. Derzeit sind wir manchmal gezwungen, Observables für wichtige Funktionen zu verwenden, und manchmal nicht in der Lage, Observables zu verwenden. Diejenigen, die Observables hassen, sind frustriert. Diejenigen, die Observables lieben, sind frustriert. Und viele von uns waren so enttäuscht von der Situation, dass wir aufgegeben und zu anderen Frameworks übergegangen sind. Ich hätte Angular gerne weiter verwendet, ein bisschen Anleitung und es hätte ein wirklich tolles Framework werden können. Aber Blogposts über Missmanagement, den Mangel an Pragmatismus, das Versehen, sie alle sind objektiv enttäuschend.

@insidewhy Seien Sie geduldig, es gibt immer einige Gipfel und Täler auf der Straße, aber das bedeutet nicht, dass andere sie nicht auch haben oder dass es einige grundlegende Fehler gibt. Es bedeutet nur, dass die Dinge schneller und effektiver vorankommen könnten, als sie es tatsächlich taten.

Es gab keine Erwähnung eines bestimmten oben genannten Problems in der Roadmap, was ich traurig fand. Ich hatte wirklich gehofft, dass es etwas geben würde, Erwähnung, Anerkennung ... diese Diskussion folgte auf Angular Discord —

image

Ich gab ihnen im Zweifel einen Vorteil und fragte im Kommentar zu diesem mittelgroßen Roadmap-Artikel nach Minkos Antwort:

image

Er hat so ziemlich wiederholt, was er hier vor einigen Monaten gesagt hat, keines dieser rxjs-bezogenen Probleme wird in absehbarer Zeit behoben, also ja.

Ich habe es satt , meinen Standpunkt darzulegen, aber lass es mich ein letztes Mal versuchen zusätzlich zu den aktuellen APIs.

  • beobachtbarer Lebenszyklus
  • beobachtbarer Input
  • beobachtbare Vorlagenereignisse

Keines davon unterbricht die Abwärtskompatibilität, erhöht die Lernkurve, ist nicht konsistent mit anderen APIs und ich kann mir vorstellen , dass es

@fxck :+1: auf jeden Fall .

  • beobachtbarer Lebenszyklus
  • beobachtbarer Input
  • beobachtbare Vorlagenereignisse

@insidewhy Seien Sie geduldig

Die Leute um mehr als 5 Jahre Geduld zu bitten, ist nicht so pragmatisch, wenn viele Konkurrenten im Rennen vorbeirennen, die alle um Aufmerksamkeit buhlen.

@ Insidewhy Es wurde allgemein gemeint.

@fxck Google hat (nach meiner letzten Zählung) 4000 Apps in eckiger

Nehmen wir nun an, wir implementieren jede dieser hilfreichen RxJS-Verknüpfungen in den Kern, was passiert dann? Es ist möglich, dass wir am Ende eine prozedurale Voreingenommenheit gegenüber einer reaktiven Voreingenommenheit haben, ohne dass klar ersichtlich ist, welche Voreingenommenheit für einen bestimmten Fall richtig ist. Nach dem Durchlesen der bisherigen Diskussionen lautet die Antwort des Angular-Teams nicht "Dies hat eine niedrige Priorität" (wie Ihr Ablauf vermuten lässt), sondern eher "Wir wollen keine Partei ergreifen".

Die fortgeschrittenen RxJS-Benutzer in der Angular-Community hier sind eine lautstarke Minderheit, denn nachdem Sie Typescript, DI, Templating und die verschiedenen Angular-Bibliotheken gelesen haben, haben Sie fast 1 Jahr Zeit, das Framework täglich zu verwenden, und Sie sind jetzt bereit um RxJS vollständig zu verstehen. Wenn man Leute auf höherer Ebene mit Reaktivitätsverzerrungen bei Peer-Reviews davonlaufen lässt, entfremdet man die Leute noch mehr, und das ist buchstäblich das Letzte, was Angular braucht.

Angulars Ziel (wie ich es sehe) besteht darin, Konversationen zu reduzieren und abzuschwächen, weg von "Verwenden Sie X-Technologie, weil es besser ist, hier eine kurze Novelle warum" und Gespräche in Peer-Reviews über die implementierte Geschäftslogik zu führen. Wollen wir unsere Komponenten wirklich noch mehr als bisher zwischen "Advanced" eckig und "Beginner" eckig schichten?

Dies sind wohl die gleichen Argumente, die wir beim Zustandsmanagement gesehen haben. Warum sollte Angular aus den vielen möglichen Mustern ermitteln, welches das richtige ist?

Lassen Sie mich nur eines der kantigen Teammitglieder für Sie zitieren.

image

Übrigens ist an all diesen Dingen absolut nichts weiter fortgeschritten (beobachtbarer Lebenszyklus, beobachtbare Eingabe, beobachtbare Vorlagenereignisse).

Dies sind wohl die gleichen Argumente, die wir beim Zustandsmanagement gesehen haben. Warum sollte Angular aus den vielen möglichen Mustern ermitteln, welches das richtige ist?

Der Unterschied zwischen der Staatsverwaltung und diesem besteht darin, dass die Staatsverwaltung von der Gemeinschaft durchgeführt werden könnte, es gibt nichts im Inneren des Winkelkerns, der dies verhindert. Leider bietet Angular keine Möglichkeiten, um keine der drei genannten drei richtig zu implementieren. (Edit: Link zum Kommentar korrigiert)

Ich bin von ganzem Herzen dafür, so viel wie möglich der Community zu überlassen, das heißt Pakete wie Formulare, Router, Flex-Layout, Universal usw., damit sich das Angular-Team auf Core, Cli und Komponenten konzentrieren kann. Aber dafür müssen sie der Community genügend Einstiegspunkte bieten, wie zum Beispiel Komponenten höherer Ordnung zulassen . Aber sie haben dies jahrelang versäumt (oft sagen sie, dass Ivy zuerst gebraucht wird) und weigern sich, dies jetzt in ihren Plänen anzuerkennen / darüber zu sprechen.

Nach dem Durchlesen der bisherigen Diskussionen lautet die Antwort des Angular-Teams nicht "Dies hat eine niedrige Priorität" (wie Ihr Ablauf vermuten lässt), sondern eher "Wir wollen keine Partei ergreifen".

Ja und es ist beängstigend.

@fxck Ich denke sehr, dass wir

Ja und es ist beängstigend.

Das ist wenig hyperbolisch, wir "brauchen" nicht @angular/core um diese Muster zu haben, tatsächlich gibt es viele VIELE Varianten und Bibliotheken in dieser Ausgabe, die heute in jedem Projekt verwendet werden können. Die einzige Zurückhaltung bei der Verwendung der zuvor genannten Optionen besteht darin, dass Sie möglicherweise in Zukunft auf etwas migrieren müssen, das Angular als standardmäßigen @angular/core Ersatz bereitstellt. Ist es wirklich so schwer für uns, npm uninstall und alle Schreibfehler zu beheben?

Wichtige architektonische Entscheidungen, die alle Angular-Projekte betreffen und unzählige Stunden benötigen, um zu dokumentieren und zu migrieren, wenn sie nicht funktionieren, erscheint mir noch beängstigender, und wir waren schon einmal da:

Das ist wenig hyperbolisch, wir "brauchen" @angular/core nicht, um diese Muster zu haben, tatsächlich gibt es viele VIELE Varianten und Bibliotheken in dieser Ausgabe, die heute in jedem Projekt verwendet werden können.

Nein, nicht wirklich, jede Lösung erfordert Hacks oder verlässt sich auf interne APIs, die sich ändern könnten. Das ist der springende Punkt.. Lesen Sie, was https://github.com/angular/angular/issues/5689#issuecomment -630661006 gesagt hat und was ich unten über Template-Ereignisstreams gesagt habe.

// Korrigierten Link zum Kommentar bearbeiten

Nein, nicht wirklich, jede Lösung erfordert Hacks oder verlässt sich auf interne APIs, die sich ändern könnten.

Welche internen APIs oder Typen sollten Ihrer Meinung nach öffentlich/generisch gemacht werden, damit dies von der Community behandelt werden kann? Wenn sich dieses Design in einer Warteschleife befindet, weil es keinen klaren Weg nach vorne gibt, dann scheint es angebracht zu verlangen, dass wir unser eigenes Design entwerfen dürfen, anstatt ständig dieselbe Trommel zu schlagen.

Lesen Sie den anderen Kommentar von @insidewhy er versuchte, es im Kern zu erledigen.

image

@fxck Ich werde nicht auf die Geschichte der Versuche

Yo @insidewhy , ich frage mich, ob dies der Typprüfungs-Hack ist, auf den sich Ihre Bibliothek verlassen hat. Anscheinend funktioniert es nicht mehr mit TS 4.0

Die Eigenschaft 'serviceStackId$' wird vor ihrer Initialisierung verwendet.ts(2729)

image

Yo @insidewhy , ich frage mich, ob dies der Typprüfungs-Hack ist, auf den sich Ihre Bibliothek verlassen hat. Anscheinend funktioniert es nicht mehr mit TS 4.0

Nein, es war im Template-Compiler. Das ist etwas anderes. Verdammt. Ah, gut. Ich kann Sie zur Betreuerliste hinzufügen, wenn Sie versuchen möchten, das Problem zu beheben.

@fxck Eigentlich sollten Sie diesen

@insidewhy Ich habe definitiv vor TS4 gearbeitet. Und überprüfe das ,

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();

es protokolliert

logging this.baz ObservableInput modifizierten Wert

Ich denke, es sollte immer noch funktionieren, nur in TS4 beschwert sich der Compiler, weil er nicht erkennt, dass es ein get mit einem Wert in diesem Dekorator gibt.

Ich verwende einen Dekorator, um die Änderung der Input-Requisite zu erkennen und eine beobachtbare Version der Input-Requisite zu erstellen. Sehen Sie sich diese Codesandbox-Demo an .

So funktioniert es:

// 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);
}

Wie @wmaurer betonte, könnte @Subjectize als "Zucker" behandelt werden, um Dinge zu erledigen.

Es lohnt sich, den offiziellen Leitfaden von angle zu lesen. getter/setter .

@hankchiutw Diese Lösung sieht meinem @BindObservable Dekorator ähnlich: https://github.com/PSanetra/bind-observable#usage

Danke @hankchiutw

Da Sie ReplaySubject mit 1 initialisieren, habe ich stattdessen BehaviorSubject verwendet.
Außerdem habe ich den Wert direkt in Subjectize initialisiert.

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

    // ...
}

Ich wünschte, ich könnte vermeiden, den Typ in die Eigenschaft "Subjectized" zu schreiben, da sie ihn aus der zugehörigen Eigenschaft erraten können sollte :( Irgendeine Idee, wie das geht?

Der Traum wäre, das zu können und automatisch die zugehörige Betreff-Requisite (in meinem Fall world$) als BehaviorSubject zu erstellenund richtig initialisiert.

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

    // ...
}

@mparpaillon Ihr vorgeschlagenes Design ist so ziemlich so, wie es in https://github.com/PSanetra/bind-observable gemacht wird
Der einzige Unterschied besteht darin, dass der @BindObservable() Dekorator ein ReplaySubject unter der Haube verwendet. Wenn Sie also möchten, dass das Subjekt einen Anfangswert enthält, müssen Sie auch die gebundene Eigenschaft explizit initialisieren (auch wenn sie nur undefiniert ist, da der Eigenschaftstyp möglicherweise keine undefinierten oder Nullwerte zulässt).

Stackblitz-Beispiel

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

Danke @PSanetra, aber ich bevorzuge meine Lösung (die eigentlich Hank-Lösung ist)

@mparpaillon Ich habe in einer anderen Demo etwas für deinen Traum (ha) ausprobiert.

Die Nutzung sieht so aus

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

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

wo Sie den subjektivierten Prop-Namen angeben können.

Obwohl es technisch machbar ist, fürchte ich, dass dies für Entwickler mehrdeutig sein kann (da ein neues Klassenmitglied unter der Haube erstellt wird).

Danke @hankchiutw ! Typescript scheint mich jedoch nicht count$ oder myCount$ verwenden zu lassen.

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

Vielleicht haben Sie auch Recht mit Mehrdeutigkeiten ... Nochmals vielen Dank

Typescript scheint mich jedoch nicht count$ oder myCount$ verwenden zu lassen.

Sie haben Ihre Klassenmitglieder als "count" und "anotherCount" deklariert, deshalb können Sie nicht auf "myCount$" und "count$" zugreifen. Sie existieren einfach nicht, weil Sie sie nirgendwo deklariert haben.

Ich weiß... das ist der Punkt. Ich habe nach einer Möglichkeit gesucht, sie vom Dekorateur zu deklarieren. @hankchiutw hat eine Lösung angeboten und ich sage nur, dass es nicht so funktioniert, wie es ist

@mparpaillon schau dir meine Lösung an: https://github.com/Futhark/ngx-observable-input

@Futhark Oh das ist heiß! Vielen Dank

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen