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

Emitted values are nested too deep in domStreams #61

Closed
chriscalo opened this issue Oct 11, 2017 · 4 comments
Closed

Emitted values are nested too deep in domStreams #61

chriscalo opened this issue Oct 11, 2017 · 4 comments

Comments

@chriscalo
Copy link

Imagine a <parent> component that contains a <child> component.

The ChildComponent emits a "change" event, passing a value:

export default {
  name: "child",
  methods: {
    onChange(value) {
      this.$emit("change", value);
    },
  },
};

In the ParentComponent we use a stream to listen to those "change" events from the ChildComponent.

export default {
  name: "parent",
  domStreams: ["changeEvents"],
  subscriptions() {
    this.changeEvents
      .map(payload => payload.event.msg)
      .subscribe(value => {
        // do something with value
      });
  },
  components: {
    ChildComponent,
  },
};

Notice that the value emitted by the ChildComponent is nested two layers deep, meaning I have to .map(payload => payload.event.msg) to retrieve it. This feels unnecessarily complicated.

Is there some way to simplify this? What feels cleaner to me is one of the following in the parent component.

.map((payload, event) => event.msg)
.map((payload, value) => value)
.map((value, payload) => value)

Is there some way to cleanly achieve this for all vue-rx stream bindings? Am I approaching this the wrong way?

@regou
Copy link
Collaborator

regou commented Oct 11, 2017

.map( (payload, event) )
It’s not about vue-rx, The emmiting value from Observable has to be a non-splittable singular.
The payload contains raw event Object and data from ‘v-stream’ directive

@chriscalo
Copy link
Author

That's a good point.

After giving this some more thought, what still seems to bother me is that the value I'm trying to pass along is getting trapped inside two layers. At worst, I feel like it should be one layer.

If I simply listen to the ChildComponent's "change" event using standard even listeners (@change="onChildChange"), then value passed from the child component comes straight through as the first parameter in the handler, no nesting.

export default {
  name: "parent",
  methods: {
    onChildChange(value) {
      // do something with value
    },
  },
  components: {
    ChildComponent,
  },
};

But as soon as you use vue-rx streams, two layers of nesting are added:

{
  event: {
    // …
    msg: "…", // the value passed from the ChildComponent
    // …
  },
  data: { /* … */ }
}

I understand that the first layer of nesting is there so you can add data parameters. But the second layer feels inconsistent with the fact that the standard event listener doesn't work this way.

This feels like what it should be doing:

export default {
  name: "parent",
  domStreams: ["changeEvents"],
  subscriptions() {
    this.changeEvents
-     .map(payload => payload.event.msg)
+     .map(payload => payload.event) // where `event` is the value passed from `ChildComponent`
      .subscribe(value => {
        // do something with value
      });
  },
  components: {
    ChildComponent,
  },
};

Or, if I don't pass any data parameters at all, I would actually prefer the following:

export default {
  name: "parent",
  domStreams: ["changeEvents"],
  subscriptions() {
    this.changeEvents
-     .map(payload => payload.event.msg)
      .subscribe(value => { // just pass along what the `ChildComponent` emitted
        // do something with value
      });
  },
  components: {
    ChildComponent,
  },
};

Is there a good reason both layers need to be there?

Cheers 🙏

@regou
Copy link
Collaborator

regou commented Oct 13, 2017

The outputs of this.changeEvents should be consistence in all circumstances, don't you think?
And instead of .map you may use .pluck('event','msg')

Above them all you can directly convert the method onChildChange(value) to observable by $createObservableMethod('onChildChange'). This api is for some child components that use callbacks.

@chriscalo
Copy link
Author

Thanks, @regou. Your tip on $createObservableMethod() helped me find something thats seems to work as expected. It was a variant on the counter-function example:

export default {
  name: "parent",
  observableMethods: ["childChange"],
  subscriptions() {
    this.childChange$.subscribe(value => {
      // do something with value
    });
  },
  components: {
    ChildComponent,
  },
};

This solves my problem. Thank you. 🙏

(It would still be great to see an example showing the full context of a child component publishing an observable stream and the parent component subscribing to it. I still don't know The Right Way to do that.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants