@ethlete/query 4.3.0 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import * as i1 from '@ethlete/core';
2
- import { BehaviorSubjectWithSubscriberCount, getCookie, setCookie, deleteCookie, createDestroy, DelayableDirective, equal, clone } from '@ethlete/core';
3
- import { Observable, filter, takeWhile, switchMap, of, tap, BehaviorSubject, shareReplay, Subject, takeUntil, interval, skip, map, timer, combineLatest, withLatestFrom, fromEvent, startWith, debounceTime, take, concat, distinctUntilChanged, pairwise } from 'rxjs';
2
+ import { BehaviorSubjectWithSubscriberCount, getCookie, setCookie, deleteCookie, createDestroy, DelayableDirective, RouterStateService, clone, equal, ET_PROPERTY_REMOVED } from '@ethlete/core';
3
+ import { Observable, filter, takeWhile, switchMap, of, tap, BehaviorSubject, shareReplay, Subject, takeUntil, interval, skip, map, timer, combineLatest, withLatestFrom, fromEvent, startWith, debounceTime, take, concat } from 'rxjs';
4
4
  import * as i0 from '@angular/core';
5
- import { isDevMode, Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef, assertInInjectionContext } from '@angular/core';
5
+ import { isDevMode, Directive, Input, InjectionToken, inject, ChangeDetectorRef, ViewContainerRef, TemplateRef, ErrorHandler, ElementRef, NgZone, assertInInjectionContext } from '@angular/core';
6
6
  import { FormGroup } from '@angular/forms';
7
7
  import { Router, ActivatedRoute } from '@angular/router';
8
8
 
@@ -1107,8 +1107,9 @@ class BearerAuthProvider {
1107
1107
  * @internal
1108
1108
  */
1109
1109
  _refreshQuery() {
1110
- if (isQueryStateLoading(this._currentRefreshQuery$.getValue()?.rawState)) {
1111
- return;
1110
+ const currentQuery = this._currentRefreshQuery$.getValue();
1111
+ if (isQueryStateLoading(currentQuery?.rawState)) {
1112
+ return currentQuery;
1112
1113
  }
1113
1114
  const currentRefreshToken = this.tokens.refreshToken;
1114
1115
  if (!currentRefreshToken || !this._config.refreshConfig) {
@@ -1243,10 +1244,10 @@ class QueryDirective {
1243
1244
  this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
1244
1245
  }
1245
1246
  }
1246
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1247
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: ["etQuery", "query"], cache: ["etQueryCache", "cache"] }, ngImport: i0 }); }
1247
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: QueryDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: i0.ErrorHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1248
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.1", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: ["etQuery", "query"], cache: ["etQueryCache", "cache"] }, ngImport: i0 }); }
1248
1249
  }
