Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/several fixes #53

Merged
merged 9 commits into from
Apr 19, 2024
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
cache: 'npm'
- run: npm ci --legacy-peer-deps
- run: npm run build
- run: npm test
- run: npm run test-all


publish:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
ReactiveFormsModule,
UntypedFormControl,
UntypedFormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { DepartmentDropdownComponent } from './components/department-dropdown/department-dropdown.component';
import { StoreDropdownComponent } from './components/store-dropdown/store-dropdown.component';
import { MatCardModule } from '@angular/material/card';

import { BranchDropdownComponent } from './components/branch-dropdown/branch-dropdown.component';
import { DepartmentDropdownComponent } from './components/department-dropdown/department-dropdown.component';

@Component({
selector: 'ngrx-traits-cache-and-dropdowns-page',
template: `
<mat-card>
<mat-card-content>
<form [formGroup]="form">
<store-dropdown
<branch-dropdown
style="width: 300px"
formControlName="store"
></store-dropdown>
formControlName="branch"
></branch-dropdown>

<div></div>
<department-dropdown
style="width: 300px"
[storeId]="form.get('store')?.value?.id"
[storeId]="form.get('branch')?.value?.id"
formControlName="department"
></department-dropdown>
</form>
Expand All @@ -35,13 +36,13 @@ import { MatCardModule } from '@angular/material/card';
imports: [
MatCardModule,
ReactiveFormsModule,
StoreDropdownComponent,
BranchDropdownComponent,
DepartmentDropdownComponent,
],
})
export class CacheAndDropdownsPageComponent {
form = new UntypedFormGroup({
store: new UntypedFormControl(),
branch: new UntypedFormControl(),
department: new UntypedFormControl(),
});
}
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
import { AsyncPipe } from '@angular/common';
import {
Component,
OnInit,
ChangeDetectionStrategy,
Component,
Input,
Output,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { ProductsStore } from '../../../models';
import { ProductsStoreLocalTraits } from './store.local-traits';
import { createSelector, Store } from '@ngrx/store';
import { input } from '@angular/core';
import {
ControlValueAccessor,
UntypedFormControl,
NG_VALUE_ACCESSOR,
ReactiveFormsModule,
UntypedFormControl,
} from '@angular/forms';
import { MatOptionModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select';
import { createSelector, Store } from '@ngrx/store';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatOptionModule } from '@angular/material/core';

import { SearchOptionsComponent } from '../../../components/search-options/search-options.component';
import { MatSelectModule } from '@angular/material/select';
import { MatFormFieldModule } from '@angular/material/form-field';
import { AsyncPipe } from '@angular/common';
import { input } from '@angular/core';
import { Branch } from '../../../models';
import { BranchLocalTraits } from './store.local-traits';

@Component({
selector: 'store-dropdown',
selector: 'branch-dropdown',
template: `
@if (data$ | async; as data) {
<mat-form-field
class="container"
floatLabel="always"
>
<mat-label>Store</mat-label>
<mat-form-field class="container" floatLabel="always">
<mat-label>Branch</mat-label>
<mat-select
[formControl]="control"
[placeholder]="data.isLoading ? 'Loading...' : 'Please Select'"
[compareWith]="compareById"
(closed)="search(undefined)"
>
>
<search-options (valueChanges)="search($event)"></search-options>
@for (item of data.stores; track item) {
<mat-option
class="fact-item"
[value]="item"
>
<mat-option class="fact-item" [value]="item">
{{ item.name }}
</mat-option>
}
Expand All @@ -57,7 +52,7 @@ import { input } from '@angular/core';
</mat-select>
</mat-form-field>
}
`,
`,
styles: [
`
:host {
Expand All @@ -70,10 +65,10 @@ import { input } from '@angular/core';
],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
ProductsStoreLocalTraits,
BranchLocalTraits,
{
provide: NG_VALUE_ACCESSOR,
useExisting: StoreDropdownComponent,
useExisting: BranchDropdownComponent,
multi: true,
},
],
Expand All @@ -85,36 +80,38 @@ import { input } from '@angular/core';
SearchOptionsComponent,
MatOptionModule,
MatProgressSpinnerModule,
AsyncPipe
],
AsyncPipe,
],
})
export class StoreDropdownComponent
export class BranchDropdownComponent
implements OnInit, ControlValueAccessor, OnDestroy
{
control = new UntypedFormControl();
data$ = this.store.select(
createSelector(
this.traits.localSelectors.isStoresLoading,
this.traits.localSelectors.selectStoresList,
(isLoading, stores) => ({ isLoading, stores })
)
this.traits.localSelectors.isBranchesLoading,
this.traits.localSelectors.selectBranchesList,
(isLoading, stores) => ({ isLoading, stores }),
),
);
private onTouch: any;
destroy = new Subject<void>();

@Input() set value(value: ProductsStore) {
@Input() set value(value: Branch) {
this.control.setValue(value);
}
@Output() valueChanges = this.control
.valueChanges as Observable<ProductsStore>;
@Output() valueChanges = this.control.valueChanges as Observable<Branch>;

constructor(private store: Store, private traits: ProductsStoreLocalTraits) {}
constructor(
private store: Store,
private traits: BranchLocalTraits,
) {}

ngOnInit(): void {
this.store.dispatch(this.traits.localActions.loadStores());
this.store.dispatch(this.traits.localActions.loadBranches());
}

writeValue(value: ProductsStore): void {
writeValue(value: Branch): void {
this.control.setValue(value);
}

Expand All @@ -132,12 +129,12 @@ export class StoreDropdownComponent
this.destroy.next();
this.destroy.complete();
}
compareById(value: ProductsStore, option: ProductsStore) {
compareById(value: Branch, option: Branch) {
return value && option && value.id == option.id;
}
search(text: string | undefined) {
this.store.dispatch(
this.traits.localActions.filterStores({ filters: { search: text } })
this.traits.localActions.filterBranches({ filters: { search: text } }),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { Injectable } from '@angular/core';
import {
addFilterEntitiesTrait,
addLoadEntitiesTrait,
} from '@ngrx-traits/common';
import {
cache,
createEntityFeatureFactory,
LocalTraitsConfig,
TraitsLocalStore,
} from '@ngrx-traits/core';
import {
addFilterEntitiesTrait,
addLoadEntitiesTrait,
} from '@ngrx-traits/common';
import { ProductsStore, ProductsStoreFilter } from '../../../models';
import { Injectable } from '@angular/core';
import { ProductsStoreService } from '../../../services/products-store.service';
import { catchError, exhaustMap, map } from 'rxjs/operators';
import { createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, exhaustMap, map } from 'rxjs/operators';

import { Branch, BranchFilter } from '../../../models';
import { BranchService } from '../../../services/branch.service';

export const storeCacheKeys = {
all: ['stores'],
Expand All @@ -22,9 +23,9 @@ export const storeCacheKeys = {
};

const storeFeatureFactory = createEntityFeatureFactory(
{ entityName: 'store' },
addLoadEntitiesTrait<ProductsStore>(),
addFilterEntitiesTrait<ProductsStore, ProductsStoreFilter>({
{ entityName: 'branch', entitiesName: 'branches' },
addLoadEntitiesTrait<Branch>(),
addFilterEntitiesTrait<Branch, BranchFilter>({
filterFn: (filter, entity) => {
const searchString = filter?.search?.toLowerCase?.();
return (
Expand All @@ -33,32 +34,34 @@ const storeFeatureFactory = createEntityFeatureFactory(
entity.address.toLowerCase().includes(searchString)
);
},
})
}),
);

@Injectable()
export class ProductsStoreLocalTraits extends TraitsLocalStore<
export class BranchLocalTraits extends TraitsLocalStore<
typeof storeFeatureFactory
> {
constructor(private storeService: ProductsStoreService) {
constructor(private storeService: BranchService) {
super();
this.traits.addEffects(this);
}

loadStores$ = createEffect(() => {
loadBranches$ = createEffect(() => {
return this.actions$.pipe(
ofType(this.localActions.loadStores),
ofType(this.localActions.loadBranches),
exhaustMap(() =>
cache({
key: storeCacheKeys.list(),
store: this.store,
source: this.storeService.getStores(),
source: this.storeService.getBranches(),
// no expire param so is stored forever
}).pipe(
map((res) => this.localActions.loadStoresSuccess({ entities: res })),
catchError(() => of(this.localActions.loadStoresFail()))
)
)
map((res) =>
this.localActions.loadBranchesSuccess({ entities: res.resultList }),
),
catchError(() => of(this.localActions.loadBranchesFail())),
),
),
);
});

Expand Down
Loading
Loading