Angular: Proposition : entrée en tant qu'observable

Créé le 8 déc. 2015  ·  183Commentaires  ·  Source: angular/angular

Désolé, je ne suis pas bon en anglais.

@Input valeurs de propriété
Et si la propriété Input a été modifiée dans le composant enfant (il a la propriété comme propriété propre), son détecteur de changement ne le remarque jamais.

Objectif

  • Les données d'entrée du parent et la propriété d'entrée de l'enfant doivent être synchronisées.
  • Les développeurs doivent comprendre que les propriétés d'entrée sont modifiées de manière asynchrone.

    Proposition

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

Le code ci-dessus ne fonctionne pas. Actuellement, pour recevoir une entrée sous la forme Observable<T> , je dois l'écrire comme ci-dessous.

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

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

Cela fonctionne bien, mais ce n'est pas indispensable. Les données d'entrée des parents sont à l'origine des données simples.

Je pense que cette proposition nous fait plaisir.

Merci.

core inputs / outputs feature Needs Design

Commentaire le plus utile

Chère équipe Angular. S'il vous plaît, donnez-nous quelque chose à espérer en 2020 :-)

De plus, la solution @ViewChild a { read } . par exemple:

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

Tous les 183 commentaires

Salut @laco0416 - votre anglais est bon, ne vous inquiétez pas !

J'aime beaucoup cette idée, et c'est quelque chose dont nous avons déjà discuté. Cela correspond également bien à https://github.com/angular/angular/issues/4062 (Observation des événements de vue) et https://github.com/angular/angular/issues/5467 (Événements observables pour les enfants par les parents)

Il est important de se rappeler que tout le monde ne voudra pas utiliser des Observables (ces personnes sont absentes !), nous devons donc fournir des options pour les deux cas d'utilisation, et il est donc peu probable que nous fassions @Input() directement dans un Observable. Je pense qu'avoir quelque chose comme @ObserveInput() pourrait fonctionner, et nous aurons une discussion _après_ nous expédierons la version bêta sur certaines de ces fonctionnalités les plus intéressantes, je pense.

En attendant, voici une implémentation basique (et _très_ expérimentale !!! ne faites PAS cela pour de vrai) de cette idée. Est-ce conceptuellement ce que vous pensiez ? http://plnkr.co/edit/Nvyd9IPBZp9OE2widOcW?p=preview

Je pense que c'est une très mauvaise idée de modifier les propriétés d'entrée dans un composant enfant. Les propriétés d'entrée doivent être en "lecture seule". Vos données doivent toujours circuler du parent vers l'enfant (et jamais dans le sens inverse).

@alexpods, je crois que l'idée ici est exactement celle-ci - son _écoute_ du changement des propriétés d'entrée _as_ un Observable, n'émettant pas de valeurs en amont, ce qui est tout à fait bien en ce qui me concerne.

@robwormald

votre anglais est bon, ne vous inquiétez pas !

Merci! Je suis tellement soulagé.

Votre @ObserveInput est ce que je veux juste !
De plus, @Input n'a pas de changements de rupture. Je pense que c'est une très bonne solution.

@alexpods Moi aussi du tout.

son écoute du changement des propriétés d'entrée en tant qu'observable, n'émettant pas de valeurs en amont, ce qui est tout à fait correct en ce qui me concerne.

Je pense de la même manière que Rob.

@laco0416 Ooh, désolé pour le malentendu. L'expression "si la propriété d'entrée a été modifiée dans le composant enfant" m'a confondu.

Je ne sais pas si je dois commenter ici ou si je dois ouvrir un nouveau sujet. Veuillez me faire savoir si j'ajoute une demande au mauvais endroit.

J'ai essayé (mais, jusqu'à présent, sans succès) d'écrire un tel décorateur, puis je suis tombé sur le plunkr de @robwormald , qui fonctionne _presque_ parfaitement (mais pas tout à fait).

Ce qui m'a enthousiasmé par cette approche, c'est le fait qu'elle s'appuie sur le crochet de cycle ngOnChanges vie
Ce que j'aimerais voir, c'est un moyen pour _tous_ les hooks de cycle de vie d'être exposés en tant qu'observables, c'est-à-dire en tant que onChanges$: Observable<{[key: string]: SimpleChange}> , onInit$: Observable<{}> , etc.

Le fait d'avoir tous les hooks de cycle de vie disponibles en tant qu'observables m'aidera à tout régler ;-)

Des mises à jour à ce sujet ?

Autant que je sache, non.
@robwormald as -tu des nouvelles ?

Je sais que c'est vieux, mais ce serait génial ! @robwormald Un mot à ce sujet ?

J'aimerais fournir des valeurs de propriété changeantes @Input tant qu'observable , tout comme le @ObserveInput @robwormald le fait. Il n'est pas toujours possible de faire passer les composants parents aux Observables, en particulier lorsque vous migrez une application existante (Angular 1). Ne pas pouvoir « contenir » des Observables dans un seul composant rend cependant beaucoup plus difficile l’exploitation de la puissance et de l’élégance de RxJS.

Malheureusement, Rob ne plaisantait pas quand il a dit de ne pas utiliser cette version de @ObserveInput . Le problème que je rencontre est que les observables sont créés à un "niveau de classe" (si cette terminologie a du sens) et sont donc partagés entre toutes les instances du composant. Ce n'est pas bon, évidemment. La création des observables au moment de l'instanciation n'a pas non plus fonctionné pour moi. Il semble qu'Angular ne connecte pas correctement la détection de changement dans ce cas.

Quelqu'un a-t-il réussi une meilleure implémentation de @ObserveInput ou y a-t-il des nouvelles sur le support officiel ?

@lephyrus Alors qu'un @ObserveInput serait un très bon décorateur, ce n'est pas strictement nécessaire pour obtenir un Observable de modification des valeurs de propriété de @Input . Le décorateur serait tout simplement très élégant "sucre".

Il existe déjà un événement de cycle de vie ngOnChanges . Dans ngOnChanges nous pouvons utiliser un rxjs Subject , pour créer un observable des changements, c'est-à-dire :

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

Ou, si vous voulez quelque chose de plus réutilisable, vous pouvez créer une classe de base que votre composant 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);
    }
}

... qui pourrait être utilisé comme suit :

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

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

J'utilise cette approche jusqu'à ce qu'un décorateur officiel @ObserveInput soit disponible.

Merci @wmaurer. Votre ReactiveComponent est le bienvenu, et utilise un code impeccable et une saisie sûre pour démarrer - vraiment sympa ! Il est important de noter qu'il se comporte également bien sous test et permet toujours d'utiliser la stratégie de détection de changement OnPush . Je suis maintenant heureux d'attendre le "sucre officiel". (De plus, je suis sûr que j'apprendrai quelque chose quand je comprendrai pourquoi vous avez dû utiliser la logique Observable.create() - je n'ai pas encore trouvé le temps de m'y intéresser.) Encore une fois : merci gäll ! :clin d'œil:

@lephyrus de rien, gärn gescheh ;-)

J'ai utilisé Observable.create() pour mettre la main sur un Observer afin de pouvoir faire un next() . J'aurais pu utiliser un Subject qui est à la fois un Observable et un Observer , mais je pense que c'est généralement une mauvaise pratique d'« exposer » un Subject ( Observer ).

@laco0416 ferme en faveur de https://github.com/angular/angular/issues/13248 ?

@DzmitryShylovich Non. La fonctionnalité proposée dans ce numéro est la transmission de données en lecture seule et événementielle.

@ObserveInput sera super cool ! :+1:

Merci @wmaurer pour un bon exemple. J'ai quand même une question. J'aimerais pouvoir utiliser un objet au lieu d'une chaîne comme observable.

Par exemple

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

Cependant, this.updateChart et ngOnChanges ne sont pas appelés. Comment étendre votre échantillon à partir d'une simple chaîne pour observer un objet à la place ?

@ChrisWorks, cela devrait également fonctionner avec des objets :

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

Je le fais très souvent, donc si cela ne fonctionne pas, je suppose qu'il y a un problème avec l'entrée de votre composant quelque part.

Salut @wmaurer , merci pour la réponse. Seriez-vous en mesure d'étendre votre échantillon avec une version de travail où vous utilisez un objet "config" ? Je n'arrive tout simplement pas à faire fonctionner le mien. Un exemple de dépôt Git ? :)

@ChrisWorks, ça devrait vraiment fonctionner comme ça. observePropertyCurrentValue ne fait pas la différence entre une entrée de chaîne et un objet.
Voici un très vieux projet ng2 beta 0 que j'ai réalisé où les entrées sont de tous types différents, pas seulement des chaînes :
https://github.com/wmaurer/todomvc-ng2-reactive
par exemple https://github.com/wmaurer/todomvc-ng2-reactive/blob/master/src/app/todo-item/todo-item.component.ts

+1 Un cas d'utilisation aussi fondamental, je ne peux pas croire qu'il n'a pas encore été trié !

J'ai enfin la meilleure solution et ça marche sans répétition et avec la compilation AOT :) Le secret est de combiner @Input() avec un deuxième décorateur.

Le décorateur :

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

Usage:

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

EDIT : j'en ai maintenant fait une bibliothèque. Heureux de recevoir des idées pour l'améliorer. Ajout d'une nouvelle méthode qui complète un @Input existant avec un Observable suivant. Voir https://github.com/ohjames/observable-input

Si je devais faire quelque chose comme ça, je préférerais opter pour un seul sujet analogue à ngOnChanges : Subject<SimpleChanges>
Vous pouvez toujours filtrer et mapper sur une seule entrée spécifique si vous le souhaitez.

1 sujet par entrée semble beaucoup sans parler de la suppression d'un accessoire de classe pour créer un getter & setter et que le type de votre entrée est erroné et que faire input = value émettra en fait la valeur sur l'observable et vous n'êtes pas compléter votre sujet.

Vous pouvez trouver un exemple d'implémentation de mon idée ici , l'approche du décorateur est expérimentale mais je pense qu'il devrait être assez sûr d'utiliser l'approche de l'héritage (gardez à l'esprit que je viens de le faire maintenant pour montrer ici, ce n'est pas utilisé).

@ghetolay peu importe si le sujet est terminé, lorsque la vue est fermée, il n'y a plus d'abonnements au flux et il peut être supprimé par le GC. L'émission de la valeur sur l'observable est fondamentalement le but de cela. Le compilateur angulaire ne vérifie actuellement pas les types de propriétés d'entrée, j'espère qu'au moment où il le fera, quelque chose de plus officiel sera disponible ;)

changes$ fuit l'interface BehaviorSubject vers le composant, idéalement, il devrait être tapé comme un Observable<...> , à part cela, cela semble raisonnable, même s'il est un peu plus détaillé.

Quant à la question de nombreux sujets... que vous utilisiez des sujets n ou 1 vous avez toujours des abonnements n . Lorsque vous avez 1 sujet, vous finissez par ajouter un opérateur de carte et un opérateur de filtre à chaque abonnement, la surcharge de performances ne serait pas beaucoup moins que l'utilisation n sujets

