require-viewmodel
Erzwingt
new ViewModel(this)in der Komponente und die Vererbung vonViewModelStore<ComponentType, Keys>und hält View-APIs aus dem ViewModel heraus.
- ⭐️ Diese Regel ist in der Flat Config
rdlabo.configs.recommendedenthalten.
Diese Regel erzwingt das ViewModel-Architekturmuster. Eine Angular-Komponente muss ein mit new ViewModel(this) initialisiertes ViewModel besitzen. Die Regel verlangt mindestens eine passende Property; zusätzliche ViewModel-Instanzen weist sie nicht zurück. Das ViewModel muss ViewModelStore<ComponentType> erweitern und sollte weder host erneut deklarieren noch View-spezifische APIs wie viewChild, effect, computed oder afterNextRender enthalten.
Einzelheiten der Regel
Die Regel führt drei Prüfungen aus:
1. Die Komponente muss ein ViewModel besitzen
Eine Klasse mit @Component muss eine mit new ViewModel(this) initialisierte Property enthalten. Das erste Argument des Konstruktoraufrufs muss this sein.
2. Das ViewModel muss ViewModelStore<ComponentType> erweitern
Die Klasse namens ViewModel beziehungsweise der konfigurierte viewModelClassName muss ViewModelStore<...> oder eine Basisklasse erweitern, deren Name mit ViewModel endet oder ModelSearch ist. Das erste generische Argument muss der Typ der Host-Komponente sein. Generische Standardwerte zwischengeschalteter Klassen werden aufgelöst.
- Bei Verwendung von
ViewModelStore<ExamplePage, 'model' | 'form'>sind das zweite und weitere Typargumente erlaubt. - Mehr als zwei Typargumente bei direkter Erweiterung von
ViewModelStorewerden gemeldet. - Der Host-Typ muss zu der Komponente passen, die das ViewModel besitzt.
3. Das ViewModel darf keine View-APIs enthalten
Die ViewModel-Klasse darf folgende APIs nicht aufrufen:
viewChild, viewChildren, contentChild, contentChildren, effect, computed, afterNextRender, afterEveryRender, afterRenderEffect.
Diese Liste lässt sich mit der Option bannedApis anpassen. Die Regel erkennt direkte Aufrufe wie viewChild() und die Variante .required() wie viewChild.required(). Sie löst keine Aufrufe mit Namespace-Präfix auf.
Beispiele
Inkorrekt
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly title = 'x'; // Kein ViewModel
}
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly vm = new ViewModel(); // `this` fehlt
}
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly vm = new ViewModel(this);
}
class ViewModel extends StoreModel {} // Falsche Basisklasse
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly vm = new ViewModel(this);
}
class ViewModel extends ViewModelStore<ExamplePage> {
readonly el = viewChild('host'); // View-API im ViewModel
}
Korrekt
import { Component, computed, effect, viewChild } from '@angular/core';
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly vm = new ViewModel(this);
readonly title = computed(() => this.vm.label());
readonly el = viewChild('host');
constructor() {
effect(() => this.vm.label());
}
}
class ViewModel extends ViewModelStore<ExamplePage> {
readonly label = signal('hello');
}
@Component({ selector: 'app-example', template: '' })
export class ExamplePage {
readonly vm = new ViewModel(this);
}
class ViewModel extends ViewModelStore<ExamplePage, 'inventoryModel'> {
readonly inventoryModel = signal<Inventory | null>(null);
}
@Component({ selector: 'app-example', template: '' })
export class FoodsPage {
readonly vm = new ViewModel(this);
}
class ViewModel extends MainViewModel<FoodsPage> {}
Optionen
{
"rules": {
"@rdlabo/rules/require-viewmodel": [
"error",
{
"viewModelClassName": "ViewModel",
"viewModelStoreClassName": "ViewModelStore",
"bannedApis": [
"viewChild",
"viewChildren",
"contentChild",
"contentChildren",
"effect",
"computed",
"afterNextRender",
"afterEveryRender",
"afterRenderEffect"
]
}
]
}
}
viewModelClassName
- Typ:
string - Standard:
"ViewModel"
Der Klassenname, nach dem die Regel in der Komponente sucht. Verwenden Sie dies bei einer anderen Namenskonvention des Projekts, beispielsweise PageState.
viewModelStoreClassName
- Typ:
string - Standard:
"ViewModelStore"
Der Name der vom ViewModel zu erweiternden Basisklasse oder einer Zwischenbasisklasse, deren Name mit ViewModel endet.
bannedApis
- Typ:
string[] - Standard: die obige Liste
APIs, die innerhalb des ViewModels nicht erlaubt sind. Die Regel erkennt direkte Aufrufe und die Verwendung von .required(...); Aufrufe mit Namespace-Präfix werden nicht aufgelöst.
Wann die Regel aktiviert werden sollte
Aktivieren Sie diese Regel, wenn Ihr Projekt das ViewModel-Muster mit @rdlabo/ionic-angular-kit oder einer ähnlichen Architektur verwendet. Sie ergänzt @rdlabo/rules/no-component-writable-signal, um Komponentenzustand schreibgeschützt und ViewModel-Zustand veränderlich zu halten.