Skip to content

Commit bb0edcb

Browse files
regouyyx990803
authored andcommitted
New feature: $createObservableFunction (#48)
* $createObservableFunction * readme y version * indent * add observableMethods
1 parent fa85abe commit bb0edcb

File tree

7 files changed

+216
-1
lines changed

7 files changed

+216
-1
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,36 @@ var vm = new Vue({
241241
})
242242
```
243243

244+
#### `$createObservableMethod(methodName)`
245+
246+
> This feature requires RxJS.
247+
248+
Convert function calls to observable sequence which emits the call arguments.
249+
250+
This is a prototype method added to instances. Use it to create a shared hot observable from a function name. The function will assigned as a vm method.
251+
252+
```html
253+
<custom-form :onSubmit="submitHandler"></custom-form>
254+
```
255+
``` js
256+
var vm = new Vue({
257+
subscriptions () {
258+
return {
259+
// requires `share` operator
260+
formData: this.$createObservableMethod('submitHandler')
261+
}
262+
}
263+
})
264+
```
265+
Or, use the `observableMethods` convenience option:
266+
``` js
267+
new Vue({
268+
observableMethods: { submitHandler:'submitHandler$' }
269+
})
270+
```
271+
[example](https://github.com/vuejs/vue-rx/blob/master/example/counter-function.html)
272+
273+
244274
### Caveats
245275

246276
You cannot use the `watch` option to watch subscriptions, because it is processed before the subscriptions are set up. But you can use `$watch` in the `created` hook instead.

example/counter-function.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!-- this demo requires a browser that natively supports ES2015 -->
2+
3+
<script src="https://unpkg.com/@reactivex/rxjs/dist/global/Rx.js"></script>
4+
<script src="https://unpkg.com/vue/dist/vue.js"></script>
5+
<script src="../dist/vue-rx.js"></script>
6+
7+
<div id="app">
8+
<div>{{ count }}</div>
9+
10+
<!-- callback declared on observableMethods -->
11+
<button v-on:click="muchMore(500)">Add 500</button>
12+
13+
<button v-on:click="minus(minusDelta1)"> Minus on Click </button>
14+
15+
<pre>{{ $data }}</pre>
16+
17+
</div>
18+
19+
<script>
20+
new Vue({
21+
el: '#app',
22+
23+
data () {
24+
return {
25+
minusDelta1: -1,
26+
minusDelta2: -1
27+
}
28+
},
29+
30+
// declare callback Subjects
31+
observableMethods: { muchMore:'muchMore$', minus:'minus$'}, // ['muchMore','minus'] as equal
32+
33+
subscriptions () {
34+
var count$ = Rx.Observable
35+
.merge(
36+
this.muchMore$,
37+
this.minus$
38+
)
39+
.startWith(0)
40+
.scan((total, change) => total + change)
41+
42+
return {
43+
count: count$
44+
}
45+
}
46+
})
47+
</script>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-rx",
3-
"version": "3.2.0",
3+
"version": "3.3.0",
44
"description": "RxJS bindings for Vue",
55
"main": "dist/vue-rx.js",
66
"files": [

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import watchAsObservable from './methods/watchAsObservable'
77
import fromDOMEvent from './methods/fromDOMEvent'
88
import subscribeTo from './methods/subscribeTo'
99
import eventToObservable from './methods/eventToObservable'
10+
import createObservableMethod from './methods/createObservableMethod'
1011

1112
export default function VueRx (Vue, Rx) {
1213
install(Vue, Rx)
@@ -16,6 +17,7 @@ export default function VueRx (Vue, Rx) {
1617
Vue.prototype.$fromDOMEvent = fromDOMEvent
1718
Vue.prototype.$subscribeTo = subscribeTo
1819
Vue.prototype.$eventToObservable = eventToObservable
20+
Vue.prototype.$createObservableMethod = createObservableMethod
1921
}
2022

2123
// auto install

src/methods/createObservableMethod.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Rx, hasRx, warn } from '../util'
2+
3+
/**
4+
* @name Vue.prototype.$createObservableMethod
5+
* @description Creates an observable from a given function name.
6+
* @param {String} methodName Function name
7+
* @param {Boolean} [passContext] Append the call context at the end of emit data?
8+
* @return {Observable} Hot stream
9+
*/
10+
export default function createObservableMethod (methodName, passContext) {
11+
if (!hasRx()) {
12+
return
13+
}
14+
const vm = this
15+
16+
if (!Rx.Observable.prototype.share) {
17+
warn(
18+
`No 'share' operator. ` +
19+
`$createObservableMethod returns a shared hot observable. ` +
20+
`Try import 'rxjs/add/operator/share' for creating ${methodName}`,
21+
vm
22+
)
23+
return
24+
}
25+
26+
if (vm[methodName] !== undefined) {
27+
warn(
28+
'Potential bug: ' +
29+
`Method ${methodName} already defined on vm and has been overwritten by $createObservableMethod.` +
30+
String(vm[methodName]),
31+
vm
32+
)
33+
}
34+
35+
const creator = function (observer) {
36+
vm[methodName] = function () {
37+
const args = Array.from(arguments)
38+
if (passContext) {
39+
args.push(this)
40+
observer.next(args)
41+
} else {
42+
if (args.length <= 1) {
43+
observer.next(args[0])
44+
} else {
45+
observer.next(args)
46+
}
47+
}
48+
}
49+
return function () {
50+
delete vm[methodName]
51+
}
52+
}
53+
54+
// Must be a hot stream otherwise function context may overwrite over and over again
55+
return Rx.Observable.create(creator).share()
56+
}

src/mixin.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ export default {
1414
}
1515
}
1616

17+
const observableMethods = vm.$options.observableMethods
18+
if (observableMethods) {
19+
if (Array.isArray(observableMethods)) {
20+
observableMethods.forEach(methodName => {
21+
vm[ methodName + '$' ] = vm.$createObservableMethod(methodName)
22+
})
23+
} else {
24+
Object.keys(observableMethods).forEach(methodName => {
25+
vm[observableMethods[methodName]] = vm.$createObservableMethod(methodName)
26+
})
27+
}
28+
}
29+
1730
let obs = vm.$options.subscriptions
1831
if (typeof obs === 'function') {
1932
obs = obs.call(vm)

test/test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const Observable = require('rxjs/Observable').Observable
1010
const Subject = require('rxjs/Subject').Subject
1111
const Subscription = require('rxjs/Subscription').Subscription
1212
require('rxjs/add/observable/fromEvent')
13+
require('rxjs/add/operator/share')
1314

1415
// user
1516
require('rxjs/add/operator/map')
@@ -316,3 +317,69 @@ test('$eventToObservable() with lifecycle hooks', done => {
316317
vm.$destroy()
317318
})
318319
})
320+
321+
test('$createObservableMethod() with no context', done => {
322+
const vm = new Vue({
323+
created () {
324+
this.$createObservableMethod('add')
325+
.subscribe(function (param) {
326+
expect(param).toEqual('hola')
327+
done(param)
328+
})
329+
}
330+
})
331+
nextTick(() => {
332+
vm.add('hola')
333+
})
334+
})
335+
336+
test('$createObservableMethod() with muli params & context', done => {
337+
const vm = new Vue({
338+
created () {
339+
this.$createObservableMethod('add', true)
340+
.subscribe(function (param) {
341+
expect(param[0]).toEqual('hola')
342+
expect(param[1]).toEqual('mundo')
343+
expect(param[2]).toEqual(vm)
344+
done(param)
345+
})
346+
}
347+
})
348+
nextTick(() => {
349+
vm.add('hola', 'mundo')
350+
})
351+
})
352+
353+
test('observableMethods mixin', done => {
354+
const vm = new Vue({
355+
observableMethods: ['add'],
356+
created () {
357+
this.add$
358+
.subscribe(function (param) {
359+
expect(param[0]).toEqual('Qué')
360+
expect(param[1]).toEqual('tal')
361+
done(param)
362+
})
363+
}
364+
})
365+
nextTick(() => {
366+
vm.add('Qué', 'tal')
367+
})
368+
})
369+
370+
test('observableMethods mixin', done => {
371+
const vm = new Vue({
372+
observableMethods: { 'add': 'plus$' },
373+
created () {
374+
this.plus$
375+
.subscribe(function (param) {
376+
expect(param[0]).toEqual('Qué')
377+
expect(param[1]).toEqual('tal')
378+
done(param)
379+
})
380+
}
381+
})
382+
nextTick(() => {
383+
vm.add('Qué', 'tal')
384+
})
385+
})

0 commit comments

Comments
 (0)