# A practical example for rx-js-light So, we've seen many things about Observable. Now, it's time to practice. Let's imagine a simple application where we have a `` and `` elements into the body. ```ts const selectElement = createLocaleSelectElement(); document.body.appendChild(selectElement); const outputElement = document.createElement('output'); document.body.appendChild(outputElement); ``` And finally, we create a function that accepts a *locale* and a *date*, and returns the formatted date and time as a string: ```ts function formatDate( locale: string, date: number | Date, ): string { return new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', }).format(date); } ``` Until there, no surprise, it's simple javascript. #### Classic code Ok, let's start to implement the expected workflow with a classic approach: ```ts function classic() { let locale: string = selectElement.value; let date: number = Date.now(); const getOutputValue = (): string => { return formatDate(locale, date); }; const refresh = () => { outputElement.value = getOutputValue(); }; const onSelectElementChange = () => { locale = selectElement.value; refresh(); }; selectElement.addEventListener('change', onSelectElementChange); const timer = setInterval(() => { date = Date.now(); refresh(); }, 1000); refresh(); return () => { selectElement.removeEventListener('change', onSelectElementChange); clearInterval(timer); }; } ```
commented ```ts function classic() { /* VARIABLES */ // we create 2 variables that will store the selected locale and the current date let locale: string = selectElement.value; let date: number = Date.now(); /* SHARED FUNCTIONS */ // formats the date and time const getOutputValue = (): string => { return formatDate(locale, date); }; // updates the element const refresh = () => { outputElement.value = getOutputValue(); }; /* SELECT */ // when the selectElement.addEventListener('change', onSelectElementChange); /* DATE */ // every second const timer = setInterval(() => { // we update the date date = Date.now(); // and we refresh the refresh(); }, 1000); // call refresh to immediately display the current date refresh(); // CLEAN function, to release resources return () => { selectElement.removeEventListener('change', onSelectElementChange); clearInterval(timer); }; } ```
[Click here to see the live demo](https://stackblitz.com/edit/typescript-ttzwzn?file=index.ts) As you may see it's pretty simple. However, we may quickly anticipate some limits: - in the real world, we have more than 2 variables, usually in the range of thousands and more, so keeping a coherent state (refreshing + updating the variables) is tricky, and bugs will appear soon. - releasing resources (removeEventListener, clearInterval), can easily be forgotten, creating memory leaks. For long-running application this is not optimal. #### Using observables Here is the same workflow coded with Observables: ```ts function observables() { return function$$( // #3 [ map$$(fromEventTarget(selectElement, 'change'), () => selectElement.value), // #1 -> #1.1 map$$(interval(1000), () => Date.now()), // #2 -> #2.2 ], formatDate, )((value: string) => { outputElement.value = value; }); } ``` [Click here to see the live demo](https://stackblitz.com/edit/typescript-fdrebf?file=index.ts) I guess you noticed how compact is it in comparison to the *classic* example. That's where Reactive Programing shines: asynchronous event streams, and operations on them. Ok, now let's decompose the code. --- ```ts const selectElementChange$ = fromEventTarget(selectElement, 'change'); ``` This creates an Observable that listen for the `change` Event on the ``. So it's an Observable that emits the locale selected by the user. ![alt text](./example-01-1-1.png "schema") However, because `selectElementChange$` only triggers when a *change* occurs, we will use the previous code in conjunction with `merge`, to dispatch the current `