Permalink
Browse files

feat(mixin): Automate event registration & removal on root vm (#581)

New mixin for $root listeners
  • Loading branch information...
alexsasharegan authored and tmorehouse committed Jun 30, 2017
1 parent b094ca2 commit be5f8341b6e45863b427d6d2ab8cbdfb0d350e14
@@ -20,6 +20,7 @@
<script>
import formMixin from '../mixins/form';
import formCheckBoxMixin from '../mixins/form-checkbox';
import isArray from '../utils/isArray';
export default {
mixins: [formMixin, formCheckBoxMixin],
@@ -45,7 +46,7 @@ export default {
},
methods: {
handleChange({ target: { checked } }) {
if (Array.isArray(this.checked)) {
if (isArray(this.checked)) {
if (this.isChecked) {
this.$emit('change', this.checked.filter(x => x !== this.value));
} else {
@@ -1,3 +1,4 @@
import isArray from '../utils/isArray';
const inBrowser = typeof window !== 'undefined';
const isServer = !inBrowser;

@@ -509,7 +510,7 @@ ScrollSpy.prototype._setParentsSiblingActiveState = function (element, selector,
if (!classes) {
return;
}
if (!Array.isArray(classes)) {
if (!isArray(classes)) {
classes = [classes];
}
let el = element;
@@ -1,9 +1,11 @@
import isArray from '../utils/isArray';

export default {
computed: {
formOptions() {
let options = this.options || {};

if (Array.isArray(options)) {
if (isArray(options)) {
// Normalize flat arrays to object Array
options = options.map(option => {
if (typeof option === 'object') {
@@ -0,0 +1,55 @@
import isArray from "../utils/isArray"
/**
* Issue #569: collapse::toggle::state triggered too many times
* @link https://github.com/bootstrap-vue/bootstrap-vue/issues/569
*/
export default {
methods: {
/**
* Safely register event listeners on the root Vue node.
* While Vue automatically removes listeners for individual components,
* when a component registers a listener on root and is destroyed,
* this orphans a callback because the node is gone,
* but the root does not clear the callback.
*
* This adds a non-reactive prop to a vm on the fly
* in order to avoid object observation and its performance costs
* to something that needs no reactivity.
* It should be highly unlikely there are any naming collisions.
* @param {string} event
* @param {function} callback
* @chainable
*/
listenOnRoot(event, callback) {
if (!this.__bv_root_listeners || !isArray(this.__bv_root_listeners)) {
this.__bv_root_listeners = []
}
this.__bv_root_listeners.push({ event, callback })
this.$root.$on(event, callback)

return this
},

/**
* Convenience method for calling vm.$emit on vm.$root.
* @param {string} event
* @param {*} args
* @chainable
*/
emitOnRoot(event, ...args) {
this.$root.$emit(event, ...args)

return this
}
},

destroyed() {
if (this.__bv_root_listeners && isArray(this.__bv_root_listeners)) {
while (this.__bv_root_listeners.length > 0) {
// shift to process in order
const { event, callback } = this.__bv_root_listeners.shift()
this.$root.$off(event, callback)
}
}
}
}
@@ -1,4 +1,5 @@
import Tether from 'tether';
import isArray from '../utils/isArray';
// Controls which events are mapped for each named trigger, and the expected popover behavior for each.
const TRIGGER_LISTENERS = {
click: {click: 'toggle'},
@@ -88,7 +89,7 @@ export default {
return true;
} else if (typeof value === 'string') {
return Object.keys(TRIGGER_LISTENERS).indexOf(value) !== -1;
} else if (Array.isArray(value)) {
} else if (isArray(value)) {
const keys = Object.keys(TRIGGER_LISTENERS);
value.forEach(item => {
if (keys.indexOf(item) === -1) {
@@ -0,0 +1,6 @@
const isArray =
typeof Array.isArray === "function"
? Array.isArray
: obj => Object.prototype.toString.call(obj) === "[object Array]"

export default isArray

0 comments on commit be5f834

Please sign in to comment.