Ignorant le typage des paramètres d'entrée eux-mêmes, la version basée sur le décorateur fournit une API plus sécurisée aux utilisateurs des observables que les types SimpleChange basés sur any .

@ohjames

lorsque la vue est fermée, il n'y a plus d'abonnements au flux et il peut être supprimé par le GC

Vous partez du principe que tous les abonnements seront liés à la vue et auront le même cycle de vie que la vue. Je ne fais aucune hypothèse sur la façon dont l'Observable sera consommé.

L'émission de la valeur sur l'observable est fondamentalement le but de cela. Le compilateur angulaire ne vérifie actuellement pas les types de propriétés d'entrée, j'espère qu'au moment où il le fera, quelque chose de plus officiel sera disponible ;)

Je voulais dire pour l'utilisateur, l'utilisateur peut toujours accéder et définir la propriété. Il définira donc la propriété comme s'il s'agissait d'un nombre, sauf qu'il est tapé en tant qu'observable et que cela ne définira jamais la propriété mais la fera émettre. C'est très déroutant pour moi.

Quant à la question des nombreux sujets... que vous utilisiez n sujets ou 1 vous avez toujours n abonnements. Lorsque vous avez 1 sujet, vous finissez par ajouter un opérateur de carte et un opérateur de filtre à chaque abonnement, la surcharge de performances ne serait pas beaucoup moins que l'utilisation de n sujets, cela pourrait même être pire.

N'entrerons pas dans ce genre de débat ici car nous allons bientôt perdre le focus sur l'objectif principal.

J'ai mis à jour pour ne pas exposer le Subject et j'ai construit quelque chose pour ajouter de la frappe aux modifications.
Je n'utilise pas un BehaviorSubject mais un simple Subject parce que je ne vois pas ces Observables comme des détenteurs de valeur mais comme des changements au fil du temps.
Je viens de trouver un défaut : lors de l'utilisation du canal asynchrone, la première valeur n'émet pas car le canal asynchrone s'abonnera après la première émission. Je mettrai à jour mon code plus tard pour gérer correctement ce cas.

Voici à nouveau le lien : https://stackblitz.com/edit/angular-observableinput?file=observablechanges%2Fimpl.ts

Vous partez du principe que tous les abonnements seront liés à la vue et auront le même cycle de vie que la vue. Je ne fais aucune hypothèse sur la façon dont l'Observable sera consommé.

D'accord, je vois votre point, compléter les observables forcera la fermeture de tous les abonnements, mais ce n'est pas quelque chose qui m'inquiète vraiment. Dans notre application, 99% des abonnements se produisent via le canal asynchrone et dans les rares qui ne doivent pas être fermés manuellement de toute façon, car ils proviennent souvent d'observables externes provenant de Redux/etc via combineLatest/switchMap.

N'entrerons pas dans ce genre de débat ici car nous allons bientôt perdre le focus sur l'objectif principal.

Eh bien, vous avez soulevé une critique invalide, il était donc nécessaire de contrer celle-ci.

~ De plus, l'utilisation de votre classe par héritage ne fonctionnera pas, le code généré par le compilateur AOT n'appelle pas les méthodes de cycle de vie dans les classes parentes, voir https://github.com/angular/angular/issues/12756#issuecomment -260804139, vous 'll faudra ajouter ngOnDestroy() { super.ngOnDestroy() } et un autre pour ngOnChanges à tous les consommateurs de la classe.~ <-- semble avoir été corrigé à partir d'Angular 4.4 avec certaines limitations.

J'ai examiné ma préoccupation concernant l'utilisation du canal asynchrone et puisque vous avez toujours accès à l'entrée, je ne pense pas que l'utilisation ait un sens. Si vous souhaitez simplement lier la valeur d'entrée sur le modèle, vous pouvez simplement lier directement à l'entrée sans avoir besoin d'utiliser d'observable et asynchrone ici. Et si vous voulez composer une nouvelle observable à partir de celle-ci, vous devriez pouvoir obtenir exactement ce que vous voulez facilement (probablement en utilisant startWith quelque part).

Donc je pense que ma déclaration précédente est ok :

Je n'utilise pas un BehaviorSubject mais un simple Subject parce que je ne vois pas ces Observables comme détenteurs de valeur mais comme des changements au fil du temps. Si vous avez besoin d'accéder à une valeur d'entrée, la propriété existe toujours et vous pouvez vous y référer de manière synchrone.

Ce code est hautement expérimental, c'est juste une sorte de poc et je n'ai joué avec lui que sur ce stackblitz.
Donc, je n'aurais pas dû dire que c'était assez sûr, désolé et que cela pourrait ne pas fonctionner avec AOT comme vous l'avez dit.
Je viens de l'essayer et les deux approches fonctionnent actuellement avec AOT (angular v4.3.6, cli v1.4.1).

Mon point principal ici est que passer d'un changes observable contenant toutes les modifications d'entrées vous donne la possibilité de faire tout ce dont vous avez besoin à l'aide d'opérateurs : réagir lorsqu'une entrée a changé, lorsqu'une seule entrée a changé, lorsqu'un nombre arbitraire d'entrées changé, quand il est passé d'une valeur spécifique à une autre etc...
Vous pouvez composer l'observable que vous voulez.

De plus, il n'y a qu'un seul sujet à gérer pour l'implémentation et 1 propriété à utiliser pour l'utilisateur contre 1 par entrée.

La chose que je pourrais changer serait d'émettre simplement de nouvelles valeurs et non un objet SimpleChanges car l'utilisateur peut probablement utiliser pair et map pour obtenir le même type de structure que SimpleChange . Mais actuellement, ce que nous avons obtenu est SimpleChanges , il serait donc idiot de le décomposer juste pour recomposer quelque chose de similaire plus tard.

PS :

Eh bien, vous avez soulevé une critique invalide, il était donc nécessaire de contrer celle-ci.

invalide pour vous .

Ce n'est pas un point de vue personnel lorsque nous parlons de performance, ce sont des faits mesurables objectifs. Vous pensez que 3 sujets équivaut à plus de frais généraux que 6 opérateurs supplémentaires, vous avez peut-être raison, mais il n'y a aucune base rationnelle pour le croire tant que vous n'avez pas fait quelques mesures.

En ce qui concerne la réaction à de nombreuses entrées... bien sûr, vous pouvez simplement utiliser switchMap ou combineLatest ou l'un des autres opérateurs conçus pour travailler avec plusieurs observables. Vous faites des déclarations très audacieuses et radicales à ce sujet, si vous voulez vraiment continuer cette conversation, retirons-la de ce traqueur de problèmes.

Voici une version avec différents inconvénients et avantages mais elle nécessite une classe de base :

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

et à utiliser :

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

Je ne sais pas si j'ai mal compris le problème, mais le canal asynchrone ne résout-il pas ce problème ?
[inputVar]="observableValue | async" ..

@najibla vous avez mal compris, les entrées ne sont pas observables, donc le tube async n'aide pas.

@ohjames bien dans mon cas, cela a fonctionné en utilisant le tuyau asynchrone pour un observable. Et lorsque je mets à jour la valeur observable du parent, la valeur est reflétée dans le composant enfant.

@najibla, ce problème de github consiste à transformer des propriétés @Input en observables, ceci est étroitement lié au cas que vous décrivez.

c'est-à-dire que vous ne devriez pas avoir besoin de convertir les propriétés d'entrée en un observable dans la vue, qu'un composant réponde à la modification de la propriété d'entrée à l'aide d'un observable ou non, doit être isolé dans un composant lui-même. Sinon, vous devez modifier l'interface de votre composant si vous décidez de consommer une propriété en tant qu'observable, ce qui est en contradiction avec l'approche habituelle "observable first" d'angular.

@icepeng En fait, vous n'avez pas tout à fait raison, il s'agit de transformer une entrée standard en un observable. Ainsi, le nouveau modèle serait en fait :

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

... alors il fournit un moyen d'accéder à prop intérieur de AppChildComponent en tant qu'observable même si ce n'est pas un observable (ou si c'était un observable, vous obtiendriez un observable d'observables ). Maintenant, bien sûr, si vous aviez prop$ en premier lieu comme dans votre exemple, cela pourrait ne pas sembler raisonnable (vous pouvez déjà simplement passer l'observable avec des entrées maintenant). Cependant, il fournit beaucoup de valeur lorsque l'entrée transmise n'est pas déjà un observable (par exemple un index partir d'un ngFor ).

Le problème avec la transmission d'un observable avec une entrée (ce qui est tout à fait possible en ce moment) est que cela ne fonctionnerait pas tout à fait avec OnPush .

@fxck Eh bien, vous avez raison, ngOnChanges ne sera pas appelé lorsque l'observable émet (car l'entrée reste la même), mais tant que vous utilisez le tube async pour vous abonner à un observable passé par @Input puis OnPush fonctionneront correctement car le tube asynchrone déclenche manuellement le détecteur de changement du composant enfant.

Oui, il était dirigé vers @icepeng.

@ohjames @fxck Je ne savais pas que la transmission de l'observable était possible en ce moment, désolé pour les informations erronées.

Étant donné qu'il est possible de passer directement de l'observable, je ne suis pas sûr que @ObserveInput soit utile.
Je pense que si la valeur qui peut être modifiée n'est pas Observable, c'est déjà un problème.
Juste un avis personnel.

@icepeng Considérez ceci :

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

Comment rendre index consommable en tant qu'observable ici sans sauter à travers des cerceaux ?

Ou considérez également que vous écrivez une bibliothèque tierce et que vous ne voulez pas forcer les consommateurs de votre bibliothèque à transmettre des observables à votre composant (de nombreux utilisateurs ne sont pas à l'aise avec les flux et évitent les rxjs).

Il existe de nombreux autres cas où cela est utile.

@ohjames index serait une valeur statique pour chaque child-component , donc je ne pense pas que cela doive être observable. Cependant, je comprends maintenant pourquoi les gens veulent cette fonctionnalité. Et votre solution semble bonne pour écrire une bibliothèque tierce.

BehaviorSubject approche @NgChanges() décorateur comme ça.

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

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

Est-ce possible à mettre en œuvre ?

Un ReplayObservable avec une longueur de tampon de 1 serait préférable, la sémantique de valeur de BehaviourSubject n'est pas nécessaire lorsque vous avez également accès à la propriété.

Quant à savoir s'il est possible de l'implémenter, vérifiez l'historique des problèmes pour de nombreuses implémentations et options différentes. Aucun n'est génial et certains sont carrément cassés, pour le faire correctement, nous avons besoin du PR lié ou de quelque chose de similaire.

mes 2 centimes : comme object.observe a été déprécié en faveur des proxys, ma solution était d'étendre un proxy (oui vous ne pouvez pas savoir, raison pour laquelle je l'ai renvoyé du constructeur) puis d'écouter n'importe quelle clé appartenant à ce objet en tant qu'Observable via la méthode $get(keyName). Vous pouvez l'utiliser avec n'importe quel objet, pas seulement la classe angulaire un.

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