1249
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: QueryDirective, decorators: [{
1250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: QueryDirective, decorators: [{
1250
1251
  type: Directive,
1251
1252
  args: [{
1252
1253
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1572,10 +1573,10 @@ class InfinityQueryDirective {
1572
1573
  this._viewContext.currentQuery = null;
1573
1574
  this._data$.next([]);
1574
1575
  }
1575
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1576
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], exportAs: ["etInfinityQuery"], hostDirectives: [{ directive: i1.DelayableDirective }], ngImport: i0 }); }
1576
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1577
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.1", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], exportAs: ["etInfinityQuery"], hostDirectives: [{ directive: i1.DelayableDirective }], ngImport: i0 }); }
1577
1578
  }
1578
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: InfinityQueryDirective, decorators: [{
1579
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: InfinityQueryDirective, decorators: [{
1579
1580
  type: Directive,
1580
1581
  args: [{
1581
1582
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1626,10 +1627,10 @@ class InfinityQueryTriggerDirective {
1626
1627
  });
1627
1628
  this._observer.observe(this._elementRef.nativeElement);
1628
1629
  }
1629
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1630
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 }); }
1630
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1631
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.1", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 }); }
1631
1632
  }
1632
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1633
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
1633
1634
  type: Directive,
1634
1635
  args: [{
1635
1636
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -1992,6 +1993,14 @@ const buildGqlCacheKey = (config, args) => {
1992
1993
  return `${queryFirst50Chars}...${queryMiddle25Chars}...${queryLast50Chars}...${vars}`;
1993
1994
  };
1994
1995
 
1996
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1997
+ class QueryFormGroup extends FormGroup {
1998
+ patchValue(
1999
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2000
+ value, options) {
2001
+ super.patchValue(value, options);
2002
+ }
2003
+ }
1995
2004
  class QueryField {
1996
2005
  get control() {
1997
2006
  return this.data.control;
@@ -2046,13 +2055,25 @@ class QueryForm {
2046
2055
  this._router = inject(Router);
2047
2056
  this._activatedRoute = inject(ActivatedRoute);
2048
2057
  this._defaultValues = this._extractDefaultValues();
2058
+ this._routerStateService = inject(RouterStateService);
2059
+ this._zone = inject(NgZone);
2049
2060
  this._isObserving = false;
2050
2061
  this.form = this._setupFormGroup();
2062
+ this._lastFormValue$ = new BehaviorSubject(null);
2063
+ this._currentFormValue$ = new BehaviorSubject({
2064
+ id: 0,
2065
+ data: this._formValue,
2066
+ });
2051
2067
  this._changes$ = new BehaviorSubject({
2052
2068
  previousValue: null,
2053
2069
  currentValue: this.form.getRawValue(),
2054
2070
  });
2055
- this.changes$ = this._changes$.asObservable();
2071
+ this.changes$ = this._currentFormValue$.pipe(withLatestFrom(this._lastFormValue$)).pipe(map(([currentValueEvent, previousValueEvent]) => {
2072
+ return {
2073
+ previousValue: previousValueEvent?.data ?? null,
2074
+ currentValue: currentValueEvent.data,
2075
+ };
2076
+ }));
2056
2077
  assertInInjectionContext(QueryForm);
2057
2078
  }
2058
2079
  observe(options) {
@@ -2063,73 +2084,90 @@ class QueryForm {
2063
2084
  return;
2064
2085
  }
2065
2086
  this._isObserving = true;
2066
- this.setFormValueFromUrlQueryParams();
2067
- combineLatest(Object.values(this._fields).map((field) => field.changes$))
2068
- .pipe(takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$), map(() => this._formValue), distinctUntilChanged((a, b) => equal(a, b)), tap((values) => {
2087
+ this.setFormValueFromUrlQueryParams({
2088
+ queryParams: this._routerStateService.queryParams,
2089
+ });
2090
+ this.form.valueChanges
2091
+ .pipe(startWith(null), tap(() => {
2092
+ this._lastFormValue$.next(clone(this._currentFormValue$.value));
2093
+ this._currentFormValue$.next({ id: this._currentFormValue$.value.id + 1, data: clone(this._formValue) });
2094
+ }), takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$))
2095
+ .subscribe();
2096
+ this._currentFormValue$
2097
+ .pipe(tap((currentValueEvent) => {
2098
+ const previousValueEvent = this._lastFormValue$.value;
2099
+ const currentValue = currentValueEvent.data;
2069
2100
  if (options?.writeToQueryParams !== false) {
2070
- this._syncViaUrlQueryParams(values, options?.replaceUrl);
2101
+ this._syncViaUrlQueryParams(currentValueEvent.data, options?.replaceUrl);
2071
2102
  }
2072
- }), pairwise(), startWith([null, this._formValue]), map(([previousValue, currentValue]) => ({ previousValue, currentValue })), tap(({ previousValue, currentValue }) => {
2073
- let didResetValues = false;
2074
- for (const formFieldKey in this._fields) {
2075
- const resets = this._fields[formFieldKey].data.isResetBy;
2076
- if (!resets)
2077
- continue;
2078
- const resetConditionKeys = Array.isArray(resets) ? resets : [resets];
2079
- for (const resetConditionKey of resetConditionKeys) {
2080
- if (!(resetConditionKey in this._fields)) {
2081
- if (isDevMode()) {
2082
- console.warn(`The field "${resetConditionKey}" is not defined in the QueryForm. Is it a typo?`, this);
2083
- }
2084
- continue;
2085
- }
2086
- if (previousValue &&
2087
- currentValue &&
2088
- !equal(previousValue[resetConditionKey], currentValue[resetConditionKey])) {
2089
- const defaultValueForKeyToReset = this._defaultValues[formFieldKey];
2090
- const currentValueForKeyToReset = currentValue[formFieldKey];
2091
- if (equal(defaultValueForKeyToReset, currentValueForKeyToReset)) {
2092
- continue;
2093
- }
2094
- this.form.controls[formFieldKey].setValue(defaultValueForKeyToReset);
2095
- didResetValues = true;
2096
- break;
2097
- }
2098
- }
2103
+ const didResetValues = this._handleQueryFormResets(previousValueEvent?.data ?? null, currentValue);
2104
+ if (didResetValues) {
2105
+ return;
2099
2106
  }
2100
- if (!didResetValues) {
2101
- this._changes$.next({
2102
- previousValue,
2103
- currentValue,
2104
- });
2107
+ if (this._currentFormValue$.value.id !== currentValueEvent.id) {
2108
+ return;
2105
2109
  }
2106
- }))
2110
+ this._changes$.next({
2111
+ previousValue: previousValueEvent?.data ?? null,
2112
+ currentValue: currentValueEvent.data,
2113
+ });
2114
+ }), takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$))
2107
2115
  .subscribe();
2108
2116
  if (options?.syncOnNavigation !== false) {
2109
- this._activatedRoute.queryParams
2110
- .pipe(takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$), tap(() => this.setFormValueFromUrlQueryParams()))
2117
+ this._routerStateService.queryParamChanges$
2118
+ .pipe(takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$), tap((changes) => this.setFormValueFromUrlQueryParams({ queryParams: changes })))
2111
2119
  .subscribe();
2112
2120
  }
2113
2121
  }
2122
+ _handleQueryFormResets(previousValue, currentValue) {
2123
+ let didResetValues = false;
2124
+ for (const formFieldKey in this._fields) {
2125
+ const resets = this._fields[formFieldKey].data.isResetBy;
2126
+ if (!resets)
2127
+ continue;
2128
+ const resetConditionKeys = Array.isArray(resets) ? resets : [resets];
2129
+ for (const resetConditionKey of resetConditionKeys) {
2130
+ if (!(resetConditionKey in this._fields)) {
2131
+ if (isDevMode()) {
2132
+ console.warn(`The field "${resetConditionKey}" is not defined in the QueryForm. Is it a typo?`, this);
2133
+ }
2134
+ continue;
2135
+ }
2136
+ if (previousValue &&
2137
+ currentValue &&
2138
+ !equal(previousValue[resetConditionKey], currentValue[resetConditionKey])) {
2139
+ const defaultValueForKeyToReset = this._defaultValues[formFieldKey];
2140
+ const currentValueForKeyToReset = currentValue[formFieldKey];
2141
+ if (equal(defaultValueForKeyToReset, currentValueForKeyToReset)) {
2142
+ continue;
2143
+ }
2144
+ this.form.controls[formFieldKey].setValue(defaultValueForKeyToReset);
2145
+ didResetValues = true;
2146
+ break;
2147
+ }
2148
+ }
2149
+ }
2150
+ return didResetValues;
2151
+ }
2114
2152
  unobserve() {
2115
2153
  this._unobserveTrigger$.next(true);
2116
2154
  }
2117
2155
  setFormValueFromUrlQueryParams(options) {
2118
- const queryParams = this._activatedRoute.snapshot.queryParams;
2119
2156
  for (const [key, field] of Object.entries(this._fields)) {
2120
- const value = queryParams[key];
2121
- // We only check using == because the value types can be different (e.g. "1" and 1)
2122
- if (value == field.control.value) {
2157
+ const value = options.queryParams[key];
2158
+ const valueDoesNotExist = value === undefined;
2159
+ if (valueDoesNotExist)
2123
2160
  continue;
2124
- }
2125
- else if (value === undefined) {
2126
- // The value might have been removed from the URL query params due to a back navigation or something
2161
+ const valueGotRemoved = value === ET_PROPERTY_REMOVED;
2162
+ if (valueGotRemoved) {
2127
2163
  field.setValue(this._getDefaultValue(key), { skipDebounce: options?.skipDebounce ?? true });
2164
+ continue;
2128
2165
  }
2129
- else {
2130
- const deserializedValue = field.data.queryParamToValueTransformFn?.(value) ?? value;
2131
- field.setValue(deserializedValue, { skipDebounce: options?.skipDebounce ?? true });
2132
- }
2166
+ const deserializedValue = field.data.queryParamToValueTransformFn?.(value) ?? value;
2167
+ const valueIsEqualToCurrent = equal(deserializedValue, field.control.value);
2168
+ if (valueIsEqualToCurrent)
2169
+ continue;
2170
+ field.setValue(deserializedValue, { skipDebounce: options?.skipDebounce ?? true });
2133
2171
  }
2134
2172
  }
2135
2173
  _getDefaultValue(key) {
@@ -2140,7 +2178,7 @@ class QueryForm {
2140
2178
  return this._getDefaultValue(key) === normalizedValue;
2141
2179
  }
2142
2180
  _setupFormGroup() {
2143
- const group = new FormGroup({});
2181
+ const group = new QueryFormGroup({});
2144
2182
  for (const [key, field] of Object.entries(this._fields)) {
2145
2183
  group.addControl(key, field.control);
2146
2184
  }
@@ -2165,6 +2203,10 @@ class QueryForm {
2165
2203
  _syncViaUrlQueryParams(values, replaceUrl) {
2166
2204
  const queryParams = { ...clone(this._activatedRoute.snapshot.queryParams) };
2167
2205
  for (const [key, value] of Object.entries(values)) {
2206
+ if (!this._fields[key]) {
2207
+ console.warn(`The field "${key}" is not defined in the QueryForm. Is it a typo?`, this);
2208
+ continue;
2209
+ }
2168
2210
  if (this._isDefaultValue(key, value) || this._fields[key].data.appendToUrl === false) {
2169
2211
  delete queryParams[key];
2170
2212
  }
@@ -2174,9 +2216,11 @@ class QueryForm {
2174
2216
  : value;
2175
2217
  }
2176
2218
  }
2177
- this._router.navigate([], {
2178
- queryParams,
2179
- replaceUrl,
2219
+ this._zone.run(() => {
2220
+ this._router.navigate([], {
2221
+ queryParams,
2222
+ replaceUrl,
2223
+ });
2180
2224
  });
2181
2225
  }
2182
2226
  }
@@ -2304,5 +2348,5 @@ const def = () => null;
2304
2348
  * Generated bundle index. Do not edit.
2305
2349
  */
2306
2350
 
2307
- export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, EntityStore, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryCreator, QueryDirective, QueryError, QueryField, QueryForm, QueryStore, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryObjectString, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, createInfinityQueryConfig, createQueryCollection, decryptBearer, deepFreeze, def, detectContentTypeHeader, extractExpiresInSeconds, extractQuery, filterFailure, filterInvalidParams, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getResponseUrl, gql, hasHeader, ignoreAutoRefresh, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isGqlQueryConfig, isParamValid, isQuery, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mergeHeaders, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, resetPageOnError, serializeBody, shouldCacheQuery, shouldRetryRequest, skipPaginationPageParamCalculator, switchQueryCollectionState, switchQueryState, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
2351
+ export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, EntityStore, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, Query, QueryClient, QueryCreator, QueryDirective, QueryError, QueryField, QueryForm, QueryFormGroup, QueryStore, buildErrorMessage, buildGqlCacheKey, buildQueryArrayString, buildQueryObjectString, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, createInfinityQueryConfig, createQueryCollection, decryptBearer, deepFreeze, def, detectContentTypeHeader, extractExpiresInSeconds, extractQuery, filterFailure, filterInvalidParams, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getResponseUrl, gql, hasHeader, ignoreAutoRefresh, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isCustomHeaderAuthProvider, isGqlQueryConfig, isParamValid, isQuery, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mergeHeaders, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, pathParamsMissingInRouteFunctionError, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, request, resetPageOnError, serializeBody, shouldCacheQuery, shouldRetryRequest, skipPaginationPageParamCalculator, switchQueryCollectionState, switchQueryState, takeUntilResponse, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
2308
2352
  //# sourceMappingURL=ethlete-query.mjs.map