vuejs / vue-rx Goto Github PK
View Code? Open in Web Editor NEW👁️ RxJS integration for Vue.js.
License: MIT License
👁️ RxJS integration for Vue.js.
License: MIT License
var Base = Vue.extend({
subscriptions () {
return {
count$: Rx.Observable.create(function(observer){
var cnt = 0;
window.setInterval(function(){
observer.next(cnt++)
}, 1000);
})
}
}
});
var Derived = Base.extend({
subscriptions () {
// How I Can get parent observables here ?
}
});
I know I can get the count$
by this.constructor.super.options.subscriptions.call(me).count$
, is there another way to get it?
When defining subscriptions in the subscriptions
field or function there doesn't appear to be a way to attach an error handler to them. I like how convenient it is to just define an observable in these blocks and have Vue subscribe and expose the results to the component, but when subscriptions defined in this manner hit an error condition it breaks the application. Would it be possible to:
The docs mention importing like so
import Vue from 'vue'
import VueRx from 'vue-rx'
Vue.use(VueRx)
However this yields a TypeScript error: TS1192: Module '...node_modules/vue-rx/types/index' has no default export
I was able to work around this via
import Vue from 'vue'
import * as VueRx from 'vue-rx'
const vueRx: any = VueRx
Vue.use(vueRx.default)
And things seem to be working normally now.
Here's the relevant package versions I'm using:
"rxjs": "^6.2.1",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vue-rx": "^6.0.0"
I am testing with karma, and I've notice this.$watchAsObservable('text') doesn't emit values even though this.text has changed.
Thanks.
The test:
it('should be saved after timeout', (done) => {
const saveFileSpy = sinon.spy()
const EditorWithMocks = EditorInjector({
'../../../api/file-access': {
saveFile: saveFileSpy
}
})
const vm = createVm(EditorWithMocks)
vm.text = 'pepo'
vm.filePath = 'filepath'
const inputTextArea = vm.$el.querySelector('.input-textarea')
inputTextArea.textContent = 'p'
dispatchInputEvent(inputTextArea)
clock.tick(1000)
Vue.nextTick()
.then(() => {
expect(saveFileSpy).to.have.been.calledWith('pepop', '123', 'filepath')
done()
})
.catch(done)
The code:
saveFileSubscription: this.$watchAsObservable('text')
.pluck('newValue')
.debounceTime(settings.autoSaveTimeout)
.distinctUntilChanged()
.do(() => this.saveFile()),
Since subscriptions
is not declared in the Vue ComponentOptions
interface adding it to the options when also using the @VueClassComponent
decorator in Typescript causes the TS compiler to believe that the supplied parameter is an instance of VueClass (since it no longer fits the profile of a Vue ComponentOptions
) - however the parameter really is an instance of ComponentOptions
:-(
The only way I've found to avoid this is to use a set of casts on the argument to @VueClassComponent:
@VueClassComponent(<ComponentOptions<MyVueComponent>>{
subscriptions: …
props: …
})
export class MyVueComponent extends Vue {
…
If instead subscriptions was actually a method on the component (MyVueComponent) it would not be necessary to have a custom field added to ComponentOptions
and the casts would not be necessary. I think the patch would be a few lines to look at vm.subscriptions
if vm.$options.subscriptions
were null/undefined. However I'm wondering if there's some reason why subscriptions must be part of the options that I'm missing?
Would you make typings.json
for this repo?
vue-rx does not support weex
Hi all :-)
I've got a problem regarding the subscriptions API. I have a piece of code like this:
import Vue from 'vue'
import numeral from 'numeral'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/interval'
import 'rxjs/add/operator/switchMap'
import 'rxjs/add/operator/map'
import axiosObservable from '../lib/axiosObservable'
export default {
name: 'Exchange',
props: ['exchange_name'],
methods: {
exchangeFetch (exchangeName) {
alert(exchangeName)
return Observable
.interval(3000)
.switchMap(axiosObservable.get(Vue.config.infoCoinUrl + '/exchanges/' + exchangeName + '/market-pairs'))
.map((response) => response.data)
}
},
mounted () {
this.$subscribeTo(
this.exchangeFetch(this.exchange_name),
(data) => {
this.market_pairs = data
})
},
data () {
return {
market_pairs: []
}
},
the idea here is that the dataset returned by the ajax call in exchangeFetch()
depends on the exchange_name
prop. I'm having the issue that the alert runs only when the page first loads and the AJAX call is fixed to the first value of exchange_name
prop.
This is a bit surprising because I'd expect mounted()
to be run on every render, so this kinda +should+ work, possibly, it follows the general docs online, yet it doesn't work.
I'm a bit new at JS, Vue, React, all of it :-) and I'm not sure if this is an issue with the framework or my inexperience (so I wrote an SO question too), yet this seems like a common use case, worthy of docs possibly :-)
PS I opened a vue-rx tag on SO love the project :-)
RxJS now supports "pipeable" operators, it might make sense to support passing in the operator references through the Rx
object bag during initialization, and then fallback to looking on the prototype. That might also make it easier to support other Observable
implementations by letting the library users pass in adapter functions for their particular flavor of Observable
. Areas like here
Hi guys,
I've been trying to add a subscription/observable to my component using the guide in the Readme.
subscriptions () {
// declaratively map to another property with Rx operators
return {
aPlusOne: this.$watchAsObservable('prompt.choices')
.subscribe(({ newValue, oldValue }) => console.log('choices', newValue, oldValue))
}
},
However I get this error in my dev tools console. No clue as to why it is invalid
. What are the rules, what am I missing. Not entirely clear from the docs. Do I need to pre-define it somewhere?
vue.common.js?4eb4:2643 [Vue warn]: Invalid Observable found in subscriptions option with key "aPlusOne".
(found in component <prompt-checkbox> at /Users/kristianmandrup/repos/vue-projs/app-generator/app/src/components/Prompt/Checkbox.vue)
I'm trying to react to updates on a set of checkboxes in order to save those values in my store so other components can reflect on it... However I can't seem to find a way to do it.
Maybe using simple watch
? I tried without luck using on-change handlers, but they only pass true|false
on, so I have no idea which checkbox the changed value is coming from :O
<md-checkbox
v-for="choice in prompt.choices"
:name="prompt.name"
:id="prompt.name"
@input="updateChoice"
@change="updateChoice($event)"
class="md-primary"
v-model="choice.value">{{ choice.label }}</md-checkbox>
I always receive simply true
or false
in my updateChoice(e)
method :(
Is watch
the way to go!? or computed
properties? Doesn't seem right, coz then I would have to watch/react to the entire object iterated and bound to by the checkboxes.
Please advice :) Thanks!
Hello,
Is there any place that I can see example of integration with Class Based Components?
Many thanks in advance!
@yyx990803 @regou I'm liking directives more and more and so I'm keen on seeing the v-ob directive proposed in issue #14 become part of vue-rx/observable. Can it be merged in or is there some problem with it?
In reviewing various vue-rx issues there seem to be a few more suggestions raised. Maybe these be resolved into a next release? We are almost at 500 stars so that should mean that this room is getting brighter for sure.
After preparing other aspects of my project I'm back to taking a look at how the Vue reactivity engine and the Observable engine can work in a harmonious way, my specific requirements are always the catalyst. Have some new strategies I'm working through in my project, always interested in discussion.
Trying to add vue-rx
to a TypeScript project:
Getting the following error:
vue.esm.js?ae66:4080 Uncaught TypeError: Cannot read property 'installed' of undefined
at Function.Vue.use (eval at <anonymous> (build.js:766), <anonymous>:4081:15)
at eval (eval at <anonymous> (build.js:982), <anonymous>:8:15)
at Object.<anonymous> (build.js:982)
at __webpack_require__ (build.js:658)
at fn (build.js:86)
at Object.<anonymous> (build.js:1422)
at __webpack_require__ (build.js:658)
at build.js:707
at build.js:710
main.ts
import Vue from 'vue'
import App from './components/App.vue'
import store from './store'
import Rx from 'rxjs/Rx'
import VueRx from 'vue-rx'
Vue.use(VueRx, Rx)
new Vue({
el: '#app',
store,
render: h => h(App)
})
The rest of the project: https://github.com/johnlindquist/vue-typescript-simple/tree/master/template
Any insights?
Hello,
We are using vue-rx with typescript and we encountered some issues:
subscriptions
we can access to the properties defined in data
but the current vue-rx types say that we can't.Note: It works if you use: subscriptions?: Observables | (() => Observables)
instead of subscriptions?: Observables | ((this: V) => Observables)
. But i didn't make a pull request because i am not sure that we can access to the props when subscriptions
is called.
this
is not extended with the data set by the subscriptions. So we can not access to the current values in the methods etc.Now the initialization runs in beforeCreate without messing up original dataFn
. But this makes properties in subscriptions
not able to use other properties in data
, computed
, props
.
That's problematic since in most times we need to do things like this:
data: {
a: 1
}
subscriptions: {
b: someObservableMaker(this.a) // this maker takes this.a as param to make an observable.
}
I guess this would be the best way to achieve our goal (write in coffee):
beforeCreate: ->
obs = this.$options.subscriptions
if typeof obs is 'function'
obs = obs.call this
return if !obs
for ob of obs # for each key in obs
# use {} value to take the position in advance. **Cannot be undefined**
# has to be {} in order to be used by others during creating
defineReactive this, ob, {}
created: ->
obs = this.$options.subscriptions
if typeof obs is 'function'
obs = obs.call this
return if !obs
for ob of obs # for each key in obs
... # do the converting job for this[obs]
I have a usecase where a key input event within a component needs to be observed from a non child (sibling) component. Is this even possible without emitting event like vm.$emit
I tried to listen for the scroll event on vm root, but it didn't work because $fromDOMEvent delegated the scroll
event to document.documentElement
, but the scroll
event didn't bubble up, please see the following demo:
<template lang="pug">
section.drag-container-wrapper
section.drag-container
</template>
<script>
import { Observable } from 'rxjs'
import { pluck } from 'rxjs/operators'
export default {
subscriptions () {
const rootScroll$ = this.$fromDOMEvent(null, 'scroll')
.map(e => console.log(e))
return {
rootScroll$
}
}
}
</script>
<style lang="stylus" scoped>
.drag-container-wrapper
height 600px
border 1px solid green
overflow-y scroll
padding 10px
.drag-container
height 1600px
border 1px solid red
</style>
Any ideas?
vue: v2.5.2
rxjs: v6.0
vue-rx: v6.0.0
chrome: v67
When debugging why my component didn't work in a unit test, I found out that with $watchAsObservable
, immediate is false by default. So that means that nothing got fired. I would have assumed that it would be true by default, as in most cases, that is what would be expected.
So is there any good reason to have it false by default? And can this be changed?
I think this library has some great goals, and I'd like to see it take full advantage of RxJS v6's modularity and "tree-shakability"
I recommend:
All of this will drastically simplify your codebase as well as make apps built with vue-rx and Webpack 4 a lot smaller.
I have a question.I need unsubscribe in the angular.But i don't know in the vue.js how to do?Because Readme didn't say this.Maybe I don't need to worry this?
Specifically TypeError: val is null
. I've made a PR that fixes it; I didn't include any test scaffold addition to verify it. #8
I want to use a stream with observableMethods
into mounted () {
with this.$subscribeTo
but then I have an error:
Property or method "foo" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See...
When I use that into subscriptions
everything is all right but I have to subscribe that observable so is it a good place for that? Is using the subscribe
inside subscriptions
guarantee unsubscribe before component will be destroyed?
I think there should be an implementation of TodoMVC using vue-rx. Or if not the full TodoMVC, then at least a simple 'todo' example. A real world application's needs would probably align closer with the todo app than with the counter examples, and it would probably help new users better understand how to use it.
code
import { shallowMount, mount, Wrapper } from "@vue/test-utils";
import { CloudTable } from "@components/cloudtable/table";
import ElementUI from "element-ui";
import { systemTable } from "@store/table.store.attchment";
import Vue from "vue";
import VueRx from "vue-rx";
describe("src/components/cloudtable/table.ts", () => {
let cmp!: Wrapper<CloudTable>;
beforeEach(() => {
Vue.use(ElementUI);
Vue.use(VueRx);
cmp = mount(CloudTable, {
propsData: {
moduleName: "usertable",
config: systemTable["usertable"],
}
});
});
it("翻页事件是否正常", () => {
cmp.find(".btn-prev").trigger("click");
expect(cmp.vm.handleCurrentChange).toBeCalled();
});
});
jest-config.json
{
"rootDir": "../",
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest",
"^.+\\.html$": "<rootDir>/test/html.tranform.js",
"^.+\\.styl$": "<rootDir>/test/stylus.tranform.js",
"^.+\\.css$": "<rootDir>/test/css.tranform.js"
},
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!(element-ui|quill)/)"
],
"globals": {
"ts-jest": {
"tsConfigFile": "tsconfig.json",
"skipBabel": true,
"enableTsDiagnostics": true
}
},
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"moduleNameMapper": {
"^vue$":"vue/dist/vue.common.js",
"^vue-rx$":"vue-rx/dist/vue-rx.esm.js",
"^@components/(.*)$": "<rootDir>/src/components/$1",
"^@views/(.*)$": "<rootDir>/src/views/$1",
"^@utils/(.*)$": "<rootDir>/src/utils/$1",
"^@router/(.*)$": "<rootDir>/src/router/$1",
"^@store/(.*)$": "<rootDir>/src/store/$1",
"^@directives/(.*)$": "<rootDir>/src/directives/$1",
"^@server/(.*)$": "<rootDir>/src/server/$1",
"^@filters/(.*)$": "<rootDir>/src/filters/$1"
}
}
tsconfig.json
{
"compilerOptions": {
/* Basic Options */
"target": "es5",
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs",
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": [
"es2015",
"dom",
"es6",
"es2016",
],
/* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
"removeComments": true,
/* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
// "strict": true,
/* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "node",
/* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
//"baseUrl": "",
/* Base directory to resolve non-absolute module names. */
//"paths": {},
/* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true,
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
"experimentalDecorators": true,
/* Enables experimental support for ES7 decorators. */
"emitDecoratorMetadata": true
/* Enables experimental support for emitting type metadata for decorators. */
}
}
As the RxJS project lead, I highly recommend just installing rxjs
(v6 preferred) and importing and using it as normal. Otherwise, there will be severe application size and performance penalties when using this library.
If you need help, I'm happy to do so.
This is related to my findings while helping review #78
Hi,
I am new to VUE ( I have an angular background ). Is there a way to and in the HTML something like this?
{{someObservable('value1')}}
{{someObservable('value2')}}
I need to watch on the same component multiple subjects depending on the value that is pass from the function.
Thanks in advance.
Hi, we are currently investigating switching to Vue.js from AngularJS and I don't see a way to use props as observables. This is what we have currently (with https://github.com/cvuorinen/angular1-async-filter):
<child my-attribute="$ctrl.myAttribute$ | async : this">
</child>
and then inside the child:
{{$ctrl.myAttribute}}
(The parent also got myAttribute$ injected with an attribute from ui-router)
The thing is that myAttribute$ can change, so it could be switched out with another observable. In AngularJS, the async filter (pipe) handles this for us, but from what I can see in the docs of vue-rx, there is no way to do this?
The only thing I think would work is using $watchAsObservable('myAttribute$').pipe(switchAll())
in the parent and then use that to inject into the child, but imho this use-case should be part of this solution, because it also needs to handle cases where the observable itself is undefined etc....
Any ideas?
Hi!
I'm facing a problem installing VueRx.
By requiring entirely RxJs everything is fine:
var Vue = require("vue");
var VueRx = require("vue-rx");
var Rx = require('rxjs');
Vue.use(VueRx, Rx);
But when I try to reduce the bundle size:
var Vue = require("vue");
var VueRx = require("vue-rx");
var Rx = require('rxjs/Observable');
Rx.Subject = require('rxjs/Subject').Subject;
require('rxjs/add/operator/debounceTime');
require('rxjs/add/operator/map');
require('rxjs/add/operator/do');
require('rxjs/add/operator/mergeMap');
Vue.use(VueRx, Rx);
It's give me this error:
Error in directive stream bind hook: "TypeError: Cannot read property 'apply' of undefined"
Am I doing something wrong?
Thanks!
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?
Admittedly a fairly trivial helper, but I know it would help with some boiler plate. And it gives a nice symmetry to the $fromEvent
helpers
Basically:
function $subscribeAsEmit (name) {
return (observable) => observable.subscribe(event => this.$emit(name, event))
}
new Vue {
subscriptions: {
a: someObservable
},
watch: {
a: function (v) {console.log (v); } // do something when 'a' changed. but not working.
}
}
v-stream绑定事件时调用的 Rx.Observable.fromEvent.
vue-rx 源码 -> https://github.com/vuejs/vue-rx/blob/master/src/directives/stream.js#L38
并不能监听vue自定义事件.
Does not support feature Event Modifiers
v-stream:click.stop
@yyx990803 The new v-stream directive is ready go, the PR #34 just needs to be merged. Having an updated version is important for ongoing development of my reactive product in Vue.
IMO, while v-stream is intended to replace $fromDOMEvent, both options could also co-exist in vue-rx.
What to do when custom events pass multiple parameters
this.$emit('pageChanged', oldPage, newPage, direction)
As someone new to Vue one of the first things I investigated was RxJS support, which landed me here, awesome! The example given in this repo is good and then I've seen another step up in how to integrate RxJS into Vue in the Summary section of the following link: http://www.christianalfoni.com/articles/2016_03_31_RxJs-the-smartest-dumbest-tool-ever
As I'm becoming acquainted with Vue I've seen the clean and elegant new @event syntax. As a result a thought entered my mind, which I would just like to share here. In essence reactive streaming API's like RxJS and others are here to stay, and support for Observables is coming to ES7: https://github.com/zenparsing/es-observable
That being the present and the future looking bright for both Vue and Observables I'm wondering if Vue might fully embrace Observables and support a @stream syntax?
I realize that after the hook was changed from beforeCreate
to created
, now computed
is initialized before subscriptions
, so things in subscriptions
cannot be used in computed
. -_-~~
new Vue {
subscriptions: {
a: arrayFromSomeObservable;
},
computed: {
b: function () {
return this.a.length // not working.... coz this.a doesn't exist when this function runs for the first time
}
}
}
A workaround is to change this.a.length
to something like this.a === null? null : this.a.length
(or this.a?.length
in coffee). But don't seem neat....
Is there any way to overcome this while still being able to use this
in subscriptions? puzzling...
I have gone through the vue docs and Majesty of Vue.js etc. and are very much an admirer. Currently I am getting familiar with most.js, a reactive programming framework similar to RxJS, which seems very nice as well.
I am having a problem getting a clear picture whether it is still useful to use rx frameworks when using Vue plus Vuex. I read somewhere that the most.js streams are pretty much ‘decentralized vuex state variables’, which makes it sound like there is not much use for it then. On the other hand this repo suggests it’s useful, I suppose. So in what areas do they 'shine'? Tried some other places/ forums before posting here. Any comments highly appreciated!
Interesting behavior in Vue. You can see from example that BehaviorSubject is initialized with false
and it is clear that self[key] = value
works. However, the vm
doesn't pick it up.
This plugin runs the data
function in the beforeCreate
hook to transform observables to subscriptions, which makes it impossible to use this
in data
, since this
does not exist when beforeCreate
.
For example, sometimes we do this:
new Vue {
data: function () {
return {
route: this.$route.path; // to get the current router path when this vue component is created.
...
}
}
}
But with this plugin we have to change it into this:
new Vue {
data: function () {
return {
route: ''
...
}
},
created: function () {
this.route = this.$route.path;
}
}
It's okay for our own codes, but it gets painful when some third-party packages have this issue. In fact many plugins such as mint-ui
have this issue, since using this
in data
is not very rare in practice.
So my suggestion is to move this data
processing code to created
hook instead of beforeCreate
hook. I understand that, in created
, if we add new properties to data
we have to manually make them reactive, but in beforeCreate
we don't need to do this. I guess this is why currently it's in beforeCreate
. But considering the issue above, I think it's worth to make this change.
Hi!
It seems that the event delegation in $fromDOMEvent
doesn't work with events that don't bubble up, like focus
or blur
.
It seems that, for events that don't bubble, you want to use event capturing when adding the event listener.
Took a quick look how CycleJS does it. They just look up the event in a list of events (https://github.com/cyclejs/cyclejs/blob/master/dom/src/MainDOMSource.ts#L28), and determine if the event should captured or not based on that (https://github.com/cyclejs/cyclejs/blob/master/dom/src/MainDOMSource.ts#L59).
Hi. Thanks for adding TS files into this library.
I tried to use the new version, but types
directory isn't included into npm packages.
Could you fix this?
It looks like createObservableMethod
will fail because of how it checks to see if share()
is supported here.
if (!Rx.Observable.prototype.share) {...}
Right now, it is checking for support on the prototype of Observable
when share()
is actually somewhere around RxJS.operators.share()
. Is there a way to address this through the new piping mechanism without having to utilize the rxjs-compat
module?
This is sort of related to #69 but since createObservableMethod
directly uses share()
off the Observable
prototype, the feature is broken.
subscriptions () {
return {
a: SomeObservable
}
},
watch: {
'a': function () {console.log('a changed!')}
}
When a
changes, it cannot be watched. This might be due to obs in subscriptions
are defined with Vue.util.defineReactive
, which makes it reactive, but not watchable.
If adding test
to data
and use $subscribeTo
in mounted
to link test
with SomeObservable
, it works. But it seems not very neat writing in this way. I guess it would be best to put the obs into data
.
Code here uses the old option name rx
instead of subscriptions
.
I understand that using subscriptions
means supporting not only RxJS but any other observable libs. So maybe it needs a new name rather than vue-rx
.
I was just looking through your code, and I noticed you're using publish().refCount()
here
This becomes problematic if something downstream causes an error and you want to reconnect the observable. something like...
// Imagine the endpoint throws a 404 here.
o.$watchAsObservable('foo').switchMap(x => Observable.ajax.getJSON('http://endpoint/' + x)).retry(3)
It's a little edge-casey, honestly. And it can be easily worked around by moving the retry
inside of the switchMap
.
My first thought is you can solve this by replacing .publish().refCount()
with .share()
. They behave similarly, but share
allows retries.
However, looking slightly more deeply, I think that what you're building on top of ($watch
) is effectively multicast anyhow, so you probably don't need publish().refCount()
in the first place, unless the underpinnings of $watch
are particularly costly. It's really up to you.
Great work here, BTW!
In readme, there is stated vue-rx can be used to subscribe to most.js observables, but it does not seem to work out-of-box. mostjs observables needs to be subscribed using observe
method which does accept simple handler. vue-rx is calling subscribe
method which expects Observer object
(https://github.com/cujojs/most/blob/master/docs/api.md#subscribe)
functioning workaround:
{
subscriptions () {
const num = most.periodic(100).scan(x => x + 1, 0)
num.subscribe = num.observe
return {
num,
}
},
}
I am new to observables, am I doing something wrong? Thanks.
The addition of the new subscriptions option to a vm makes a huge difference, thanks Evan! There is now a place (sandbox) for observables to do their thing in. Using the subscriptions option it is possible to build any kind of observable while the method option remains for standard functions. Its a nice separation of concerns.
When I first encountered Vue and was learning the basics I saw an opportunity to bind RxJS directly into the Vue event system and I mentioned this in several issues here but never got any feedback on this idea. No one said a word but finally I came to the understanding that this binding could be achieved using a Vue Directive.
I suppose this directive could be added to this vue-observable plugin as well but I'm not even sure it is the most versatile idea anymore? Using RxJS alone (using fromEvent) it is possible to capture events from the DOM so why bother with the directive? Can someone tell me instead of me just always making what I consider positive suggestions!
Anyways, I just want to auto subscribe several observables when I create a component and capture their events as a streams. This looks like it is possible now so I can finally rest my battle weary head and enjoy the fruit of my quest for a good framework.
Based on feedback I'll kill this and the other issues I created and we can all move on in triumph :)
When following the usage description and trying to watch a property as an Observable I get the following error in the browser console:
"this.$watchAsObservable(...).pluck is not a function"
My app environment looks like this:
"dependencies": {
"elasticsearch": "^12.1.3",
"material-design-lite": "^1.3.0",
"rxjs": "^5.0.3",
"vue": "^2.1.0",
"vue-locale": "^0.4.0",
"vue-material": "^0.6.3",
"vue-router": "^2.1.3",
"vue-rx": "^2.3.1"
},
"devDependencies": {
"autoprefixer": "^6.4.0",
"babel-core": "^6.0.0",
"babel-eslint": "^7.0.0",
"babel-loader": "^6.0.0",
"babel-plugin-transform-runtime": "^6.0.0",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.0.0",
"babel-register": "^6.0.0",
"chalk": "^1.1.3",
"connect-history-api-fallback": "^1.1.0",
"css-loader": "^0.25.0",
"eslint": "^3.7.1",
"eslint-friendly-formatter": "^2.0.5",
"eslint-loader": "^1.5.0",
"eslint-plugin-html": "^1.3.0",
"eslint-config-standard": "^6.1.0",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^2.0.1",
"eventsource-polyfill": "^0.9.6",
"express": "^4.13.3",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.9.0",
"friendly-errors-webpack-plugin": "^1.1.2",
"function-bind": "^1.0.2",
"html-webpack-plugin": "^2.8.1",
"http-proxy-middleware": "^0.17.2",
"json-loader": "^0.5.4",
"cross-env": "^3.1.3",
"karma": "^1.3.0",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.0",
"karma-sinon-chai": "^1.2.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "^1.7.0",
"lolex": "^1.4.0",
"mocha": "^3.1.0",
"chai": "^3.5.0",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0",
"inject-loader": "^2.0.1",
"babel-plugin-istanbul": "^3.0.0",
"phantomjs-prebuilt": "^2.1.3",
"chromedriver": "^2.21.2",
"cross-spawn": "^4.0.2",
"nightwatch": "^0.9.8",
"selenium-server": "2.53.1",
"semver": "^5.3.0",
"opn": "^4.0.2",
"ora": "^0.3.0",
"shelljs": "^0.7.4",
"url-loader": "^0.5.7",
"vue-loader": "^10.0.0",
"vue-style-loader": "^1.0.0",
"vue-template-compiler": "^2.1.0",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-hot-middleware": "^2.12.2",
"webpack-merge": "^0.14.1"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
}
import Vue from 'vue'
import VueRouter from 'vue-router'
import vueResource from 'vue-resource'
import VueSession from 'vue-session'
import VueModal from 'vue-js-modal'
import VuePopper from 'vue-popperjs'
import VueJQuery from 'jquery'
import Bootstrap from 'bootstrap'
import app from './App.vue'
import {routes} from './route.js'
Vue.use({VueJQuery});
Vue.use(VuePopper)
Vue.use(VueSession, {persist: true})
Vue.use(VueRouter)
Vue.use(vueResource)
Vue.use(VueModal)
Vue.http.options.root = 'http://localhost:1337/';
Vue.use(Bootstrap);
Uncaught TypeError: Cannot read property 'install' of undefined
at Function.Vue.use (vue.esm.js?efeb:4680)
at eval (main.js?3479:20)
at Object. (build.js:1056)
at webpack_require (build.js:679)
at fn (build.js:89)
at Object. (build.js:905)
at webpack_require (build.js:679)
at build.js:725
at build.js:728
I keep getting this issue only when i add the use part of bootstrap
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.