Exemple:

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 , y a-t-il une traction sur cette question ? Cela contribuerait certainement beaucoup à rendre les choses plus faciles à utiliser.

@bryanrideshark La meilleure chance que cela soit pris en charge est via https://github.com/angular/angular/issues/10185 Je pense, surpris que les relations publiques ne soient pas liées à ce problème.

Cela n'arrivera qu'après l'expédition d'Ivy
Le mercredi 21 février 2018 à 7 h 56, James Pike [email protected] a écrit :

@bryanrideshark https://github.com/bryanrideshark La meilleure chance de
ceci est pris en charge via #10185
https://github.com/angular/angular/issues/10185 Je pense, surpris que
PR n'est pas lié à cette question.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/angular/angular/issues/5689#issuecomment-367372931 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAgpkvtGA4w8uHgiz0QsdYwBgqgM2EpAks5tXDyWgaJpZM4Gwr8f
.

Votre anglais est excellent et votre angulaire est plus grand.

@ pldin601 Votre méthode ne prend pas en charge le code compilé AOT, ce qui entraînera d'énormes fuites de mémoire pour le code de production de la plupart des gens. Consultez plutôt mon package observable-input qui fonctionne bien avec AOT.

@ pldin601 le problème avec votre code est qu'il ajoute dynamiquement la méthode de cycle ngOnDestroy vie ngOnDestroy si le compilateur peut déduire statiquement son existence. Ainsi, votre méthode ne fonctionnera que si chaque composant qui utilise le décorateur définit également un ngOnDestory (il peut être vide s'il n'est pas nécessaire). Dans tous les autres cas, les abonnements seront divulgués, empêchant les composants d'être ramassés.

Je suppose que cela se produira une fois la section 3.2 terminée (et j'espère que ce besoin sera pris en compte) ?
https://is-angular-ivy-ready.firebaseapp.com/#/status

Ivy fera-t-il partie de la 7.0.0 ?

J'ai implémenté un décorateur qui peut lier une propriété à une propriété compagnon observable. Il peut être utilisé sur les propriétés d'entrée angulaire, mais aussi sur toute autre propriété. Il s'inspire du décorateur @ObservableInput() de @ohjames , mais évite les problèmes possibles causés par les incompatibilités de type entre les getters et les setters de propriétés en utilisant une propriété différente pour fournir l'Observable.

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

Exemple:

class MyClass {

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

}

const myInstance = new MyClass();

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

myInstance.myProp = 'newValue'

Ce code imprime les valeurs 'initialValue' et 'newValue' sur la console.

Toute mise à jour sur le moment où cela sera publié jusqu'à présent, le package observable-input semble le plus élégant sans rien casser + aucun sous-classement. @ohjames Dans

Je pense que le support officiel serait plus mature, garantirait un support continu à travers les versions et une expérience de développement plus fluide/encouragera les développeurs à utiliser rxjs* complet et à optimiser avec la détection de changement push (cela devrait être une fonctionnalité révolutionnaire à mon avis)

*sans compromettre la compatibilité avec les entrées non observables ou avoir besoin d'un passe-partout supplémentaire pour les entrées hybrides, c'est-à-dire : le passeur appelant ensuite sur le sujet

Entrée observable utilisée en angulaire 4, 5 et 7 avec et sans aot. Cela semble bien fonctionner. Je suis presque sûr que je savais vaguement ce que je faisais quand je l'ai écrit.

j'espère qu'ils l'ajouteront dans le framework et encourageront son utilisation 2 téléchargements hebdomadaires npm n'est pas suffisant par rapport aux avantages qu'il offre xD s'ils l'ajoutent je parie que les gens verront qu'il est simple de suivre cette approche

Je propose l'API suivante pour l'entrée asynchrone avec l'utilisateur défini observer

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

les utilisateurs pourraient simplement l'utiliser comme

@AsyncInput()
asynchronusProperty1 = new Subject();

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

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

Angular internal peut simplement appeler observer.next(newValue) chaque fois que la valeur change.

N'oubliez pas non plus le support @HostBinding !

Cela devrait être combiné avec l'injection @Input du constructeur pour le rendre encore plus impressionnant. De cette façon, nous pourrions corriger "strictPropertyInitialization" d'une manière très élégante :

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

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

}

@benneq vaut la peine de noter qu'il pourrait être aussi petit que :

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

@maxime1992 oui , bien que vous ayez besoin d'un décorateur séparé pour les entrées en tant qu'observables pour distinguer le cas des observables passés d'un composant à un autre.

@benneq @maxime1992 Les noms de paramètres ne font pas partie des métadonnées du décorateur, comment les mapper ?

@trotyl Je suppose que vous pourriez alors utiliser @Input('paramName') private myParam: Observable<Data>

@trotyl @benneq oui mon mauvais. Qu'à cela ne tienne :zipper_mouth_face:

Je ne sais pas si quelqu'un a déjà posté cette solution , mais c'est une assez bonne solution

@ElianCordoba Il ne s'agit pas de HTML <input> . C'est à peu près angulaire @Input()

C'est un problème différent, mais tout aussi douloureux @ElianCordoba. https://github.com/angular/angular/issues/13248

Je pense que c'est une pseudo-exigence. Premièrement, le décorateur d'entrée peut accepter une valeur de type Observable, deuxièmement, si le composant nécessite un observable en entrée, il doit explicitement lancer une erreur lorsqu'il reçoit une valeur non observable au lieu de le convertir discrètement en valeur de type Observable.

C'est assez similaire à la conversion de type implicite en javascript, peut être confus même provoquer un bogue et difficile à trouver.

Il ne s'agit pas de faire taire les mauvaises entrées. Il s'agit d'exposer une interface commune entre les composants (qui est une entrée non observable). Cela vous donne la liberté d'introduire la fonctionnalité rx sans casser son interface avec le monde extérieur. Un autre avantage est principalement de lever la mutabilité et l'état interne, car tout sera une transformation de l'entrée, ce qui rend la détection de changement de poussée à partir de ce point une évidence.

Au contraire, exposer, une interface qui nécessite des observables semble maladroit et obliger les gens à fournir de (valeur) juste parce que votre composant l'a dit me semble étrange.

De plus, il ne s'agit pas de conversion silencieuse, c'est une API pour s'abonner aux modifications via rxjs. Étant donné que angular.http et le routeur fournissent des observables, il est très difficile que la gestion des changements d'entrée ne le fasse pas, l'unification des mondes des rappels et des RxJ nécessite trop de passe-partout.

Non pas que je n'aime pas certaines des solutions astucieuses ci-dessus, mais parfois, une légère réorganisation de la manière «standard» de le faire suffit à résoudre le vrai problème ici qui est le manque de clarté/la maladresse. De plus, j'espère toujours un moyen «officiel» après le lierre de le faire un jour.

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

Ensuite, vous pouvez simplement mettre quelque chose comme combineLatest(this.service.magicInput$, this.inputs, config$)...... pour combiner les entrées avec RxJS.

Soit BehaviorSubject soit ReplaySubject fonctionne. BehaviorSubject est généralement plus sûr et plus prévisible.

  • BehaviorSubject - à utiliser si vous avez des valeurs par défaut
  • ReplaySubject - l'observable n'émettra pas si vous oubliez de définir la valeur d'entrée

Cela aide non seulement à la clarté du code, mais parce que je regroupe toutes les entrées, je peux facilement voir ce qu'est une entrée observable «pure» en tapant simplement this.inputs. et en obtenant la saisie semi-automatique.


Vous pouvez aller plus loin avec la sécurité du type avec cela (c'est surtout pour le plaisir).

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

Ensuite, vous n'avez pas besoin de spécifier explicitement le type de la propriété @Input .

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

J'aurais pu créer une interface ObservableInputs pour que le composant applique inputs mais j'ai décidé de ne pas le faire car il ne compilera pas de toute façon si vous bousillez ça.

@simeyla Trop de passe-

J'ai décidé d'y mettre mon propre décorateur. C'est mon premier package npm donc je suis sûr qu'il me manque quelque chose, mais le voici : https://www.npmjs.com/package/@ng-reactive/async -input

Installation

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

Usage

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 vraiment sympa, je ne vois aucune raison pour laquelle quelque chose comme ça ne devrait pas être intégré. Pour info, le lien github sur npm pour le package est obsolète, il va ici :

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

Je vois que c'est un problème assez ancien, mais la fonctionnalité est assez incroyable et je suis vraiment ravi de le voir dans Angular.

Ce qui est encore plus cool, c'est qu'avec les entrées observables, vous n'avez pas besoin OnChanges crochet pairwise rxjs pour obtenir les valeurs précédentes et actuelles des entrées observables :

@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

C'est mon implémentation personnelle, cela fonctionne parfaitement et assez génial, si nous pouvons l'intégrer, c'est vraiment cool.

J'ai publié la solution que j'ai utilisée personnellement dans mes projets sous forme de package npm :

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

Installation

npm install ngx-observable-input

Usage

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

    ...
}

Je vois que c'est un problème assez ancien, mais la fonctionnalité est assez incroyable et je suis vraiment ravi de le voir dans Angular.

Ce qui est encore plus cool, c'est qu'avec les entrées observables, vous n'avez pas besoin OnChanges crochet pairwise rxjs pour obtenir les valeurs précédentes et actuelles des entrées observables :

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

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

C'est un problème qui me tracasse également depuis un certain temps, j'ai donc enquêté un peu et j'ai trouvé la même solution que celle que vous mentionnez ici (@gund).

J'ai implémenté un petit assistant de décorateur ( @ObservableInput ) qui étend en interne le décorateur @Input et permet ce genre de composition. Vous pouvez le vérifier ici (également en tant que package npm ). J'ai testé avec des exemples simples, mais je n'ai pas eu le temps de l'utiliser pour des projets étendus. Tout commentaire est le bienvenu :)

Voici un exemple d'utilisation :

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

Et ce composant peut être utilisé comme ceci :

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

@aleics Êtes-vous sûr que cela fonctionnera avec le compilateur AOT ?

@aleics Êtes-vous sûr que cela fonctionnera avec le compilateur AOT ?

Non, pas prêt à l'emploi, bien sûr, puisque la propriété @Input n'est pas explicitement définie. Mais vous pouvez définir votre module avec CUSTOM_ELEMENTS_SCHEMA , comme lorsque vous utilisez des composants Web, puis il devrait être compilé.

Ce numéro est ouvert depuis 5 ans 🤦‍♂ . Je pense qu'il est nécessaire d'avoir cela pour faciliter une approche de programmation réactive

Ivy est enfin là, donc je suppose que quelqu'un a le temps de travailler sur celui-ci ? S'il te plaît s'il te plaît s'il te plaît!

Omg, je souscris au fait que cela est vraiment nécessaire. Les données d'entrée doivent être émises en tant que source réactive, et vous devez utiliser une solution de contournement pour que cela fonctionne dans un ngOnChanges

J'ai vraiment hâte pour ça

Je me rends compte qu'Angular est open source, mais est-il faux ou naïf de ma part de penser qu'un projet géré par Google devrait être capable de résoudre des problèmes fortement suivis et demandés en moins de 5 ans ? Y a-t-il des problèmes financiers dont je ne suis pas au courant qui empêchent Google d'embaucher plus de développeurs pour travailler sur Angular ?

@etay2000 Je ne sais pas, je pense que c'est

J'ai l'impression que la chaîne de priorisation va comme ça

exigences des utilisateurs internes de Google -> tout ce qui a à voir avec le compilateur plus rapide -> tout ce qui a à voir avec la taille de l'application plus petite -> tout ce qui ne dérange pas les nouveaux arrivants -> ce que veulent réellement les développeurs

Et tandis que les responsables techniques diraient qu'ils conviennent que c'est important, le fait est qu'Igor et Misko ont tendance à penser à la plupart des problèmes en termes de compilation de modèles, de liaisons de vues et de rendu. Peu importe ce que les consommateurs d'Angular disent être important pour eux, la solution est toujours de changer le système de modèles, d'écrire un nouveau moteur de rendu ou d'améliorer le compilateur.

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

Il suffit de regarder quelques-uns des problèmes les plus votés.

Proposition : entrée en tant qu'observable #5689

Créé il y a 5 ans, dernière réponse d'un membre de l'équipe concerné - il y a 5 ans, statut actuel inconnu.

Prise en charge des flux d'événements froids dans les modèles #13248

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - il y a 1 ans, statut actuel - en attente de l'atterrissage d'Ivy.

Proposition : fournir des crochets de cycle de vie des composants en tant qu'observables #10185

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - il y a 3 ans, statut actuel inconnu.

Proposition : Besoin de pouvoir ajouter des directives aux éléments hôtes dans la déclaration de composant. #8785

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - il y a 2 ans, statut actuel inconnu.

as local-val sans *ngIf #15280

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - il y a 2 ans, statut actuel inconnu.

Prise en charge de la projection de contenu dynamique #8563

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - il y a 3 ans, statut actuel inconnu.

ng-content contenu par défaut #12530

Créé il y a 4 ans, dernière réponse d'un membre de l'équipe concerné - jamais, statut actuel inconnu.

Ensuite, il y a des choses comme les fonctionnalités des composants, qui permettraient des composants d'ordre supérieur, puis il y a bien sûr beaucoup plus de problèmes les plus votés, mais j'espérais qu'ils seraient résolus (c'est-à-dire résolus, sans nécessairement s'attendre à ce qu'ils soient implémentés immédiatement après Ivy ), car ils ont à voir avec l'utilisation quotidienne du framework ET la réactivité, qui, je pense que personne ne le contesterait, est ce que la plupart des gens utilisent (étant donné que ngrx est la bibliothèque de gestion d'état la plus populaire).

Mon application est pleine de "polyfills" à moitié cuits (simplement en raison de limitations techniques, certains ne peuvent être correctement exécutés que dans le noyau) et de hacks pour la plupart de ces problèmes, dans l'espoir que je pourrai un jour tomber dans un natif angulaire remplacement. Mais d'une manière ou d'une autre, cela ne semble pas venir.

Alors oui, disons qu'un article de blog traitant de l'état de certains des plus gros problèmes liés à la réactivité / à l'expérience des développeurs serait vraiment apprécié.

Et si nous essayions de coder nous-mêmes une première version de cette fonctionnalité ? je suis
mourant d'ennui pendant le truc covid, qui veut me rejoindre?

Plusieurs personnes l'ont déjà fait, par exemple. https://github.com/insidewhy/observable-input

Le problème avec la plupart d'entre eux est que pour les faire efficacement, vous devez modifier le compilateur ou d'autres parties internes d'angular.

Cela ne compte pas. Je veux dire, faisons une contribution appropriée à l'angulaire
coeur. Après tout, nous avons le code source disponible. En fait, je ne pense pas que nous aurons même besoin de toucher au compilateur dans ce cas.

@ganqqwerty J'ai essayé de l'implémenter dans Angular avant d'écrire cette bibliothèque. Angular est extrêmement compliqué cependant. Pour être honnête, le code est bien plus lisible et compréhensible que React et ses fonctions folles de cinq cents lignes, mais il est "sophistiqué". Et j'aurais quand même été heureux de faire l'effort de faire cette mise en œuvre si j'avais pensé que cela en valait la peine. Mais je ne pense pas que cela en vaille la peine pour précisément les raisons @fxck itérées ci-dessus. L'équipe Angular n'écoute pas la communauté, elle est constamment obsédée par les optimisations et les performances sans se soucier de la convivialité d'Angular en général. Je me fiche d'un framework qui fonctionne bien lorsqu'il m'oblige à implémenter un passe-partout pour des problèmes simples qui ont été démontrés il y a cinq ans. J'ai donc décidé d'arrêter de me soucier d'Angular, de mettre en œuvre le minimum d'efforts dont j'avais besoin pour soutenir les projets sur lesquels je travaillais déjà et de l'éviter chaque fois que possible pour tous les projets futurs.

Ce n'est pas seulement un problème avec Angular, je pense, mais avec de nombreuses offres de Google. Ce problème et les autres répertoriés par @fxck ci-dessus ne sont que d'autres exemples de problèmes endémiques chez Google. Si vous regardez Dart ou GoLang, vous verrez également que les développeurs soulèvent des problèmes courants très connus et que les problèmes restent ouverts pendant plus de 5 ans.

Je suis d'accord que cela devrait être ajouté, mais wow, la haine sur ce fil est un peu trop, je veux dire que nous parlons d'ajouter quelque chose qui permet d'économiser quelques lignes de code. Vous pouvez maintenant avoir des entrées observables avec un setter décoré avec @Input et votre propre sujet sur

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

Si c'est trop simple, nous avons déjà quelques options tierces simples :

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

Je suis satisfait du développement d'Angular et n'abandonnerais certainement pas le cadre incroyablement complet et fiable à cause d'une fonctionnalité aussi insignifiante (bien que souhaitable).

Le problème général est principalement du point de vue de la façon dont les gens le voient. Pour quelqu'un, il s'agit de quelques lignes de code et il semble assez simple de modifier/ajouter quoi que ce soit, mais en réalité, il y a beaucoup plus de portée et de nombreux effets secondaires. Tous doivent être pris en compte et comme toujours, l'éventail des sujets est long et tout a un prix de revient, une valeur ajoutée et une priorité.

Je tiens à souligner que personnellement, je ne m'attends pas nécessairement à ce que tous ces problèmes soient résolus immédiatement.

Mais j'espère que maintenant, qu'Ivy est à l'écart et qu'il est dans la nature depuis un certain temps, une sorte de mise à jour officielle sur, disons, les 25 principaux problèmes votés, serait publiée.

Je veux dire, je ne trouve pas possible pour un projet de cette taille de ne pas avoir dans la gestion de projet considéré comme prioritaire et une sorte de plan pour tous les 25 principaux (ou autre) problèmes votés. La plupart d'entre eux ont même une balise effort . Créez simplement un article de blog, informez la communauté que vous les connaissez et que vous avez une sorte de plan pour eux.

Je n'abandonnerais certainement pas non plus Angular, malgré toutes ses lacunes, je l'aime toujours beaucoup mieux que toutes les autres alternatives. Mais je pense qu'il est juste de dire qu'il manque de "gestion des relations avec la communauté" (sur github en particulier).

// Éditer

Cela vous dérangerait-il de remplir ce sondage ? Compte tenu de votre situation actuelle et tout bien considéré, lequel de ces problèmes vous affecte le plus / améliorerait le plus votre expérience de développeur https://forms.gle/cprhx239kuqwWd5M8

@fxck Merci d'avoir écrit cela. Je commençais à me demander si tout le monde venait d'accepter le fait que l'équipe Angular fasse ce qu'elle veut, quand elle veut. Bien que ce soit certainement leur droit, je pense également qu'il est nécessaire que les gens les appellent lorsqu'ils ignorent continuellement la voix des développeurs. Je conviens que je ne pense pas que quiconque s'attende à une résolution immédiate des problèmes, mais les ignorer pendant 4 à 5 ans ou simplement attendre que le problème soit automatiquement verrouillé ne semble vraiment pas professionnel pour tout projet, sans parler d'un projet exécuté par Google. Ils ont gagné du temps en ajoutant des balises « Fixed by Ivy » à un tas de problèmes ouverts, puis ont poursuivi en ne faisant rien.

Je n'abandonnerais certainement pas non plus Angular, malgré toutes ses lacunes, je l'aime toujours beaucoup mieux que toutes les autres alternatives. Mais je pense qu'il est juste de dire qu'il manque de "gestion des relations avec la communauté" (sur github en particulier).

Je pense que cette phrase résume parfaitement mes pensées.

@chriszrc Je n'ai pas vraiment interprété quoi que ce soit dans ce fil comme de la "haine". Plus comme des gens qui expriment enfin leurs frustrations avec Angular en ignorant régulièrement les problèmes pendant des années. Il ne s'agit même pas spécifiquement de cette question, il s'agit plutôt du principe du maintien d'une certaine forme d'interaction communautaire. L'équipe Angular est-elle considérée comme tellement supérieure à n'importe qui d'autre qu'elle pense qu'elle peut ignorer les demandes des développeurs parce qu'elle sait ce qui est le mieux pour tout le monde ?

@chriszrc Je ne vois aucune haine dans ce fil, juste un tas de frustration compréhensible. Je pense qu'assimiler cette demande et la déception qui en découle à « économiser quelques lignes de code » est une exagération. Ce n'est pas seulement ce problème qui frustre la communauté, mais l'ensemble important de problèmes populaires soulevés par @fxck ci-dessus qui ont été négligés.

Bonjour à tous, excusez-nous pour le silence sur ce fil. Il y a deux demandes orthogonales que nous recevons depuis un certain temps :

  1. Meilleur support RxJS de première classe dans le framework
  2. Moins de RxJS dans Angular, le rendant potentiellement facultatif

Les deux demandes sont sur notre radar, et les deux ont leurs avantages et leurs inconvénients. Par exemple, si nous allons dans la première direction, nous rendrons le framework moins accessible aux ingénieurs qui découvrent l'API expressive et sémantiquement riche de RxJS. De nombreuses personnes s'inquiètent de l'utilisation de RxJS partout dans leurs applications angulaires, ce qui rend le code source difficile à lire entre les membres de l'équipe ayant différents niveaux d'expérience.

En même temps, nous avons déjà beaucoup d'API réactives, mais certaines des primitives proposées par Angular sont tout à fait impératives et les choses ne se passent pas très bien. Cela dit, il est logique d'améliorer le support de la réactivité, mais cela doit-il faire partie du noyau d'Angular ou être délégué à un projet communautaire (ngrx - l'extension réactive d'Angular, par exemple) avec lequel nous collaborons étroitement ?

