@kluntje/services
Collection of useful services, when creating web-components.
Install
npm install @kuntje/services
Usage
ViewportObserver
IntersectionObserver instance, that fires "kl-in-vp"-event when Component enters Viewport and "kl-out-vp"-event when it leaves the Viewport
import { ViewportObserver } from "@kluntje/services";
class MyAmazingComponent extends Component {
viewportObserver = ViewportObserver.getInstance();
afterComponentRender(): void {
this.viewportObserver.observe(this);
}
}
MediaQueryService
Service, that fires "kl-mq-change"-events on window, when mq-change occurs.
import { MediaQueryService } from "@kluntje/services";
const myMQs = [
{
name: 'MQ2',
query: '(min-width: 769px)'
},
{
name: 'MQ1',
query: '(min-width: 0px)'
}
];
MediaQueryService.getInstance(myMQs);
URLSearchParamsService
Service, that gets and sets URLSearchParams.
import { URLSearchParamsService } from "@kluntje/services";
const queryParam = URLSearchParamsService.get("query");
URLSearchParamsService.set("query", "newValue");
URLSearchParamsService.delete("filter");
const filters: string[] | null = URLSearchParamsService.getAll("filter");
DebuggerService
Service to log messages to the console depending on js-debug query-param.
import { DebuggerService } from "@kluntje/services";
DebuggerService.log("Hello World");
DebuggerService.warn("Warning");
DebuggerService.error("Error");
When using in Jest unit tests, make sure using jest.mock
to properly mock the imported module.
import { DebuggerService } from "@kluntje/services";
jest.mock("@kluntje/services");
spyOn(DebuggerService, "error");
LazyConnectService
Service to trigger callback, when component is in viewport.
import { LazyConnectService } from "@kluntje/services";
LazyConnectService.subscribe(this, () => this.doSomething());
I18nService
A service to provide sync/async way to provide internationalization values.
With i18n values being able to have variable placeholder in them. indexed for arrays e.g. {0}
or named for objects e.g. {hour}
.
Usage:
import module and get the singleton instance:
import { I18nService } from '@kluntje/services';
const i18nService = I18nService.getInstance();
set up via url for the ajax endpoint returning the dictionary
i18nService.setUp({ url: 'path/to/i18n/ajax/service' });
or provide the dictionary
i18nService.setUp({
dictionary: {
'com.page.filter.notifications': '{0} Nachrichten',
}
});
using the get
method to render i18n values:
const i18n = i18nService.get;
render(
html`<button>${
i18n('com.page.filter.notifications', {
fallback: "Info",
interpolations: [7]
})}
</button>`, el);
If the dictionary hasn't been fetched yet a placeholder element will be returned <span class="kl-i18n-placeholder">{fallback}</span>
with the provided fallback
text, or the last part of the key. This placeholder will be replaced in den DOM with the i18n value as soon as the dictionary is fetched.
Signature of the get method: I18nService.getInstance().get(i18nKey, options)
[options.fallback]
{string}
: text to be rendered when the dictionary hasn't been loaded. if not provided, the last part of the key (after the last .
will be used.)
[options.interpolations]
{Array|Object}
: a list of items to be put in the placeholders in the i18n value.
I18nService.getInstance().setUp({dictionary: {'duration': '{hour} Stunden und {minutes} Minuten.'}})
console.log(I18nService.getInstance().get('duration', { interpolations: { hour: '10', minutes: '15' } }))
If any action needs the keys to be ready and shouldn't be replaced later in the DOM, the ready
accessor can be called. This will automatically trigger the fetch for the keys from the server (if not done already)
await i18nService.ready;
localStorage.setItem('welcomeText', i18nService.get('com.page.filter.salutation', {interpolations: userInfo}));
The boolean loaded
can be used to check if the keys have been fetched form the server. This will not trigger the fetch.
return i18nService.loaded ? textMarkup : iconMarkup;
StorageService
Service to store and retrieve data from localStorage or sessionStorage.
import { StorageService } from "@kluntje/services";
StorageService.addItem("my-storage-key", "my-storage-value");
StorageService.observeItem("my-storage-key", () => console.log("my-storage-key has changed"));
StorageService.removeItem("my-storage-key");
Options
storageType (optional)
: "local" | "session"
(default: "local") - defines the storage to use
Advanced Usage
It is certainly possible to extend the StorageServiceImpl
class and override the methods to customize the behavior or implement a fully custom caching service that implements the IStorageService
interface.
CachingService
Service to cache data using the StorageService or in-memory.
import { CachingService } from "@kluntje/services";
CachingService.cacheValue("my-cache-key", "my-cache-value", {
validFor: 1000 * 60 * 60,
storageType: "local",
});
const cachedValue = CachingService.getCachedValue("my-cache-key", {
storageType: "local",
});
CachingService.clearCachedValue("my-cache-key", {
storageType: "local",
});
Options
validFor
: number
- defines the time in milliseconds the value is valid
storageTypestorageType (optional)
: "local" | "session"
(default: "local") - defines the storage to use
Advanced Usage
It is possible to customize the caching service by initializing the service with a custom StorageService implementation and/or a custom storageKeyPrefix.
import { CachingServiceImpl } from "@kluntje/services";
import { CustomStorageService } from "./CustomStorageService";
export default new CachingServiceImpl({
storageService: CustomStorageService,
storageKeyPrefix: "my-custom-prefix",
});
Further, it is certainly possible to extend the CachingServiceImpl
class and override the methods to customize the behavior or implement a fully custom caching service that implements the ICachingService
interface.
RequestCachingService
Service to cache requests using the caches-api.
import { RequestCachingService } from "@kluntje/services";
const response = await fetch(url);
await RequestCachingService.cacheRequest({
request: new Request(url),
response,
storage: "local",
maxAge: 1000 * 60 * 60,
});
const cachedResponse = await RequestCachingService.getCachedResponse(new Request(url), {
storage: "local",
});
Options
request
: Request
- the request to cacheresponse
: Response
- the response to cachestorage
: "local" | "session"
- defines the storage to usemaxAge
: number
- defines the time in milliseconds the value is valid
Advanced Usage
It is possible to customize the request caching service by initializing the service with:
- a custom StorageService implementation (optional)
- a custom storageKeyPrefix (optional)
- a custom requestCacheName (optional)
import { RequestCachingServiceImpl } from "@kluntje/services";
import { CustomStorageService } from "./CustomStorageService";
export default new RequestCachingServiceImpl({
storageService: CustomStorageService,
storageKeyPrefix: "my-custom-prefix",
requestCacheName: "my-custom-request-cache",
});
Further, it is certainly possible to extend the RequestCachingServiceImpl
class and override the methods to customize the behavior or implement a fully custom caching service that implements the IRequestCachingService
interface.
APIService
Service to handle API requests.
import { APIService } from "@kluntje/services";
const responseJSON = await APIService.fetchJSON("https://api.example.com/data");
const responseHTML = await APIService.fetchHTML("https://example.com");
Options
fetchOptions
: RequestInit
- options for the fetch requestcacheOptions
:
- all options from
CachingService
forceRefetch
: boolean
(default: false
) - defines if the request should be refetched even if it is cachedrequestBasedCaching
: boolean
(default: false
) - defines if the caching should be request-based or notcacheKeys
: string[]
- list of keys to add to the cache key (default: []
) - useful for post-requests since the cache key is generated from the request url
throwError
: boolean
(default: false
) - defines if the service should throw an Errors
Advanced Usage
It is possible to customize the api service by initializing the service with:
- a custom CachingService implementation (optional)
- a custom RequestCachingService implementation (optional)
import { APIServiceImpl } from "@kluntje/services";
import { CustomCachingService } from "./CustomCachingService";
import { CustomRequestCachingService } from "./CustomRequestCachingService";
export default new APIServiceImpl({
cachingService: CustomCachingService,
requestCachingService: CustomRequestCachingService,
});
Further, it is certainly possible to extend the APIServiceImpl
class and override the methods to customize the behavior or implement a fully custom caching service that implements the IAPIService
interface.
AbortableRequestService
Wrapper for APIService to handle abortable requests.
import { AbortableRequestService } from "@kluntje/services";
const abortableRequestService = new AbortableRequestService();
const abortableRequest1 = abortableRequestService.fetchJSON("https://api.example.com/data?value=1");
const abortableRequest2 = abortableRequestService.fetchJSON("https://api.example.com/data?value=2");
Options
url
: string
- the url to fetchoptions
: APIService options
ObserverService
Message bus to observe and notify events.
import { ObserverService } from "@kluntje/services";
observerService.observe("my-event", (data) => console.log(data));
observerService.notify("my-event", "Hello World");
Advanced Usage
It is certainly possible to extend the ObserverServiceImpl
class and override the methods to customize the behavior or implement a fully custom caching service that implements the IObserverService
interface.
ContextStateService
Service to create and consume context states. A ContextState is a state that belongs to a DOM-Element. All children of this element can access the state.
Create a ContextState
import { ContextStateService } from "@kluntje/services";
const contextState = ContextStateService.createContextState("my-context-state", this);
Set a value
const contextState = await ContextStateService.getContextState("my-context-state", this);
contextState.setState("myStateItem", "myStateValue");
Get a value
const contextState = await ContextStateService.getContextState("my-context-state", this);
const stateValue = contextState.getState<string>("myStateItem");
Observer a state change
const contextState = await ContextStateService.getContextState("my-context-state", this);
contextState.observeState("myStateItem", () => console.log("myStateItem has changed"));