Skip to content

Commit

Permalink
refactor: revert signal changes
Browse files Browse the repository at this point in the history
  • Loading branch information
arturovt committed Feb 1, 2024
1 parent d6a3fe4 commit 3b2b343
Show file tree
Hide file tree
Showing 13 changed files with 74 additions and 82 deletions.
6 changes: 3 additions & 3 deletions integration/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="todo-list">
<div>
<h3>Reactive Form</h3>
<p>{{ injected() }}</p>
<p>{{ injected$ | async }}</p>
<form [formGroup]="pizzaForm" novalidate (ngSubmit)="onSubmit()" ngxsForm="todos.pizza">
Toppings: <input type="text" formControlName="toppings" /> <br />
Crust <input type="text" formControlName="crust" /> <br />
Expand All @@ -23,10 +23,10 @@ <h3>Todo Form</h3>
<input placeholder="New Todo" #text /> <button (click)="addTodo(text.value)">Add</button>
</div>
<ul>
<li class="todo" *ngFor="let todo of todos(); let i = index">
<li class="todo" *ngFor="let todo of todos$ | async; let i = index">
{{ todo }} <button (click)="removeTodo(i)">🗑</button>
</li>
<li *ngFor="let todo of pandas()">🐼</li>
<li *ngFor="let todo of pandas$ | async">🐼</li>
</ul>

<div class="menu">
Expand Down
66 changes: 44 additions & 22 deletions integration/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { take } from 'rxjs/operators';
import { Store, provideStore } from '@ngxs/store';
import { withNgxsFormPlugin } from '@ngxs/form-plugin';

Expand Down Expand Up @@ -37,38 +38,49 @@ describe('AppComponent', () => {
component.addTodo('Get Milk');
component.addTodo('Clean Bathroom');

const state: Todo[] = component.todos();
expect(state.length).toBe(2);
component.todos$.subscribe((state: Todo[]) => {
expect(state.length).toBe(2);
});
});

it('should remove a todo', () => {
component.addTodo('Get Milk');
component.addTodo('Clean Bathroom');
component.removeTodo(1);

const state: Todo[] = component.todos();
expect(state.length).toBe(1);
expect(state[0]).toBe('Get Milk');
component.todos$.subscribe((state: Todo[]) => {
expect(state.length).toBe(1);
expect(state[0]).toBe('Get Milk');
});
});

it('should set toppings using form control', fakeAsync(async () => {
const ngxsFormDebounce = 100;
const { pizza } = component;

fixture.detectChanges();
await fixture.whenStable();

component.pizzaForm.patchValue({ toppings: 'oli' });
tick(ngxsFormDebounce);
tick(200);
let flag = false;

expect(pizza().model.toppings).toBe('oli');
expect(pizza().model.crust).toBe('thin');
component.pizza$.pipe(take(1)).subscribe((pizza: Pizza) => {
flag = true;
expect(pizza.model.toppings).toBe('oli');
expect(pizza.model.crust).toBe('thin');
});

expect(flag).toBe(true);

component.pizzaForm.patchValue({ toppings: 'olives', crust: 'thick' });
tick(ngxsFormDebounce);
tick(200);
flag = false;

expect(pizza().model.toppings).toBe('olives');
expect(pizza().model.crust).toBe('thick');
component.pizza$.pipe(take(1)).subscribe((pizza: Pizza) => {
flag = true;
expect(pizza.model.toppings).toBe('olives');
expect(pizza.model.crust).toBe('thick');
});

expect(flag).toBe(true);
}));