Il existe de nombreuses façons de résoudre ce problème, mais nous devons prendre en compte :

  • Rétrocompatibilité - non seulement pour le code source mais aussi pour les ressources de formation
  • Courbe d'apprentissage
  • Cohérence avec les API actuelles
  • Cohérence entre les projets
  • Performances - temps d'exécution et temps de chargement initial

Nous sommes en train de hiérarchiser certains des principaux problèmes de GitHub, en examinant les améliorations les plus demandées et les plus percutantes que nous pouvons résoudre. Je dirais que c'est l'un des plus difficiles, il est donc difficile de s'engager sur une date.

@mgechev Merci d'avoir répondu. Si les rxjs et les apis réactifs doivent être divisés en une autre extension (pas mon vote personnel), serait-il plus logique de ne pas coupler cela avec une implémentation de magasin d'état/redux particulière ? Je suis rapidement passé de ngrx à ngxs (qui ressemblait à beaucoup moins de passe-partout et beaucoup plus "angulaire" avec les décorateurs), puis finalement à Akita, qui est mon préféré actuel et celui avec lequel j'ai le plus développé. Ou s'il est regroupé avec ngrx, au moins, il est vraiment facile d'ajouter simplement les pièces dont nous avons besoin, afin que nous ne soyons pas contraints d'utiliser ngrx ou d'inclure ces dépendances-

Si les rxjs et les apis réactifs vont être divisés en une autre extension (pas mon vote personnel)

Je ne dis pas que c'est ce qui va se passer. Dans mon commentaire, je partage juste une liste incomplète d'alternatives afin que je puisse montrer la portée du projet et les différentes considérations que nous avons.

@mgechev en effet, merci pour la réponse.

Je me demande cependant, si la partie réactive d'Angular est en quelque sorte "rétrogradée" dans le projet communautaire, cela ne signifierait-il pas que réactif deviendra un citoyen de deuxième classe d'Angular?

@mgechev Je sens ta douleur se déchirer dans deux directions à la fois. Notre équipe n'est en effet pas opposée au fractionnement des pièces impératif/réactif.

Voici nos exigences pour une telle division :

  • Utiliser à la fois le besoin impératif et réactif de se sentir natif et aucun ne devrait se sentir boulonné sur
  • Pas de lien avec une solution de gestion d'état spécifique pour permettre la réactivité (divulgation complète, nous avons déjà migré les 50+ projets pour utiliser akita)
  • Les deux options doivent être publiées dans une seule version en même temps (pas de lag/délai)
  • Il ne peut y avoir de "favori", tout ce qui est angulaire devrait fonctionner dans les deux mondes tout en se sentant natif
  • Prise en charge officielle complète des deux approches, soutenue par l'équipe angulaire (d'après notre expérience, il s'agit d'une exigence du client à l'arrêt)

Sur la base de ce qui précède :

  • Il y a 2 options principales :

    • core impératif + addon réactif

    • core réactif + addon impératif

  • L'emballage réactif pour le faire paraître impératif est assez simple, pas l'inverse
  • Par conséquent, nous voterions pour l'utilisation de réactif dans le noyau et pour que l'addon contienne les API impératives
  • En raison du délai zéro + aucune exigence de favoris ainsi que du support officiel requis, je ne vois pas en quoi l'addon peut être un projet communautaire

Je comprends que ce qui précède est notre vision du monde et qu'il y en a beaucoup d'autres. La raison pour laquelle j'écris ceci est :

  • Si vous atterrissez sur l'extraction réactive dans un projet communautaire, nous devrons migrer plus de 50 solutions vers un autre framework (encore une fois, ce sera axé sur le client, pas notre choix)
  • Je demanderais donc à nous (la communauté) de savoir dès que possible où vous atterrissez sur cela afin que nous ayons le temps de recycler nos développeurs sur un autre framework et de migrer ces projets

ajouter la fonctionnalité s'il vous plaît

@mgechev Je ne comprends pas vos préoccupations. Cette proposition consiste à combiner les deux mondes avec une interface uniforme et simple pour les développeurs novices. Il ne s'agit pas de choisir l'un ou l'autre mais plutôt de permettre la combinaison. Par exemple, le développeur x décide de créer un composant réactif génial. Et le développeur y décide de l'utiliser dans son projet pas si réactif. Pourquoi pas? Pourquoi a-t-il besoin de dépendre d'une colle ngrx ?
La différence entre les deux mondes est de savoir si vous stockez/gérez l'état dans votre composant intelligent ultime par rapport au magasin d'état central et c'est ce que devrait être ngrx, mais pour les composants, je pense que le cadre lui-même devrait être le catalyseur.

Il y a deux demandes orthogonales que nous recevons depuis un certain temps :

  1. Meilleur support RxJS de première classe dans le framework
  2. Moins de RxJS dans Angular, le rendant potentiellement facultatif

Je serais bien de toute façon, mais cela donne parfois une impression de décousu à Angular, ce qui est la dernière chose que vous voudriez excepter d'un cadre avec batteries incluses.

Personnellement, je suis curieux de voir comment vous auriez même des versions non RxJS pour tous les packages Angular (HTTP, Router, Forms). Je soupçonne qu'il n'y a pas de bonnes versions non-RxJS de ceux-ci, c'est pourquoi ils ont RxJS en premier lieu.

C'est-à-dire... à moins que je manque quelque chose, (2) n'est pas faisable.


PS Je ne qualifierais pas ces demandes d'"orthogonales" ; plutôt "en face".

Moins de RxJS dans Angular, le rendant potentiellement facultatif

Par curiosité @mgechev , y a-t-il des problèmes avec Github pour cela ? (Je n'en ai vu aucun.) Ou est-ce plutôt un truc de Googleur ?

@pauldraper J'ai vu au moins un problème sur github où quelqu'un se plaint de la complexité horrible de rxjs et souhaite qu'il soit complètement facultatif. Personnellement, j'adore rxjs, mais j'ai maintenant travaillé avec deux équipes où cela a suscité la peur et la répugnance des développeurs juniors et seniors. De plus, orthogonal est le meilleur terme qu'inverse, car il est possible d'implémenter les deux requêtes en même temps (étant donné que chaque solution peut être travaillée sans que l'une n'enlève l'autre en fournissant plusieurs options d'API pour consommer les choses de manière réactive et impérative).

Pour chaque commentaire se plaignant de rxjs sur github, il y a probablement des milliers de développeurs qui l'utilisent et l'apprécient sans problème.

image

image

Voici les résultats de ce formulaire que j'ai posté ci-dessus (près de 200 personnes ont répondu), alors que j'en discutais sur Angular Discord.

Sans surprise, les formes sont la plus grosse douleur dans le cul, mais apparemment @brandonroberts et @MikeRyanDev pourraient enfin cuisiner quelque chose.

Pour chaque commentaire se plaignant de rxjs sur github, il y a probablement des milliers de développeurs qui l'utilisent et l'apprécient sans problème.

Même si j'aime rxjs, je ne suis pas aussi optimiste. J'ai travaillé avec beaucoup de développeurs qui sont tellement épuisés que l'idée de devoir consacrer du temps pour apprendre quelque chose avec une courbe d'apprentissage abrupte est un cauchemar. Et beaucoup qui se soucient bien plus de gagner de l'argent que de coder :D

J'ai travaillé avec beaucoup de développeurs qui sont tellement épuisés que l'idée de devoir consacrer du temps pour apprendre quelque chose avec une courbe d'apprentissage abrupte est un cauchemar. Et beaucoup qui se soucient beaucoup plus de gagner de l'argent que de coder

Ce sont les développeurs qu'Angular essaie de répondre à ce moment-là, épuisés et sans vouloir apprendre? :) Et qui s'en soucie même à ce stade de toute façon. Angular existe depuis un certain temps, ça ne va nulle part et ça ne va absolument pas perdre de la traction si vous ajoutez un cycle de vie observable, une entrée observable, des événements observables. Ajoutez simplement ces trois petites choses et les gens seront heureux pendant un moment, c'est tout (et suivez cela avec https://indepth.dev/component-features-with-angular-ivy/ pour compléter le package de base).

angular_rxjs

Celui-ci dit tout. IMHO Angular devrait rester cohérent et utiliser plus de RxJS : sans RxJS du tout, ce ne serait pas Angular.

Ce sont les développeurs qu'Angular essaie de satisfaire alors? :)

Oui, il serait prétentieux de ne s'adresser qu'aux développeurs qui souhaitent écrire du code à l'aide de rxjs. Même si je préfère utiliser rxjs, je veux qu'Angular s'adresse aux deux groupes de développeurs. Pourquoi Angular devrait-il s'adresser uniquement à nous et non à ceux qui pensent différemment ? Surtout quand je pense que nous sommes minoritaires, pas majoritaires.

Encore une fois, aller « entièrement réactif », comme en ajoutant des cycles de vie observables, des entrées, des événements n'affecterait en aucun cas ceux dont vous parlez, mais rendrait l'autre groupe très heureux.

Et les fonctionnalités des composants sont utiles que vous aimiez ou non la programmation réactive.

@fxck Je n'ai jamais été en désaccord avec cela une seconde. Je répondais juste à votre commentaire précédent pour souligner qu'il y a beaucoup de gens qui ne veulent pas utiliser rxjs et beaucoup d'entre eux ont ouvert des problèmes github pour s'en plaindre.

Malgré la façon dont angulaire décide de développer le noyau - de manière réactive ou non, dans le monde idéal, il y aurait le package opposé construit sur le dessus pour répondre aux besoins opposés (par exemple @angular/reactive ou @angular/imperative - avec de meilleurs noms avec un peu de chance).

L'un ou l'autre de ces deux accès à la communauté est pour moi un déclassement pour certaines personnes et pour moi, le fait d'avoir la perspective d'être un excellent cadre réactif était une raison de l'utiliser en premier lieu.


En passant, je pense qu'il serait plus facile de garder angulaire réactif et d'avoir des extensions impératives, car c'est beaucoup plus facile à relier, plutôt que de relier impératif à réactif - en parlant de la simplicité du noyau et du package d'extension.

Avis de non-responsabilité : le dernier point que j'ai formulé sur la base d'hypothèses - je ne serais pas surpris s'il est beaucoup plus facile d'écrire l'impératif de base - l'extension réactive serait plus complexe.

Par curiosité @mgechev , y a-t-il des problèmes avec Github pour cela ? (Je n'en ai vu aucun.) Ou est-ce plutôt un truc de Googleur ?

Pas une chose interne à Google. Vous seriez surpris (comme moi lorsque j'ai rejoint l'équipe) de l'ampleur de l'intersection entre les exigences externes et internes. La principale différence réside dans le système de construction et la gestion des dépendances, à part cela, les Googleurs ont à peu près les mêmes exigences que les non-Googleurs.

Nous sommes en contact avec des milliers de développeurs - beaucoup d'entreprises externes, d'équipes internes et de contributeurs individuels. Dans les deux cas, il y a des gens qui aimeraient se lancer pleinement dans RxJS et d'autres qui ne pensent pas que c'est le bon choix pour eux. Les deux camps ont d'excellents arguments.

Ce n'est pas une décision que nous voudrions précipiter, d'autant plus qu'il existe des solutions de contournement/communauté bien établies. Le travail effectué en communauté nous aide à collecter des points de données supplémentaires et à établir une solution optimale pour l'ensemble actuel de variables.

Je pense qu'avoir une approche unifiée réactive ou impérative (c'est un choix par projet) lors du développement d'une application angulaire serait très bénéfique. La possibilité de mélanger et de faire correspondre ne facilite pas l'expérience de développement et ne crée pas de code DRY (par exemple, des entrées non réactives).

Rien ne se passe de manière isolée, je peux donc tout à fait comprendre que les environnements d'entreprise ont du mal à recycler de grandes quantités de développeurs à la programmation réactive. Donc, abandonner l'impératif déplacerait vraiment angulaire hors du cadre idéal de l'entreprise, ce qui, soyons réalistes, ne se produira tout simplement pas car il constitue une grande base d'utilisateurs clés pour un cadre comme angulaire.

Cela dit, ce que je ne considère pas comme réaliste, c'est de construire une interface réactive en plus d'une interface impérative. L'autre direction est assez simple car vous pouvez toujours écrire la sortie d'un observable dans une variable qui peut ensuite être utilisée de manière impérative. En fait, c'est ce que fait déjà angular à de nombreux endroits sous le capot.

Par conséquent, je vote pour rendre angulaire entièrement réactif en son cœur, puis créer des « wrappers » impératifs sur le dessus.

Le principal problème avec cette approche serait très probablement des étapes de migration plus importantes pour les utilisateurs impératifs. Ce qui est un nono dans les environnements d'entreprise qui pourrait être exactement ce que l'équipe angulaire essaie d'empêcher, d'où la suggestion de faire impératif au cœur.

@mgechev Puisque cela a été soulevé plusieurs fois, il serait intéressant d'entendre vos réflexions sur le noyau réactif / l'extension impérative et s'il a une jambe sur laquelle se tenir?

Dans les deux cas, il y a des gens qui aimeraient se lancer pleinement dans RxJS et d'autres qui ne pensent pas que c'est le bon choix pour eux. Les deux camps ont d'excellents arguments.

Super, bon à savoir. Définir le plein avec RxJS ? Comment l'ajout d'un cycle de vie observable, d'une entrée observable et d'événements observables s'intègre-t-il dans cela ? Et non, aucun d'entre eux n'a vraiment de "solution de contournement/communauté bien établie".

@fxck aucun de ceux-ci n'a vraiment de "solution de contournement/communauté bien établie".

C'est vrai. J'ai écrit l'une de ces solutions et cela ne fonctionne que grâce à un gros hack qui repose sur une mauvaise vérification de type dans les modèles. J'ai également consulté quelques-unes des autres solutions publiées dans ce fil de discussion et chacune d'entre elles présente au moins l'un des problèmes suivants :

  • fuites d'abonnement
  • exigences standard pour l'utilisateur
  • hacks aussi mauvais, sinon pire, que celui que j'ai utilisé dans ma bibliothèque.

En ce qui me concerne, c'est impossible de faire ça bien.

Les événements observables sont encore pires, il n'y a pas beaucoup de solutions communautaires, ils nécessitent généralement une étape de construction supplémentaire (qui dans certains cas casse le SSR dans les configurations monorepo) et des hacks en plus de cela même (si vous utilisez l'extension de classe par exemple pour obtenir des événements observables du cycle de vie, car hé, angular ne prend pas en charge cela nativement) https://github.com/typebytes/ngx-template-streams/issues/8

