diff --git a/README.md b/README.md index 67327952..2e50f497 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Integrates [apollo](http://www.apollostack.com/) in your [Vue](http://vuejs.org) - [Subscriptions](#subscriptions) - [Skipping the subscription](#skipping-the-subscription) - [Pagination with `fetchMore`](#pagination-with-fetchmore) +- [Skip all](#skip-all) ## Installation @@ -723,12 +724,12 @@ mounted() { }, ``` -You can declare subscriptions in the `apollo` option with the `subscribe` keyword: +You can declare subscriptions in the `apollo` option with the `$subscribe` keyword: ```javascript apollo: { // Subscriptions - subscribe: { + $subscribe: { // When a tag is added tags: { query: gql`subscription tags($type: String!) { @@ -772,7 +773,7 @@ If the subscription is skipped, it will disable it and it will not be updated an // Apollo-specific options apollo: { // Subscriptions - subscribe: { + $subscribe: { // When a tag is added tags: { query: gql`subscription tags($type: String!) { @@ -895,6 +896,34 @@ export default { [Here](https://github.com/Akryum/apollo-server-example/blob/master/schema.js#L21) is a simple example for the server. +## Skip all + +You can disable all the queries for the component with `skipAllQueries`, all the subscriptions with `skipAllSubscriptions` and both with `skipAll`: + +```javascript +this.$apollo.skipAllQueries = true +this.$apollo.skipAllSubscriptions = true +this.$apollo.skipAll = true +``` + +You can also declare these properties in the `apollo` option of the component. It can be booleans: + +```javascript +apollo: { + $skipAll: true +} +``` + +Or reactive functions: + +```javascript +apollo: { + $skipAll () { + return this.foo === 42 + } +} +``` + --- LICENCE ISC - Created by Guillaume CHAU (@Akryum) diff --git a/package.json b/package.json index 0b991414..578a181a 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "vue-apollo", - "version": "1.3.1", + "version": "1.4.0", "description": "Vue apollo integration", "main": "index.js", "scripts": { "compile": "babel --presets es2015,stage-0 -d lib/ src/", "prepublish": "npm run compile", - "ev": "npm-watch" + "dev": "npm-watch" }, "watch": { "compile": "src/*.js" diff --git a/src/smart-apollo.js b/src/smart-apollo.js index 5c296c52..ff85dc3b 100644 --- a/src/smart-apollo.js +++ b/src/smart-apollo.js @@ -10,15 +10,16 @@ class SmartApollo { this.key = key this.options = options this._skip = false + this._watchers = [] // Query callback if (typeof this.options.query === 'function') { const queryCb = this.options.query.bind(this.vm) this.options.query = queryCb() - this.vm.$watch(queryCb, query => { + this._watchers.push(this.vm.$watch(queryCb, query => { this.options.query = query this.refresh() - }) + })) } this.autostart() @@ -26,9 +27,9 @@ class SmartApollo { autostart () { if (typeof this.options.skip === 'function') { - this.vm.$watch(this.options.skip.bind(this.vm), this.skipChanged.bind(this), { + this._watchers.push(this.vm.$watch(this.options.skip.bind(this.vm), this.skipChanged.bind(this), { immediate: true, - }) + })) } else if (!this.options.skip) { this.start() } else { @@ -56,8 +57,10 @@ class SmartApollo { } refresh () { - this.stop() - this.start() + if (!this._skip) { + this.stop() + this.start() + } } start () { @@ -116,6 +119,13 @@ class SmartApollo { this.options.error.call(this.vm, error) } } + + destroy () { + this.stop() + for (const unwatch of this._watchers) { + unwatch() + } + } } export class SmartQuery extends SmartApollo { @@ -237,8 +247,10 @@ export class SmartQuery extends SmartApollo { this.loading = false } - get fetchMore () { - return this.observer.fetchMore.bind(this.observer) + fetchMore (...args) { + if (this.observer) { + this.observer.fetchMore(...args) + } } } diff --git a/src/vue-plugin.js b/src/vue-plugin.js index 6be09ac1..6a7d51c5 100644 --- a/src/vue-plugin.js +++ b/src/vue-plugin.js @@ -2,6 +2,7 @@ import omit from 'lodash.omit' import { print } from 'graphql-tag/printer' import { SmartQuery, SmartSubscription } from './smart-apollo' +let Vue let apolloClient = null let defineReactive = function () {} @@ -23,6 +24,9 @@ function addGraphQLSubscriptions (networkInterface, wsClient) { class DollarApollo { constructor (vm) { + this._apolloSubscriptions = [] + this._watchers = [] + this.vm = vm this.queries = {} this.subscriptions = {} @@ -37,12 +41,11 @@ class DollarApollo { } watchQuery (options) { - const vm = this.vm const observable = this.client.watchQuery(options) const _subscribe = observable.subscribe.bind(observable) - observable.subscribe = function (options) { + observable.subscribe = (options) => { let sub = _subscribe(options) - vm._apolloSubscriptions.push(sub) + this._apolloSubscriptions.push(sub) return sub } return observable @@ -53,12 +56,11 @@ class DollarApollo { } subscribe (options) { - const vm = this.vm const observable = this.client.subscribe(options) const _subscribe = observable.subscribe.bind(observable) - observable.subscribe = function (options) { + observable.subscribe = (options) => { let sub = _subscribe(options) - vm._apolloSubscriptions.push(sub) + this._apolloSubscriptions.push(sub) return sub } return observable @@ -71,11 +73,52 @@ class DollarApollo { subscribeOption (key, options) { this.subscriptions[key] = new SmartSubscription(this.vm, key, options) } + + defineReactiveSetter (key, func) { + this._watchers.push(this.vm.$watch(func, value => { + console.log(value) + this[key] = value + }, { + immediate: true, + })) + } + + set skipAllQueries (value) { + for (let key in this.queries) { + this.queries[key].skip = value + } + } + + set skipAllSubscriptions (value) { + for (let key in this.subscriptions) { + this.subscriptions[key].skip = value + } + } + + set skipAll (value) { + this.skipAllQueries = value + this.skipAllSubscriptions = value + } + + destroy () { + for (const unwatch of this._watchers) { + unwatch() + } + for (let key in this.queries) { + this.queries[key].destroy() + } + for (let key in this.subscriptions) { + this.subscriptions[key].destroy() + } + this._apolloSubscriptions.forEach((sub) => { + sub.unsubscribe() + }) + this._apolloSubscriptions = null + this.vm = null + } } const prepare = function prepare () { - this._apolloSubscriptions = [] - // Lazy creation Object.defineProperty(this, '$apollo', { get: () => { @@ -91,6 +134,10 @@ const prepare = function prepare () { if (apollo) { this._apolloQueries = omit(apollo, [ 'subscribe', + '$subscribe', + '$skipAll', + '$skipAllQueries', + '$skipAllSubscriptions', ]) // watchQuery @@ -110,9 +157,32 @@ const launch = function launch () { } let apollo = this.$options.apollo - if (apollo && apollo.subscribe) { - for (let key in apollo.subscribe) { - this.$apollo.subscribeOption(key, apollo.subscribe[key]) + if (apollo) { + if (apollo.subscribe) { + Vue.util.warn('vue-apollo -> `subscribe` option is deprecated. Use the `$subscribe` option instead.') + for (let key in apollo.subscribe) { + this.$apollo.subscribeOption(key, apollo.subscribe[key]) + } + } + + if (apollo.$subscribe) { + for (let key in apollo.$subscribe) { + this.$apollo.subscribeOption(key, apollo.$subscribe[key]) + } + } + + defineReactiveSetter(this.$apollo, 'skipAll', apollo.$skipAll) + defineReactiveSetter(this.$apollo, 'skipAllQueries', apollo.$skipAllQueries) + defineReactiveSetter(this.$apollo, 'skipAllSubscriptions', apollo.$skipAllSubscriptions) + } +} + +function defineReactiveSetter ($apollo, key, value) { + if (typeof value !== 'undefined') { + if (typeof value === 'function') { + $apollo.defineReactiveSetter(key, value) + } else { + $apollo[key] = value } } } @@ -120,9 +190,9 @@ const launch = function launch () { module.exports = { addGraphQLSubscriptions, - install (Vue, options) { + install (pVue, options) { + Vue = pVue defineReactive = Vue.util.defineReactive - apolloClient = options.apolloClient Vue.mixin({ @@ -135,11 +205,8 @@ module.exports = { created: launch, destroyed: function () { - this._apolloSubscriptions.forEach((sub) => { - sub.unsubscribe() - }) - this._apolloSubscriptions = null if (this._apollo) { + this._apollo.destroy() this._apollo = null } },