it('should set toppings prefix', fakeAsync(async () => {
Expand All @@ -78,20 +90,30 @@ describe('AppComponent', () => {
component.pizzaForm.patchValue({ toppings: 'cheese' });
tick(100);
component.onPrefix();
let flag = false;
tick(100);

const pizza: Pizza = component.pizza();
expect(pizza.model).toBeDefined();
expect(pizza.model.toppings).toBe('Mr. cheese');
expect(pizza.model.crust).toBe('thin');
component.pizza$.pipe(take(1)).subscribe((pizza: Pizza) => {
flag = true;
expect(pizza.model).toBeDefined();
expect(pizza.model.toppings).toBe('Mr. cheese');
expect(pizza.model.crust).toBe('thin');
});

expect(flag).toBe(true);
}));

it('should load data in pizza form', () => {
component.onLoadData();
let flag = false;

component.pizza$.pipe(take(1)).subscribe((pizza: Pizza) => {
flag = true;
expect(pizza.model.toppings).toBe('pineapple');
expect(pizza.model.crust).toBe('medium');
expect(pizza.model.extras).toEqual([false, false, true]);
});

const pizza: Pizza = component.pizza();
expect(pizza.model.toppings).toBe('pineapple');
expect(pizza.model.crust).toBe('medium');
expect(pizza.model.extras).toEqual([false, false, true]);
expect(flag).toBe(true);
});
});
17 changes: 7 additions & 10 deletions integration/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {
FormsModule,
ReactiveFormsModule
} from '@angular/forms';
import { ChangeDetectionStrategy, Component, OnInit, Signal, effect } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { Store } from '@ngxs/store';
import { NgxsFormDirective } from '@ngxs/form-plugin';
import { Observable } from 'rxjs';

import { TodoState } from '@integration/store/todos/todo/todo.state';
import { TodosState } from '@integration/store/todos/todos.state';
Expand Down Expand Up @@ -38,16 +39,12 @@ export class AppComponent implements OnInit {
});

greeting: string;
todos: Signal<Todo[]> = this._store.selectSignal(TodoState);
pandas: Signal<Todo[]> = this._store.selectSignal(TodoState.getPandas);
pizza: Signal<Pizza> = this._store.selectSignal(TodosState.getPizza);
injected: Signal<string> = this._store.selectSignal(TodosState.getInjected);
todos$: Observable<Todo[]> = this._store.select(TodoState);
pandas$: Observable<Todo[]> = this._store.select(TodoState.getPandas);
pizza$: Observable<Pizza> = this._store.select(TodosState.getPizza);
injected$: Observable<string> = this._store.select(TodosState.getInjected);

constructor(private _store: Store, private _fb: FormBuilder) {
effect(() => {
console.log('todos() signal: ', this.todos());
});
}
constructor(private _store: Store, private _fb: FormBuilder) {}

get extras(): FormControl[] {
const extras = this.pizzaForm.get('extras') as FormArray;
Expand Down
5 changes: 3 additions & 2 deletions integration/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { APP_ID, ApplicationConfig } from '@angular/core';
import { APP_ID } from '@angular/core';
import { provideRouter } from '@angular/router';
import { ApplicationConfig } from '@angular/platform-browser';
import { provideStore } from '@ngxs/store';
import { withNgxsFormPlugin } from '@ngxs/form-plugin';
import { withNgxsLoggerPlugin } from '@ngxs/logger-plugin';
Expand Down Expand Up @@ -41,7 +42,7 @@ export const appConfig: ApplicationConfig = {
[TodosState, TodoState],
{ developmentMode: !environment.production, selectorOptions: {} },
withNgxsFormPlugin(),
withNgxsLoggerPlugin({ logger: console, collapsed: false, disabled: false }),
withNgxsLoggerPlugin({ logger: console, collapsed: false, disabled: true }),
withNgxsReduxDevtoolsPlugin({ disabled: environment.production }),
withNgxsRouterPlugin(),
withNgxsStoragePlugin({ key: [TODOS_STORAGE_KEY] })
Expand Down
2 changes: 1 addition & 1 deletion integration/app/counter/counter.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{ counter() | json }}
{{ counter$ | async | json }}
5 changes: 3 additions & 2 deletions integration/app/counter/counter.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Component, OnInit, Signal } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngxs/store';
import { CounterStateChangeAction } from '@integration/counter/counter.actions';
import { CounterState, CounterStateModel } from '@integration/counter/counter.state';
import { Observable } from 'rxjs';

@Component({
selector: 'counter',
templateUrl: './counter.component.html'
})
export class CounterComponent implements OnInit {
counter: Signal<CounterStateModel> = this._store.selectSignal(CounterState);
counter$: Observable<CounterStateModel> = this._store.select(CounterState);

constructor(private _store: Store) {}

Expand Down
2 changes: 1 addition & 1 deletion integration/app/detail/detail.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{ detail() | json }}
{{ detail$ | async | json }}
3 changes: 2 additions & 1 deletion integration/app/detail/detail.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { Store } from '@ngxs/store';
import { Observable } from 'rxjs';