Les événements de cycle de vie sont sans doute les "plus faciles", mais doivent toujours s'appuyer sur une extension de classe ou des décorateurs personnalisés, dont aucun n'est idéal.

@fxck Autant que je sache, il n'est pas possible de nettoyer les abonnements aux événements de cycle de vie sans avoir à utiliser une classe parente (euh) ou une méthode que l'utilisateur doit appeler à partir de son propre événement de cycle de vie de destruction (pire encore).

Les événements de cycle de vie sont sans doute les "plus faciles", mais doivent toujours s'appuyer sur une extension de classe ou des décorateurs personnalisés, dont aucun n'est idéal.

J'avais également essayé d'implémenter des événements de cycle de vie (pour le rendre réactif) avec des décorateurs personnalisés et c'est pénible. ~Sans extension de classe, je ne sais pas si c'est possible sans 100 hacks~. La possibilité pour l'utilisateur d'étendre l'angle est jusqu'à présent très médiocre et elle repose sur des hacks ou de nombreux passe-partout pour le faire.

@tonivj5 Si la fonctionnalité du composant était une API publique, voyez-vous cela comme un moyen potentiel d'implémenter des cycles de vie sans héritage ?

@ntziolis hah drôle, vous devriez mentionner les fonctionnalités, je travaille actuellement sur la partie cycle de vie de ngx-sub-form et les fonctionnalités sont exactement quelque chose qui, à mon avis, aiderait. En attendant, il est tout à fait possible de patcher l'usine de composants avec ivy. Je vois cela comme étant très utile en dehors de ngx-sub-form, donc je pense que je vais diviser cette logique dans une lib séparée

@ntziolis à ce stade, je ne sais pas si nous verrons un jour les promesses d'Ivy être réellement tenues.

As-tu vérifié l'effet angulaire ? (pas ngrx/effects) https://dev.to/stupidwesome/reactive-adventures-in-angular-introducing-angular-effects-1epf Avec cet outil, vous pouvez écrire des applications entièrement réactives.
État observable bidirectionnel entre les composants parent et enfant inclus
https://dev.to/stupidwesome/exploring-the-angular-effects-api-2gol
La version 9.1.0 introduira un modèle de composition/hooks basé sur l'API de composition de Vue 3.
Je pense que c'est vraiment une prochaine étape pour angulaire de travailler avec la réactivité.

@mgechev

Ce n'est pas une décision que nous voudrions précipiter, d'autant plus qu'il existe des solutions de contournement/communauté bien établies

Juste curieux, qui sommes-nous et combien de Googleurs contribuent activement au processus de prise de décision Angular ?

Vous indiquez que ce n'est pas une décision qui devrait être précipitée, mais je me demande quelle est votre définition de non précipité? Est-ce que celui-ci applique une étiquette « Fixed by Ivy » dessus et l'ignore jusqu'à ce que davantage de développeurs recommencent à faire du bruit ? Y a-t-il une version ciblée en tête pour tout travail réactif ou d'autres versions plus récentes du compilateur doivent-elles être publiées en premier ?

Le fait qu'il y ait généralement 2500 problèmes ouverts à un moment donné revient-il dans les discussions internes ?

@ntziolis , comme l' a dit features aiderait

@ntziolis J'ai fait un autre essai avec le cycle de vie et j'ai un POC fonctionnel (sans extension de classe ni implémentation d'interfaces de cycle de vie). Il s'appuie sur une API privée (:exclamation :)

@tonivj5 hah je n'ai pas eu l'occasion de lire le vôtre mais j'ai presque aussi publié ma solution :) https://github.com/cloudnc/ngx-observable-lifecycle

L'idée avec la bibliothèque sur laquelle je travaille est d'avoir une base commune à laquelle d'autres bibliothèques peuvent se connecter pour créer leur propre fonctionnalité prenant en compte le cycle de vie. Il devrait pouvoir fonctionner de telle sorte que s'il y a plusieurs fonctions qui souhaitent accéder au même crochet, il n'y a qu'un seul crochet décoré sur le composant def.

Tout fonctionne, il suffit de trier les CI et les tests unitaires.

Le fait qu'il y ait généralement 2500 problèmes ouverts à un moment donné revient-il dans les discussions internes ?

Lol, il n'y a pas eu 2500 problèmes ouverts depuis mi-2019.

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

À mon goût, je préfère les projets open source qui gardent les problèmes ouverts à la discussion jusqu'à ce qu'il y ait une discussion/un consensus clair de la communauté plutôt que des projets qui ferment chaque problème ouvert sans discussion. C'est aussi une étape pour les responsables d'expliquer leurs préoccupations au fil du temps à la communauté avant de fermer toute possibilité d'accepter une proposition.

@agalazis Ce problème est ouvert depuis 4 ans et demi et à peu près ignoré depuis 3 ans.

@agalazis Ce problème est ouvert depuis 4 ans et demi et à peu près ignoré depuis 3 ans.

Il y avait un membre de l'équipe Angular qui expliquait pourquoi cela était encore ouvert il y a seulement 5 jours, donc vous n'avez tout simplement pas raison.

@etay2000 Certaines décisions sont parfois difficiles car elles affectent l'évolution de l'ensemble du projet et c'est acceptable. Je crois que la chose la plus simple était de rejeter la proposition et de clore le problème, mais cela ne s'est pas produit pour une raison.

@beeman

Il y avait un membre de l'équipe Angular qui expliquait pourquoi cela était encore ouvert il y a seulement 5 jours, donc vous n'avez tout simplement pas raison.

Vous aimez vraiment ces emojis pouces vers le bas, hein ? Était-ce vraiment une explication ? Après plus de 4 ans, il a dit qu'ils ne voulaient pas précipiter la décision.

@agalazis
Je suis d'accord que certaines décisions sont difficiles, mais qu'est-ce qui devrait être considéré comme un délai acceptable pour retarder la prise de ces décisions difficiles ? Tous les 2855 problèmes en suspens n'impliquent pas ces décisions difficiles, mais beaucoup d'entre eux existent également depuis un certain temps également.

@etay2000 Acceptez-le ou non, ce sont des personnes open source qui ouvrent des problèmes sont bien plus que les mainteneurs. Le projet Typescript, par exemple, a presque deux fois plus de problèmes ouverts et une autre proposition que j'ai faite là-bas a également pris beaucoup de temps. Cela ne me dérange pas puisque la discussion a apporté de nombreuses alternatives qui ne sont pas aussi sophistiquées que la fonctionnalité mais ont réussi à voir beaucoup d'autres perspectives

@agalazis Vous avez raison, je suppose que j'attendais (à tort) plus d'un projet open source maintenu par Google que d'un projet plus petit.

@beeman Insérez les pouces vers le bas emoji ici : -------->

@etay2000 Vous devez toujours vous rappeler que chaque décision aussi importante affecte des centaines de milliers de choses, de projets et de personnes. Et ce qui est encore plus important, une décision imparfaite et l'introduction d'API publiques, qui entraîneraient des changements décisifs peu de temps après, n'est qu'un cauchemar. Vous pouvez voir presque sur chaque PR, comment chaque étape est examinée, et si elle n'est pas parfaite, elle attend simplement, des semaines, des mois ou même des années.

@agalazis Vous avez raison, je suppose que j'attendais (à tort) plus d'un projet open source maintenu par Google que d'un projet plus petit.

Je ne sais pas, regarde Go et dard aussi. Google est en fait assez célèbre pour avoir ignoré les demandes de la communauté extrêmement populaires pendant une demi-décennie :D En général, leur approche des langages/frameworks/etc. est très conservateur . Vous pouvez voir apparaître de nouvelles langues et de nouvelles idées qui révolutionnent des domaines et Google ne les adopte toujours pas depuis des années, par exemple la sécurité nulle a frappé Kotlin, TypeScript et Scala bien avant Dart. Je suppose qu'il y a des avantages et des inconvénients à ce genre d'approche, mais pour moi au moins, j'ai tendance à éviter les choses développées par Google dans la mesure du possible car cela ne correspond pas vraiment à ma philosophie.

(Désolé pour cela, tout le monde, mais je dois le faire.)

@beeman Insérez les pouces vers le bas emoji ici : -------->

@etay2000 Je ne sais pas du tout en quoi ce genre de commentaire aide, sinon une violation de la conduite ici. Je suis presque sûr que tout le monde sait comment baisser les pouces, alors à quoi bon le sarcasme ?

Pour rappel, personne n'est obligé d'utiliser Angular, vous pouvez essayer de trouver un autre framework où les gens vous plaisent davantage.

@brunojcm Je suppose que la fête est finie maintenant que la police des commentaires est là. Le fait est qu'il a rejeté tous mes autres commentaires, mais je ne savais pas que le sarcasme était une violation de la conduite.

Pour rappel, personne n'est obligé d'utiliser Angular, vous pouvez essayer de trouver un autre framework où les gens vous plaisent davantage.

La façon dont je veux vraiment répondre à cela violerait définitivement le code de conduite ici.

J'ai terminé, chacun peut reprendre sa programmation habituelle. Je reviendrai dans 4 à 5 ans pour voir comment les choses se sont passées.

@tonivj5 @zakhenry C'est bien d'entendre que cela pourrait être une avenue.

@mgechev Je comprends que ce n'est même pas une discussion préliminaire, mais j'aimerais entendre vos réflexions sur :

  • noyau réactif + extension non réactive vs l'inverse.
  • et plus spécifiquement à ce problème, y a-t-il une chance réaliste d'exposer l'API de fonctionnalité de quelque manière que ce soit.

    • même si c'est juste avec la mise en garde de ruptures de changements à l'avenir tant que la fonction générale serait toujours accessible.

    • Comme @zakhenry l' a fait pour les événements du cycle de vie, je vois un ou un nombre très limité de projets créant des API qui peuvent être utilisées par d'autres au lieu d'accéder directement à ces API

    • Vous pouvez ensuite travailler avec ces équipes de wrapper pour les informer des changements de rupture à venir dès le début (donc très similaire à votre suggestion sur les extensions réactives)

Je pense que vous pouvez appliquer directement le module réactif de Vue 3.0 (réf ou réactif) et résoudre ce problème.

@AnonymousArthur si vous parlez du package @vue/reactivity cela n'a aucun rapport avec ce dont nous discutons ici car il fournit une réactivité aux propriétés et n'a rien à voir avec les flux réactifs (c'est ce qu'est RxJs).

@gund Oui, je suis d'accord. Cependant, cette conversation prend assez de temps (4,5 ans) et n'est pas encore terminée, alors je viens de faire apparaître une idée (peut-être pas) très rapidement pour ceux qui ne veulent pas écrire s'abonner/désabonner ou ngOnChange Handler. RxJS fournit une fonction de réactivité et cette conversation (je n'ai pas tout lu) parle d'envelopper la valeur d'entrée avec l'observable en tant que sucre syntaxique pour le rendre regardable et je pense que c'est une idée géniale.

