JavaScript Angular Werte aus ng-content festlegen #Contentchildren

-Rayz-

Lieutenant
Registriert
Okt. 2010
Beiträge
897
Hallo,

ich habe eine Component erstellt, in der ich anhand der Klasse den Content zuweise.
HTML:
<div class="tab-content">
    <div class="foo " [ngClass]="foo ? 'show' : 'hide'">
        <ng-content select=".myTabPanel"></ng-content>
    </div>
    <div class="bar" [ngClass]="!bar ? 'show' : 'hide'">
        <ng-content select=".myTabPanelBar"></ng-content>
    </div>
</div>

In einer anderen Component füge ich meine Tab Component ein und der Content selber kommt aus mehreren, weiteren Components:

Javascript:
 <app-tab-panel>
     <ng-container class="myTabPanel">
         <div class="flex-container">
            <app-eins></app-eins>
            <app-zwei></app-zwei>
            <app-drei></app-drei>
            <app-vier></app-vier>
...
        </div>
    </ng-container>
    <ng-container class="myTabPanelBar">
        ...
    </ng-container>
 </app-tab-panel>

In meiner Tab Component gibt es nun einen Button und wenn man auf diesen klickt, soll sich in jeder Component innerhalb vom ng-container etwas ändern. Was sich ändert ist immer das selbe,drücke ich auf den Button soll in jeder Component eine CSS Klasse hinzugefügt werden. Klar könnte ich einfach in jeder Component ein Input() einfügen aber ich würde die komplette Logik gerne in meiner Tab-Component haben. Es gibt ja die Möglichkeit mit Contentchildren auf den Inhalt zuzugreifen:

<app-eins #child></app-eins>
<app-zwei #child></app-zwei>
<app-drei #child></app-drei>
<app-vier #child></app-vier>

Also so dachte ich mir das zumindest...
Innerhalb vom ng-container hab ich einfach keinen Zugriff drauf. Gibt es überhaupt Möglichkeiten das so zu realisieren? Oder evtl. über eine directive...
Es gibt ja soviele Möglichkeiten das zu realisieren dass ich gestehen muss, dass ich nicht weiß was hier nun best practice wäre.
 
Mach die Auswahl doch über *ngIf oder *ngSwitch statt über ngClass das Element zu verstecken
 
dann bräuchte ich in jedem Child eine Variable worauf sich das ngIf aber bezieht. Also müsste ich überall ein Input() hinzufügen. Ich hätte das halt gerne etwas dynamischer über den Parent gelöst.

Im Moment läuft es ja so ab:
Innerhalb vom ng-conent sind Components in denen Formulare stecken. Wenn man in der Tab Component nun den Button drückt, sollen nur die Felder angezeigt werden, die einen anderen Wert enthalten als bei der Initialisierung der Form.
Deswegen hab ich in jeder Form halt ein Input Feld und ich mach das über ngClass weil ich dann einfacher eine kleine css Animation mit einfügen kann. Sonst müsste ich das glaube ich über die Angular animations machen.

Wenn man aber nun 14 solcher Components mit Formularen hat, fragt man sich halt, ob das nicht auch automatisiert geht.. ohne überall Input() ngClass etc. einzufügen.

Hostbinding wäre toll... aber das gilt halt nicht für childs :p
 