import { DetailState } from '@integration/detail/detail.state';

Expand All @@ -8,7 +9,7 @@ import { DetailState } from '@integration/detail/detail.state';
templateUrl: './detail.component.html'
})
export class DetailComponent {
detail = this._store.selectSignal(DetailState);
detail$: Observable<boolean> = this._store.select(DetailState);

constructor(private _store: Store) {}
}
6 changes: 3 additions & 3 deletions integration/app/list/list.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div>
{{ list() }},
{{ hello() }}
{{ list$ | async }},
{{ hello$ | async }}
</div>

<div *ngIf="router() as router">
<div *ngIf="router$ | async as router">
animals were resolved {{ router.root!.firstChild!.firstChild!.data.list }}
</div>
7 changes: 4 additions & 3 deletions integration/app/list/list.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { Store } from '@ngxs/store';
import { RouterState } from '@ngxs/router-plugin';
import { Observable } from 'rxjs';

import { ListState } from '@integration/list/list.state';

Expand All @@ -9,9 +10,9 @@ import { ListState } from '@integration/list/list.state';
templateUrl: './list.component.html'
})
export class ListComponent {
list = this._store.selectSignal(ListState);
hello = this._store.selectSignal(ListState.getHello);
router = this._store.selectSignal(RouterState.state);
list$: Observable<string[]> = this._store.select(ListState);
hello$ = this._store.select(ListState.getHello);
router$ = this._store.select(RouterState.state);

constructor(private _store: Store) {}
}
8 changes: 1 addition & 7 deletions packages/store/src/internal/state-stream.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Injectable, OnDestroy, Signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { Injectable, OnDestroy } from '@angular/core';

import { PlainObject } from '@ngxs/store/internals';

Expand All @@ -11,11 +10,6 @@ import { OrderedBehaviorSubject } from './custom-rxjs-subjects';
*/
@Injectable({ providedIn: 'root' })
export class StateStream extends OrderedBehaviorSubject<PlainObject> implements OnDestroy {
readonly state: Signal<PlainObject> = toSignal(this, {
manualCleanup: true,
requireSync: true
});

constructor() {
super({});
}
Expand Down
27 changes: 1 addition & 26 deletions packages/store/src/store.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
// tslint:disable:unified-signatures
import {
CreateComputedOptions,
Inject,
Injectable,
Optional,
Signal,
Type,
computed
} from '@angular/core';
import { Inject, Injectable, Optional, Type } from '@angular/core';
import { Observable, of, Subscription, throwError } from 'rxjs';
import { catchError, distinctUntilChanged, map, shareReplay, take } from 'rxjs/operators';
import { INITIAL_STATE_TOKEN, PlainObject } from '@ngxs/store/internals';
Expand Down Expand Up @@ -101,23 +93,6 @@ export class Store {
return selectorFn(this._stateStream.getValue());
}

/**
* Select a signal from the state.
*/
selectSignal<T>(
selector: (state: any, ...states: any[]) => T,
options?: CreateComputedOptions<T>
): Signal<T>;
selectSignal<T = any>(
selector: string | Type<any>,
options?: CreateComputedOptions<T>
): Signal<T>;
selectSignal<T>(selector: StateToken<T>, options?: CreateComputedOptions<T>): Signal<T>;
selectSignal<T>(selector: any, options?: CreateComputedOptions<T>): Signal<T> {
const selectorFn = this.getStoreBoundSelectorFn(selector);
return computed<T>(() => selectorFn(this._stateStream.state()), options);
}

/**
* Allow the user to subscribe to the root of the state
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/store/tests/state-token.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { take } from 'rxjs/operators';
import { Observable } from 'rxjs';

describe('[TEST]: StateToken', () => {
describe('Simple use', function () {
describe('Simple use', function() {
it('should successfully create a simple token', () => {
const TODO_TOKEN = new StateToken<string>('todo');
expect(TODO_TOKEN).toBeInstanceOf(StateToken);
Expand Down

0 comments on commit 3b2b343

Please sign in to comment.