Je pense que cette idée est vraiment utile et que le prototype de

Permettez-moi de proposer un léger ajustement sur cette solution pour corriger quelques lacunes, mais fondamentalement la même approche :

Angular définirait un décorateur @OInput() et un type EventReceiver<T> qui étend Observable<T> mais ajoute également un .value getter (comme BehaviorSubject<T> ).

Du côté du composant parent , comme dans l'exemple de @robwormald , rien ne change. Si vous voulez y passer une valeur Observable, vous avez toujours besoin de | async . Ou vous pouvez lui passer un type non observable, c'est bien (comme toujours) aussi.

Du côté du composant enfant , voici à quoi je propose que cela ressemble (un léger écart par rapport à cette proposition):

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

Voici maintenant les avantages de cette approche, qui me semblent un peu sous-estimés :

  • Cela permet effectivement des conceptions entièrement réactives dans les composants parent et enfant, si vous le souhaitez.
  • Dans les composants parents, maintient les modèles de conception d'entrée existants d'Angular, de sorte qu'aucun composant n'y soit forcé ou ne doive concevoir autour de celui-ci.
  • Les contextes parent et enfant sont entièrement indépendants, le parent n'a pas besoin de savoir si l'enfant utilise Input ou OInput , éliminant ainsi le risque de bogues entre composants liés à ce changement.
  • Il est relativement facile de migrer partiellement un seul composant enfant, si vous le souhaitez, car Angular les maintient tous connectés aux événements de cycle de vie existants comme auparavant.
  • Étant donné qu'Angular implémente cette fonctionnalité, tous les EventReceiver peuvent inclure en interne un tube jusqu'à takeUntil(ngOnDestroyEvent) , donc la plupart des cas n'auront pas besoin de se rappeler de se désinscrire lorsque leur composant est détruit, car ces observables se termineront automatiquement . (Yay réduit les fuites de mémoire !)
  • Dans ce composant enfant, cela ressemble et fonctionne de manière très similaire au modèle de @Output() aujourd'hui, ce qui donne un bon parallélisme et une capacité potentielle à les connecter correctement.

    • Note latérale : en guise de suivi, je pense qu'il serait cool de proposer un @InputOutput() qui utilise un ReplaySubject<T>(1) pour connecter les comportements pour une liaison bidirectionnelle de manière plus transparente et cohérente. Mais cela a ses propres défis et arguments, donc je ne propose

  • Pas de nouveaux types de passe-partout pour que cela fonctionne, c'est aussi simple que @Output() .
  • Angular ferait de manière transparente switch() les modifications apportées aux Observable entrées par le parent, de sorte que les modèles réactifs plus faibles comme celui-ci ne collent pas à la même instance Observable n'ont pas besoin d'être dans un cas particulier ( switch() ed) dans les composants enfants.

Note à propos du nom OInput que j'ai choisi : de toute évidence, c'est ouvert au débat. Cependant, j'aime personnellement ce nom parce qu'il est l'abréviation de « Entrée observable » ET parce qu'il ressemble un peu à « Sortie », qui est ce que cela reflète.

Chère équipe Angular. S'il vous plaît, donnez-nous quelque chose à espérer en 2020 :-)

De plus, la solution @ViewChild a { read } . par exemple:

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

Voilà pour avoir quelque chose à espérer en 2020. :D À moins bien sûr que cela (et d'autres problèmes énumérés ci-dessus) ne compte comme un bogue et non comme une nouvelle fonctionnalité. :)

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

@fxck je peux avoir une opinion impopulaire ici , mais si 2020 est honnêtement l'année était l' équipe angulaire décide de squash beaucoup de bugs sur les formulaires, routeur , etc. Je ne serais pas fou du tout avec 0 caractéristiques: haussement :.

image

Cela dit, c'est peut-être plus un problème lié aux événements récents et je suppose qu'il se passe des choses compliquées en ce moment dans l'équipe Angular. J'espère qu'ils parviendront à garder les gens formidables qui ont activement construit Angular jusqu'à présent : coeur:. Mais c'est une autre histoire.

Désolé pour le hors sujet. S'envole

@maxime1992 Ce serait bien aussi pour moi.

J'ai peut-être une opinion impopulaire ici mais honnêtement si 2020 est l'année où l'équipe Angular décide d'écraser beaucoup de bugs sur les formulaires, le routeur etc. Je ne serais pas du tout en colère avec 0 fonctionnalités

Mais ce qui me rend nerveux, c'est le fait qu'il existe des processus RH malsains à long terme au sein de l'équipe Angular qui nous affectent, sans nous. Surtout du point de vue des investissements massifs dans ce domaine.

Depuis mon POV, ils résolvent les problèmes principalement en les fermant via BOT - en laissant sans réponse et en fermant par bot., .. :-/

@ montella1507 Non, ce n'est pas tout à fait vrai. Le bot ne verrouille que les problèmes déjà fermés. Et c'est déjà vrai que les membres de l'équipe Angular ont beaucoup d'efforts dans de nombreux cas lorsqu'ils essaient d'expliquer ce qui est nécessaire pour décrire et reproduire lorsque de nouveaux problèmes sont entrés. C'est un processus très long et qui demande beaucoup de patience.

Pour ceux qui blâment l'équipe Angular et se plaignent de ne pas obtenir les fonctionnalités et les modifications rapidement :
Je comprends ta douleur. J'aimerais aussi voir cette fonctionnalité dans Angular, je changerais aussi beaucoup de choses que je n'aime pas personnellement.

Mais peut-être qu'Angular n'est pas censé être un framework qui a tous les nouveaux jouets brillants et qui obtient des tonnes de fonctionnalités à chaque version. Et ça me va. Il doit y avoir des cadres qui visent plus de niveau d'entreprise et offrent stabilité et fiabilité. Et Angular le fait très bien, du moins d'après mon expérience.

J'aime plus Vue. Je l'utilise pour mes projets personnels. Mais mes projets peuvent rapidement devenir obsolètes et je ressens le besoin de passer à un nouveau style de composant. De plus, lorsque je fais des mises à niveau, les choses se cassent toujours de la manière la plus étrange. L'écosystème semble également avoir plus de mal à maintenir la compatibilité.

Angular en revanche est mature et stable. Cela ne change pas souvent, mais cela signifie également que vous avez moins de travail pour refactoriser votre code car vous maintenez vos dépendances à jour, ce qui est précieux pour les produits commerciaux. Vos connaissances restent également pertinentes plus longtemps et au lieu d'essayer de suivre le rythme, vous pouvez approfondir.

Les personnes

@insidewhy Soyez patient, il y a toujours des pics et des vallées sur la route, mais cela ne veut pas dire que d'autres n'en ont pas aussi ou qu'il y a des erreurs principales. Cela signifie seulement que les choses pourraient avancer plus rapidement et plus efficacement qu'elles ne l'ont fait en réalité.

Il n'y avait aucune mention d'un problème particulier susmentionné dans la feuille de route, ce que j'ai trouvé triste, j'espérais vraiment qu'il y aurait quelque chose, une mention, une reconnaissance ... cette discussion a suivi sur Angular Discord -

image

Je leur ai donné le bénéfice du doute et leur ai demandé dans le commentaire de cet article de la feuille de route moyenne , la réponse de Minko :

image

Il a à peu près réitéré ce qu'il a dit ici il y a quelques mois, aucun de ces problèmes liés à rxjs n'est résolu de si tôt, alors oui.

J'ai fini d'essayer de faire comprendre mon point de vue, mais permettez-moi d'essayer une dernière fois.. Je ne demande pas qu'Angular soit transformé en

  • cycle de vie observable
  • entrée observable
  • événements de modèle observables

Aucun de ceux-ci ne rompt la compatibilité descendante, n'augmente la courbe d'apprentissage, n'est cohérent avec les autres API et je peux imaginer qu'il n'affecte guère les performances . Ajoutez simplement un à la fois, montrez que vous vous en souciez. S'il te plaît.

@fxck :+1: bien sûr.

  • cycle de vie observable
  • entrée observable
  • événements de modèle observables

@insidewhy Soyez patient

Demander aux gens plus de 5 ans de patience n'est pas si pragmatique quand il y a beaucoup de concurrents qui défilent dans la course, tous en lice pour attirer l'attention.

@ insidewhy Cela signifiait plus généralement.

@fxck Google a (selon mon dernier décompte) 4000 applications construites de manière angulaire et de nature très similaire, la commutation entre ces projets et l'examen par les pairs est (j'imagine) assez transparente. Même dans mon entreprise, l'un des énormes avantages d'Angular est que sans même que je révise le code d'une autre équipe, je sais que c'est dans un état où un examen par les pairs ne déclenche pas une enquête entière.