Zuletzt bearbeitet:
Abgesehen davon, dass ich noch nicht ganz verstanden habe, was genau du erreichen willst: Der Zugriff auf Childs des Parents über eines der Childs ist so nicht vorgesehen. Was sollte denn da dann z.B. passieren, wenn du sowohl im Parent als auch im Child ein Child gleich "bennenst" (#name)?

Das was du vor hast, ist schlechter Programmierstil, du erzeugst nicht nur eine Abhängigkeit vom Child zum Parent, sondern hast diese auch noch nichtmal wirklich sichtbar!

Bitte noch einmal "von außen" (nicht anhand deiner aktuellen (gewünschten) Umsetzung) beschreiben, was passieren soll wenn du was machst, um ein eventuelles XY Problem zu vermeiden.
 
Zuletzt bearbeitet:
Mein Ziel ist ja alles übers Parent laufen zu lassen. Denke ich aber mich mal wieder schlecht ausgedrückt. Ich habe / will keine Abhängigkeit vom Child zum Parent. Der Parent soll das eigentlich alles regeln.

Aufbau ist vereinfacht dargestellt so:
Code:
<app> // Main Formgroup
    <parent>
        <ng-container> // über css Klasse im Parent erfolgt die content Zuweisung
            <child 1> // Forumlar
            <child 2> // Forumlar
            <child 3> // Forumlar
            etc.
        <ng-container>
    <button> // der Button ist im parent definiert
</app>

Das Formular in der app baut sich aus den Child Formularen zusammen.
Wird der Submit Button gedrückt, werden alle Formcontrols die keinen Wert haben aus den Childs "disabled"
Dadurch entsteht dann so eine Art Vorschau vom Formular.
 
über Viewchildren komme ich aber nicht an die Components innerhalb vom ng-container ran. Das ist ja das wo ich nicht weiter komme.. teste es deswegen gerade mit einer directive.
Service geht auch aber dann müsste ich in jedem Child ein Subscribe auf den Service machen und naja.. das will ich nicht ^^ Ich möchte eigentlich so wenig wie möglich im Child machen. also kein Input definieren, keinen Service...

Evtl. könnte ich auch eine Basisklasse definieren und die in jedem Child implementieren - muss ich mir mal überlegen.
Ziel ist einfach dass ich nicht 10 oder 20 mal immer wieder den selben Code schreiben muss für ein und die selbe Aktion.
 
Du willst also effektiv Components, die zwischen "edit" und "preview" wechseln können. Die meiner Meinung nach sauberste und beste Lösung wäre hier dann tatsächlich ein Input.

Mit einem Service hast du nicht nur noch mehr Implementierungsaufwand, sondern zugleich noch "globals", die meiner Meinung nach noch unschöner bezüglich Abhängigkeit als dein bisheriger Weg sind.

Ich würde hier ganz klar Inputs nutzen und das, wie du schon sagtest, eventuell über eine Basisklasse regeln. Ansonsten ist Code-Duplizierung nicht immer schlecht, bspw. wenn sich dadurch, wie hier, Kopplungen meiden lassen.
 
Hatte das mit der Basisklasse nun verfolgt und habe bisher folgendes:
Basisklasse:

Javascript:
export class BaseComponent implements OnDestroy {

    protected formSubscription: FormSubscriptionService;
    protected previewService: PreviewService;
    protected formCopy: string;
    protected form: FormGroup;
    public color: any;
    public asset: any;
    public gebuehren: any;
    public name: string;
    public isPreview = false;

    private subscriptions: Subscription[] = [];

    constructor() {
        this.formSubscription = AppInjector.injector.get(FormSubscriptionService);
        this.previewService = AppInjector.injector.get(PreviewService);
    }

    init(config: any, form: FormGroup): void {
        this.color = config.color;
        this.gebuehren = config.gebuehren;
        this.asset = config.asset;
        this.name = config.name;
        this.formCopy = JSON.stringify(form.value);
        this.form = form;
        this.OnChanges(form);
    }

    OnChanges(form) {
        this.subscriptions.push(form.valueChanges.subscribe((value) => {
            if (JSON.stringify(value) !== this.formCopy) {
                this.formSubscription.addForm({
                    name: this.name,
                    form: this.form
                });
            }
        }));

        this.subscriptions.push(this.previewService.isPreview.subscribe(x => {
            this.isPreview = x;
        }));
    }

    ngOnDestroy(): void {
        this.subscriptions.forEach(s => s.unsubscribe());
    }

    public getControl(name) {
        return this.form.controls[name];
    }
}

Parent:

Code:
export class xxxComponent extends BaseComponent implements OnInit {
    xxx: FormGroup;

    constructor(
        private formBuilder: FormBuilder) {

        super();
        this.xxx = this.formBuilder.group({
                xxx: new FormControl(false),
                xxx: new FormControl(false),
                xxx: new FormControl(false),
                xxx: new FormControl(false),
                xxx: new FormControl(false)
            }
        );
    }

    ngOnInit(): void {
        this.init(xxx.formValues.xxx, this.Form);
    }
}

Noch der Injector:

Javascript:
export class AppInjector {

    private static _injector: Injector;

    static set injector(injector: Injector) {
        this._injector = injector;
    }

    static get injector(): Injector {
        return this._injector;
    }
}

Funktioniert bis jetzt eigentlich so wie es soll.
 
Zurück
Oben