StatefulEvt<T>

A StatefulEvt is an Evt stat keep a reference to the last value posted.

You can think of it as way to observe when a value is changed.

When you attach to a StatefulEvt the callback is immediately called with the current value (except with attachExtract and attachOnceExtract).

.state

Property type: T

reading the property gives the last event data posted. Setting the property (evt.state = data) is equivalent to calling .post(data).

import { Evt } from "evt";

const evtCount = Evt.create(0); // Equivalent wit new StatefulEvt<number>(0)

evtCount.attach(console.log);

console.log(evtCount.state); //Pints "state: 0"

evtIsConnected.post(1); //Pints "1" 

console.log(evtCount.state); //Prints "1";

evtCount.state++; //Prints "2"

console.log(evtCount.state); //Pints "2";

.pipe(...)

Same as evt.pipe(...) but return a StatefulEvt. Be aware that the current state of the StatefulEvt must be matched by the operator ( if any ) when invoking .pipe(), elst an exception will be thrown.

import { Evt } from "evt";

type Circle = { 
    color: "WHITE" | "RED";
    radius: number;
};

const evtSelectedCircle = Evt.create<Circle>({ "color": "RED", "radius": 3 });

const evtSelectedCricleColor = 
    evtSelectedCircle.pipe(circle=> [ cicle.color ]);

evtSelectedCircleColor.attach(console.log);

Converting an Evt into a StatefulEvt

Basic example:

import { Evt } from "evt";

const evtSrc = Evt.create<string>();

const evtFoo = evtSrc.toStatefull("initial value");

console.log(evtFoo.state === "initial value");

evtStr.post("new value");

console.log(evtFoo.state === "new value");

Concrete example:

import { Evt } from "evt";

// Evt that post whenever the window is resized window.addEventListener("resize", ...)
const evtResize = Evt.from(window, "resize");

// A statefulle evt with evtInnerWith state which is always the current value of
// window.innerSize.
const evtInnerWidth = evtResize
    .toStatefull() // convert into a statefull evt with initial value set to unefined
    .pipe(()=> [window.innerWidth]);

onlyIfChanged operator

When using stetefull Evt is often usefull to have event posted only when the state value has changed. For that purpose you can pipe with the onlyIfChanged operator.

Concrete example:

If we take the previous example:

import { Evt } from "evt";


const evtInnerWidth = Evt.from(window, "resize")
    .toStatefull() 
    .pipe(()=> [window.innerWidth]);
    
evtInnerWith.attach(innerWidth => {

    // This callback will be called whenever the screen is resized 
    // including if only if the height has changed because
    // window.addEventListener("resize", ()=> ... 
    // is the source event emitter.  

});

Now if we put the onlyIfChanged operator intor the mix:

import { Evt, onlyIfChanged } from "evt";

const evtInnerWidth = Evt.from(window, "resize")
    .toStatefull() 
    .pipe(()=> [window.innerWidth])
    // By default it compare object structure so { foo: 3 } is considered equal to 
    // an other object that would also be { foo: 3 }
    .pipe(onlyIfChanged());
    
evtInnerWith.attach(innerWidth => {

    // This callback will only be called whenever window.innerWidth
    // actually changes.  

});

Merging multiple StatefulEvts

import { Evt } from "evt";

const evtIsBlue= Evt.create(false);
const evtIsBig= Evt.create(false);

const evtIsBigAndBlue = Evt.merge([
    evtIsBlue.evtChange,
    evtIsBig.evtChange
])
    .toStateful()
    .pipe(()=> [ evtIsBlue.state && evtIsBig.state ])
    ;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBlue.state= true;

console.log(evtIsBigAndBlue.state); // Prints "false"

evtIsBig.state= true;

console.log(evtIsBigAndBlue.state); // Prints "true"

****Run the example****

Make a StatefulEvt readonly

To prevent a StatefulEvt to be posted by parts of the code that is not supposed to StatefulEvt can be exposed as StatefulReadonlyEvt.

import { StatefulEvt, StatefulReadonlyEvt } from "evt";

//Return an event that post every second.
function generateEvtTick(delay: number): StatefulReadonlyEvt<number> {

    const evtTick= new StatefulEvt(0);

    setInterval(()=> evtTick.state++, delay);

    retrun evtTick;

}

const evtTick= generateTick(1000);


evtTick.state++; // TS ERROR
evtTick.post(2); // TS ERROR

.toStateless([ctx])

Return a stateless copy of the Evt.

import { Evt } from "evt";

const evtText= Evt.create("foo");

//x is Evt<string>
const x= evtText.toStateless();

evt.toStateless() is equivalent to Evt.prototype.pipe.call(evt)

Last updated