Maintenant, disons que nous implémentons chacun de ces raccourcis RxJS utiles dans le noyau, que se passe-t-il alors ? Il est possible que nous nous retrouvions avec un biais procédural par rapport à un biais réactif, sans indication claire du biais correct pour un cas particulier. Après avoir lu les discussions jusqu'à présent, la réponse de l'équipe angulaire n'est pas "Ceci est une faible priorité" (comme le suggère votre flux), elle semble en fait plus proche de "Nous ne voulons pas prendre parti".

Les utilisateurs avancés de RxJS dans la communauté Angular ici sont une minorité vocale, car après avoir exploré Typescript, DI, les modèles et les diverses bibliothèques d'Angular, vous avez presque 1 an à votre actif pour utiliser le framework quotidiennement, et vous êtes maintenant prêt pour bien comprendre RxJS. Laisser les personnes de haut niveau partir avec des biais de réactivité dans les évaluations par les pairs aliène encore plus les gens, et c'est littéralement la dernière chose dont Angular a besoin.

L'objectif d'Angular (comme je le vois) est de réduire et d'atténuer les conversations loin de "Utiliser la technologie X parce que c'est mieux, voici une courte nouvelle pourquoi" et de maintenir les conversations dans les revues par les pairs sur la logique métier mise en œuvre. Voulons-nous vraiment stratifier nos composants entre angulaire "Avancé" et angulaire "Débutant" plus que nous ne l'avons déjà fait ?

Ce sont sans doute les mêmes arguments que nous avons vus avec la gestion d'état, pourquoi Angular devrait-il déterminer parmi les nombreux modèles possibles celui qui est correct ?

Permettez-moi de citer l'un des membres de l'équipe angulaire pour vous.

image

En passant, il n'y a absolument rien d'avancé à propos de ces éléments (cycle de vie observable, entrée observable, événements de modèle observables).

Ce sont sans doute les mêmes arguments que nous avons vus avec la gestion d'état, pourquoi Angular devrait-il déterminer parmi les nombreux modèles possibles celui qui est correct ?

La différence entre la gestion étatique et cela, c'est que la gestion étatique pourrait être effectuée par la communauté, il n'y a rien à l'intérieur du noyau angulaire qui l'empêche. Malheureusement, Angular ne fournit aucun moyen de mettre en œuvre correctement aucun des trois que j'ai mentionnés. (edit: lien corrigé pour commenter)

Je suis de tout cœur pour laisser autant que possible à la communauté, qui comprend des packages tels que des formulaires, un routeur, une disposition flexible, universelle, etc., laissez l'équipe Angular se concentrer sur le noyau, la CLI et les composants. Mais pour cela, ils doivent fournir à la communauté suffisamment de points d'entrée, comme par exemple autoriser des composants d'ordre supérieur . Mais ils n'ont pas réussi à le faire pendant des années (souvent en disant qu'Ivy est nécessaire en premier) et refusent de reconnaître / d'en parler dans leurs plans maintenant.

Après avoir lu les discussions jusqu'à présent, la réponse de l'équipe angulaire n'est pas "Ceci est une faible priorité" (comme le suggère votre flux), elle semble en fait plus proche de "Nous ne voulons pas prendre parti".

Oui et ça fait peur.

@fxck Je pense vraiment que nous sommes sur la même

Oui et ça fait peur.

C'est peu hyperbolique, nous n'avons pas " besoin " de @angular/core pour avoir ces modèles, en fait, il existe de nombreuses variantes et bibliothèques dans ce numéro qui peuvent être utilisées aujourd'hui sur n'importe quel projet. La seule réticence à utiliser les options mentionnées précédemment est que vous devrez peut-être, à l'avenir, migrer vers quelque chose qu'Angular fournit en remplacement standard de @angular/core . Est-ce vraiment si difficile pour nous de npm uninstall et de corriger toutes les erreurs dactylographiées ?

Les décisions architecturales majeures, qui affectent tous les projets angulaires, et nécessitent d'innombrables heures pour documenter et migrer si elles ne fonctionnent pas, cela me semble encore plus effrayant, et nous y sommes déjà allés :

C'est peu hyperbolique, nous n'avons pas " besoin " de @angular/core pour avoir ces modèles, en fait, il existe de nombreuses variantes et bibliothèques dans ce problème qui peuvent être utilisées aujourd'hui sur n'importe quel projet.

Non, pas vraiment, chaque solution nécessite des hacks ou s'appuie sur des API internes qui peuvent évoluer. C'est tout le problème .. lisez ce que https://github.com/angular/angular/issues/5689#issuecomment -630661006 et ce que j'ai dit ci-dessous à propos des flux d'événements de modèle.

// modifier le lien corrigé pour commenter

Non, pas vraiment, chaque solution nécessite des hacks ou s'appuie sur des API internes qui peuvent évoluer.

Selon vous, quelles API ou types internes devraient être rendus publics/génériques pour permettre à la communauté de s'en occuper ? Si cette conception est dans un schéma d'attente parce qu'il n'y a pas de voie claire à suivre, alors il semble approprié de demander que nous soyons autorisés à concevoir la nôtre plutôt que de frapper constamment ce même tambour.

Lisez l'autre commentaire de @insidewhy, il a essayé de le faire dans le noyau.

image

@fxck Je ne vais pas discuter de l'historique des tentatives de mise en œuvre de cela dans le noyau ou de la façon dont ce problème est ouvert depuis 5 ans, qu'est-ce qui nous empêche maintenant d'ouvrir les internes pour permettre à la communauté de développer elle-même un design ?

Yo @insidewhy , je me demande si c'est le type de vérification du hack sur lequel votre bibliothèque s'est appuyée. Apparemment ça ne marche plus avec TS 4.0

La propriété 'serviceStackId$' est utilisée avant son initialisation.ts(2729)

image

Yo @insidewhy , je me demande si c'est le type de vérification du hack sur lequel votre bibliothèque s'est appuyée. Apparemment ça ne marche plus avec TS 4.0

Non, c'était dans le compilateur de modèles. C'est autre chose. Mince. Et bien. Je peux vous ajouter à la liste des responsables si vous voulez essayer de le réparer.

@fxck En fait, vous devez affecter cet opérateur canalisé dans ngOnInit car les propriétés basées sur le décorateur ne seront injectées qu'après l'exécution du constructeur, il s'agit donc en fait d'un problème légitime avec votre code.

@insidewhy j'ai définitivement travaillé avant TS4. Et vérifie ça ,

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

il enregistre

enregistrement de la valeur modifiée this.baz ObservableInput

donc je pense que cela devrait toujours fonctionner, seulement dans TS4, le compilateur se plaint car il ne réalise pas qu'il y a un get avec une valeur à l'intérieur de ce décorateur..

J'utilise un décorateur pour détecter le changement d'accessoire d'entrée et créer une version observable de l'accessoire d'entrée. Voir cette démo codesandbox .

Voilà comment cela fonctionne:

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

Comme @wmaurer l'a souligné, @Subjectize pourrait être traité comme un "sucre" pour faire avancer les choses.

Cela vaut la peine de lire le guide officiel d'angular Intercepter les changements de propriété d'entrée avec un setter , ce qui explique que nous pouvons détecter les changements d'entrée en utilisant getter/setter .

@hankchiutw Cette solution ressemble à mon décorateur @BindObservable : https://github.com/PSanetra/bind-observable#usage

Merci @hankchiutw

Puisque vous initialisez ReplaySubject avec 1, j'ai choisi d'utiliser BehaviorSubject à la place.
J'ai également initialisé la valeur directement dans Subjectize.

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

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

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

    // ...
}

J'aimerais pouvoir éviter d'écrire le type sur la propriété "Subjectized" car il devrait pouvoir le deviner à partir de la propriété associée :( Avez-vous une idée de comment faire cela ?

Le rêve serait de pouvoir le faire et de créer automatiquement l'accessoire Subject associé (world$ dans mon cas) en tant que BehaviorSubjectet correctement initialisé.

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

    // ...
}

@mparpaillon Votre conception proposée est à peu près comme cela est fait dans https://github.com/PSanetra/bind-observable
La seule différence est que le décorateur @BindObservable() utilise un ReplaySubject sous le capot. Donc, si vous voulez que le sujet contienne une valeur initiale, vous devez également initialiser explicitement la propriété liée (même si elle est simplement indéfinie car il est possible que le type de propriété n'autorise pas les valeurs indéfinies ou nulles).

Exemple Stackblitz

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

Merci @PSanetra mais je préfère ma solution (qui est en fait la solution de Hank)

@mparpaillon J'ai essayé quelque chose pour ton rêve (ha) dans une autre démo .

L'utilisation ressemble

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

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

où vous pouvez choisir de spécifier le nom de l'accessoire subjectivé.

Bien que cela soit techniquement faisable, je crains que cela puisse être ambigu pour les développeurs (puisqu'un nouveau membre de la classe est créé sous le capot).

Merci @hankchiutw ! Typescript ne semble pas me permettre d'utiliser count$ ou myCount$.

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

Aussi, vous avez peut-être raison sur l'ambiguïté... Merci encore

Typescript ne semble pas me permettre d'utiliser count$ ou myCount$.

Vous avez déclaré les membres de votre classe comme "count" et "anotherCount", c'est pourquoi vous ne pouvez pas accéder à "myCount$" et "count$". Ils n'existent tout simplement pas, parce que vous ne les avez déclarés nulle part.

Je sais... c'est le but. Je cherchais un moyen de les déclarer du décorateur. @hankchiutw a proposé une solution et je dis juste que cela ne fonctionne pas tel quel

@mparpaillon jetez un oeil à ma solution : https://github.com/Futhark/ngx-observable-input

@Futhark Oh c'est chaud ! Merci

Cette page vous a été utile?
0 / 5 - 0 notes