Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new BehaviorSubject().filter(...).getValue() not working? #2378

Closed
gnimmelf opened this issue Feb 16, 2017 · 12 comments
Closed

new BehaviorSubject().filter(...).getValue() not working? #2378

gnimmelf opened this issue Feb 16, 2017 · 12 comments

Comments

@gnimmelf
Copy link

RxJS version: 5.1.1 on Node v7.5.0

Code to reproduce:

const s2 = new Rx.BehaviorSubject()
  .filter((x) => parseInt(x))
  .distinctUntilChanged()
  .do(x => log('b:', x))

s2.next(1)
s2.subscribe((x) => {
  console.log(s2.value, s2.getValue)
})

Expected behavior:
console.log(s2.value, s2.getValue) should print 1, [Function]

Actual behavior:
console.log(s2.value, s2.getValue) prints undefined, undefined

Additional information:
Running this through babel-preset-es2015-node6.

This works however:

const s2 = new Rx.BehaviorSubject()
s2.next(1)
s2.subscribe((x) => {
  console.log(s2.value, s2.getValue)
})

so problem might be my understanding of how this is supposed to work. I'm learning.

Cheers!

@kwonoj
Copy link
Member

kwonoj commented Feb 17, 2017

I don't think it's filter operator specific, it happens anytime as soon as chain operator after behaviorSubject.

I'd assume it's known expected, via lift always create new observable each operator chain and does not deliver characteristics of original if it's extended observable type. This is actually problematic when it comes to custom observable extending Observable<T>.. and since subjects are extending observable as well, you can observe same behavior.

For discussions of extending observable in general, you can refer #1876 / #1829 .

@trxcllnt
Copy link
Member

we could implement getValue() all the way through the Subject chain (which would be my preference), but I've been outnumbered on Subject composition strategies before ^_^, which is likely why it's not there today

@gnimmelf
Copy link
Author

@kwonoj yes, filter was just the example operator, I'm not quite into the terminology yet. I'll look at the links for extending, thanks.

@trxcllnt as a newbie I cannot make specific suggestions as to how this matches the FRP paradigm, but I can say that my greatest frustration so far is how streams change by applying operators; what I get back at the end is often not what I expect. Then it's either a bug or a feature, which takes time to figure out (due to fragmented documentation, but that's another issue).

@gnimmelf
Copy link
Author

gnimmelf commented Feb 22, 2017

Ok, I need to reopen this one due to this:

const nextPageToken$ = new Rx.BehaviorSubject()
  .startWith('')
  .filter(x => x || x == '')

console.log(log("nextPageToken$.next", nextPageToken$.next)   

which prints

nextPageToken$.next undefined

The bare subject behaves

const nextPageToken$ = new Rx.BehaviorSubject()
console.log(log("nextPageToken$.next", nextPageToken$.next)   

and of course prints

nextPageToken$.next function (value) {
        _super.prototype.next.call(this, this._value = value);
    }

I think either you have to explicitly add a recipe for handling these extremely normal cases very early in the documentation (@kwonoj's links above is way above my level, and beyond my interest), or you have to take a hint from @trxcllnt.

Edit: I'm having some really strange inconsistencies in my code here, so the problem might be me...

@gnimmelf gnimmelf reopened this Feb 22, 2017
@paulpdaniels
Copy link
Contributor

paulpdaniels commented Feb 22, 2017

Why can't you just save the reference to the original Subject?

const subject$ = new Rx.BehaviorSubject();
const nextPageToken$ = subject$
  .startWith('')
  .filter(x => x || x == '')

console.log(log("subject$.next", subject$.next)

@gnimmelf
Copy link
Author

Hmm. I'm returning the subject from a wrapper function, and need both the result stream and the source stream's next method. I could of course code my way out of that, but that shouldn't be necessary imho, as it impacts testability as well as modularity...

@trxcllnt
Copy link
Member

We originally did compose Subject bi-directionality through lift, so if you called next on a Subject returned from an operator, the value would be next'd to the original Subject, and run through the operator chain (snake-eating-its-own-tail-style), but people complained that was confusing. I think it's more confusing that Subjects don't compose bi-directionally, but I've been known to be wrong.

@trxcllnt
Copy link
Member

@gnimmelf for what it's worth, recompose has a method I use to create Subject/next pairs called createEventHandler.

@gnimmelf
Copy link
Author

gnimmelf commented Feb 23, 2017

@trxcllnt thanks for the replies. I'll manage with it 'as-is', one way or another. =)

Just out of curiosity on the note on the original bi-directonal composition: why would it also next the original subject? -I was under the impression that the returned observable from the operator chain would be a new observable subclassed from the "original" observable top of the chain, and not act as if it is the original. Hmm, I think I see the complexity here...

If only I could do s.th like this:

const tmp$ = new Rx.BehaviorSubject()
    .startWith('')
    .filter(x => x || x == '')

return Rx.extend(stream$, Rx.Subject)
// or
return stream$.extend(Rx.Subject)
// or
return stream$.extend(Rx.Subject, 'next')
// ..you get the idea: Simple for me, hard for you ;-)

Cheers!

@gnimmelf
Copy link
Author

I can do this?

export const getNextPageToken$ = () => {
  const orig$ = new Rx.BehaviorSubject();
  const op$ = orig$
    .startWith('')
    .filter(x => x || x === '')

  op$.next = orig$.next.bind(orig$) // <-- THIS!

  return op$
}

and get away with it? -Seems to work...

@gnimmelf
Copy link
Author

gnimmelf commented Feb 23, 2017

Another "case":

const stop$ = new Rx.Subject().merge(storedFiles$)
//...
stop$.next()

Becomes

const cancel$ = new Rx.Subject();
const stop$ = cancel$.merge(storedFiles$);
// ...
cancel$.next()

...at least I'm seeing a pattern. And when I look (again, more thouroughly) at the documentation, most operators return Observable, which does not imply the Subject subclass members...

Thanks & feel free to close this issue.

@lock
Copy link

lock bot commented Jun 6, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 6, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants