RxJS proper way of Creating Behavior Subjects from other Behavior Subjects? - angularjs

So I'm using an observable values in an angular application, and I want to make several behavior subjects derived from other behavior subject. I was transforming my behavior subjects with the .map() operator, but found out that I could not reference .value. I wanted to be able to reference the current value as was emitted last (so passed through the mapping function). A little digging around with the output of foo.map() I found I could get the functionality I wanted with:
let foo = /* some BehaviourSubject */
let bar = foo.map((x) => x / 2)
bar.operator.project(bar.destination.value) // to get the value as last emitted
But thats not very nice looking
Currently I'm doing something that looks like this to get the functionality i want:
foo = /* some observable*/
bar = foo.map((x) => x / 2).toBehaviorSubject()
foobar = bar.map((y) => y > 10).toBehaviorSubject()
toBehaviorSubject() is a function I've defined as the following
rx.Observable.prototype.toBehaviorSubject = function (initialValue) {
initialValue = initialValue || null
let subject$ = new rx.BehaviorSubject(initialValue)
this.subscribe((value) => { subject$.next(value) })
return subject$
}
I had earlier toyed with this as a solution, but opted for what I've shown above:
foo = /* some BehaviourSubject */
bar = new rx.BehaviorSubject( foo.value / 2))
foo.subscribe( (x) => {
bar.next(x / 2)
})
foobar = new rx.BehaviorSubject(bar.value > 10)
bar.subscribe( (y) => {
foobar.next(y > 10)
})
These work and all, but I have to ask, is there a standard convention for something that works like the above two examples?
Edit-------------------
Some added context might be helpful.
so I have a BehaviorSubject auth.User$ that is sourced from a service I wrote for window.localstorage access which hands out BehaviorSubjects on its localStorage.get(key) function. I wrote this wrapper to deal with the fact that the localStorage change event fires on all tabs except the tab that changed the value.
Some parts of my application need to know whether the user has been initialized, or if the user is an anonymous user (some portlets can be accessed without logging in) or authenticated (for those which require the user to be logged in), and when these statuses change. In order to avoid duplicating the logic for producing the boolean values for isInitialized, isAnonymous, and isAuthenticated, I wanted to derive more BehaviorSubjects from auth.User$. I want them to be BehaviorSubjects specifically because some of the parts of the application only need the values on an on-call basis, and so being able to reference auth.isAuthenticated$.value is preferable to subscribing to that observable.
I used the Observable.map() function because I wanted to have observable values that fire when auth.user$ does and which transform the emitted values from it, but would like it to still be a BehavorSubject as mentioned above.
So my question is essentially: is there a standard convention for applying a transformation/mapping function to a BehaviorSubject and still get a BehaviorSubject?

I am not sure I understand your question, but basically a behaviour subject always has a value, so you can query the subject from that value at any point of time. I believe in Rxjs v5, getValue is the relevant method.
When you do let foo = /* some BehaviourSubject */ let bar = foo.map((x) => x / 2), then bar is not a subject anymore, it is an observable, i.e. a producer of a stream of values. You need to subscribe to bar to start that producer and actually get a value. Your API seems to do just that. A shorter way is to do bar.subscribe(anotherBehaviourSubject).
Now, do you really need to start the producer so early? i.e. do you actually need a behaviour subject in the first place? If you do, then of course go ahead.

Related

Understanding react function notation

Learning react here. Can someone walk me through how to interpret the function below:
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
As far as I understand it, this is the same as calling:
onElementsRemove(setElements(elementsToRemove(els))?
Is that correct? Is there a benefit to the first notation? Perhaps I am biased coming from the python side of the world but the second one feels more compact? Can someone help me undrstand the reasoning? Thanks!
No, those are not the same. Let's start with the inner part, which needs to be the way it is:
setElements((els) => removeElements(elementsToRemove, els))
When setting state in react, there are two options. You can either directly pass in what you want the new state to be, or you can pass in a function. If you pass in a function, then react will look up what the latest value of the state is, and call your function. Then you return what the new state will be.
So the purpose of doing it this way is to find out what the latest value in the state is. There isn't another way to do this.
Next, the outer part, which has more flexibility:
const onElementsRemove = (elementsToRemove) => /* the stuff we looked at earlier */
This is defining a function called onElementsRemove. From the name, i assume that this is going to be called at some arbitrary point of time in the future. So it's just defining the functionality, and later on you can call it, once you know which elements you want to remove. It will then turn around and set the state. For example, you would do:
onElementsRemove([1, 2, 3]); // i don't actually know what will be in the array
Maybe having this outer function is useful, maybe not. If you're having to do this fairly often it could make sense. In other cases, maybe you could directly call setElements, as in:
setElements((els) => removeElements([1, 2, 3], els));

What is the purpose of next('r') in the context of an RxJS Subject

I'm still fairly new to the RxJS world (please pardon my semantics), but I've seen a few examples of code that creates a Subject to do some work, and then calls next(0), or next('r') on the subscription. It appears to re-run the stream, or rather fetch the next value from the stream.
However, when I tried using this to call an API for some data, it completely skips over the work it's supposed to do as defined in the stream (assuming it would "run" the stream again and get new data from the server), and instead my subscriber gets the 'r' or zero value back when I try to call next like that.
I get that making the subscription "starts execution of the stream", so to speak, but if I want to "re-run" it, I have to unsubscribe, and resubscribe each time.
Is it a convention of some kind to call next with a seemingly redundant value? Am I just using it in the wrong way, or is there a good use-case for calling next like that? I'm sure there's something fundamental that I'm missing, or my understanding of how this works is very wrong.
It's a good question, I definitely recommend you to read about hot and cold Observables.
cold Observables execute each time someone subscribes to it.
const a$ = of(5).pipe(tap(console.log))
a$.subscribe(); // the 'tap' will be executed here
a$.subscribe(); // and here, again.
hot Observables do not care about subscriptions in terms of execution:
const a$ = of(5).pipe(
tap(console.log),
shareReplay(1)
);
a$.subscribe(); // the 'tap' will be executed here
a$.subscribe(); // but not here! console.logs only once
In your example you are using Subject that represents cold Observable.
You can try to use BehaviorSubject or ReplaySubject - both of them are hot but be aware that they behave differently.
IN you example you can modify your Subject like the following:
const mySubject = new Subject();
const myStream$ = mySubject.pipe(
shareReplay(1)
);
myStream$.subscribe(x => console.log(x))
mySubject.next(1);
mySubject.next(2);
mySubject.next(3);

How best to store a number in google realtime model, and get atomic change events?

Sounds pretty simple, however...
This number holds an enumerated type, and should be a field within a custom realtime object. Here's its declaration in the custom object registration routine:
MyRTObjectType.prototype.myEnumeratedType =
gapi.drive.realtime.custom.collaborativeField('myEnumeratedType');
I can store it in the model as a simple javascript number, and initialize it like this:
function initializeMyRTObjectType() {
// other fields here
this.myEnumeratedType = 0;
}
...but the following doesn't work, of course, since it's just a number:
myRTObject.myEnumeratedType.addEventListener(
gapi.drive.realtime.EventType.OBJECT_CHANGED, self.onTypeChanged);
I can add the event listener to the whole object:
myRTObject.addEventListener(
gapi.drive.realtime.EventType.OBJECT_CHANGED, self.onTypeChanged);
But I'm only interested in changes to that number (and if I were interested in other changes, I wouldn't want to examine every field to see what's changed).
So let's say I store it as a realtime string, initializing it like this:
function initializeMyRTObjectType() {
var model = gapi.drive.realtime.custom.getModel(this);
// other fields here
this.myEnumeratedType = model.createString();
}
Now I'll get my change events, but they won't necessarily be atomic, and I can't know whether a change, say from "100" to "1001", is merely a change enroute to "101", and so whether I should react to it (this exact example may not be valid, but the idea is there...)
So the question is, is there either a way to know that all (compounded?) changes, insertions/deletions are complete on a string field, or (better) a different recommended way to store a number, and get atomic notification when it has been changed?
You also get a VALUE_CHANGED event on the containing object like you would for a map:
myRTObject.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED,
function(event) {
if (event.property === 'myEnumeratedType') {
// business logic
}
});

Programmatically composing a chain

I would like to be able to programmatically compose a chain, for later inclusion in another chain. I know it can't be that hard, but I seem to be missing something.
In theory, I should be able to do something like this:
var c = ??? // the part I can't figure out
List( 1, 2, 3 ).foreach {
c.exec( http("Fetch something").get("..." + _ ) )
}
That is, I expect to be able to create a chain, then populate that chain in a loop, rather than hard-coding the chain in the source code.
My biggest struggle, I think, is knowing what to assign to c. I had assumed that it should be
var c = new ChainBuilder()
but according to the documentation I have to pass it a list of actionBuilders and the next action, implying that it is not possible to build an empty chain and then build on it in a separate statement.
Is there any way to make my .foreach loop work the way I intend it to work?
The answer is
import bootstrap._
and then
var c = bootstrap
But then the loop must be modified, like so:
List( 1, 2, 3 ).foreach( x => {
c = c.exec( ... )
})
The reason has to do with the fact that you have to do what chaining does. When you have
foo()
.bar()
.blip()
The result of the whole expression is the return value from blip and not foo - which is obvious when you think about it - so the variable that we are attaching to has to move as nodes are attached.
I hope someone, somewhere, besides me, finds value in seeing this example.

Define component list dynamically for Sidekick and Insert dialog in CQ5

I am trying to modify the list of components displayed in the sidekick based on the user's privileges.
I am trying it as explained here.
What i would like to know is how to send back the modified allowed array that is received as the argument, because what ever modifications i make to the array appears to be in the local scope. For e.g. if i want the allowed components to consist only of the default list component, i do something like this.
function MyHandler(cell, allowed, componentList) {
allowed = [];
allowed.push("/libs/foundation/components/list");
}
But once the control goes back to the function that triggered this event, these changes are not visible. Should i be returning the array or something ? Could you please explain if i am missing something here?
Ok. Finally figured the issue. I wanted to clear the existing list of components that were passed on to my handler, for which I used allowed = [];.
This removed all the existing references to the allowed array. (More about this explained here).
Thus changing it to allowed.length = 0; works absolutely fine.
function MyHandler(cell, allowed, componentList) {
allowed.length = 0;
allowed.push("/libs/foundation/components/list");
}

Resources