Vue 2 + Bootstrap-vue - dynamic attribute - vue.js

this is my first steps in Vue 2 + bootstrap-vue, and I'm trying to figure out how to dynamically change the name of an attribute, so that at a small screen resolution the tooltip changes its position.
JS code below works fine, but tooltip not changing his position =(
Please help me improve my mistake;
.pug
JS
'use strict';
import Vue from 'vue';
import BootstrapVue from 'bootstrap-vue';
document.addEventListener("DOMContentLoaded", function () {
Vue.use(BootstrapVue);
new Vue({
el: '#freshbroccoli',
data: {
windowWidth: null,
position: this.windowWidth >= 480 ? 'left' : 'bottom'
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
this.getWindowWidth();
});
},
methods: {
getWindowWidth() {
this.windowWidth = document.documentElement.clientWidth;
console.log('this.windowWidth >= 480 ? \'left\' : \'bottom\'', this.windowWidth >= 480 ? 'left' : 'bottom', '\n', this.windowWidth);
}
},
beforeDestroy() {
window.removeEventListener('resize', this.getWindowWidth);
}
});
});
Browser - Chrome
Browser console - Chrome

Edit: my old answer assumed that was a v-b-tooltip was a component and not a directive.
From what I can tell, using a variable in a directive isn't supported. One solution would be to use vue-popper since you can update its options dynamically. Bootstrap uses Popper under the hood for its tooltips, so you wouldn't be introducing new technologies this way.

For Bootstrap-Vue tooltip there is parameter placement, so code could look like this:
<b-btn title="Title" target="d150" :placement="position">My btn</b-btn>
More at: https://bootstrap-vue.js.org/docs/components/tooltip

Related

how to binding TinyMCE (text editor for article) to Vue js in laravel?

hi in this case blade i used 'TinyMCE' for article text edit , and 'v-model' is setting to 'textarea' tag,I want to bind the text inserted in the text editor to Vue. I used v-model but it didn't work.
in blade I used TinyMCE CDN and textarea tag binding like this :
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: '#mytextarea'
});
</script>
<textarea id="mytextarea" v-model="ArticleBody"></textarea>
in app.js :
createApp({
data() {
return {
ArticleBody: ''
}
},
created: function () {
},
methods: {
AddArticel:function (){
alert( this.ArticleBody)
},
}
}).mount('#article')
But in Vue Devtools ArticleBoy is undefined !!
when remove id="mytextarea" in textarea tag everything is OK and work But i need TextEditor for Articles!
I don't want to use the vue js component. The codes are written in app.js.
please help me

Vuetify Storybook remapInternalIcon issue

Using Vuetify 2 and Storybook 6 (source https://github.com/lydonchandra/vuetify2storybook6 )
The component renders fine, but keep getting this error TypeError because vm.$vuetify.icons is undefined, when rendering component for first time.
Not sure which storybook-vuetify initialization bridge did I miss ?
TypeError: Cannot read property 'component' of undefined
at remapInternalIcon (vuetify.js:44048)
at VueComponent.getIcon (vuetify.js:16881)
at Proxy.render (vuetify.js:17009)
at VueComponent.Vue._render (vue.esm.js:3557)
at VueComponent.updateComponent (vue.esm.js:4075)
at Watcher.get (vue.esm.js:4488)
at new Watcher (vue.esm.js:4477)
function remapInternalIcon(vm, iconName) {
// Look for custom component in the configuration
var component = vm.$vuetify.icons.component; // <-- issue here when rendering for first time
if (iconName.startsWith('$')) {
// Get the target icon name
src/plugins/vuetify.ts
import Vue from "vue";
import Vuetify from "vuetify/lib";
import { UserVuetifyPreset } from "vuetify";
Vue.use(Vuetify);
export const options: UserVuetifyPreset = {
icons: {
iconfont: "mdiSvg"
}
};
export default new Vuetify(options);
Workaround for now is to set addon-essentials.docs to false. (Ref.
https://github.com/storybookjs/storybook/issues/7593)
file: .storybook/main.js
...
"addons": [
"#storybook/addon-links",
{
name: "#storybook/addon-essentials",
options: {
docs: false
}
}
],
...
If you don't want to disable addon-essentials.docs, you can add the following style in .storybook/preview-head.html
<style>
.sb-errordisplay {
display: none !important;
}
</style>
Another workaround without having to disable addon-essentials or adding any styles in the preview-head.html file you can import Vuetify at the top of your .stories.js (or .stories.ts) file like so e.g.
import vuetify from '#/plugins/vuetify'
then when you declare your storybook Template, pass in your vuetify object
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { YourComponent },
vuetify, // <-- Very important line
template: `<YourComponent />`
})
I found this workaround in this thread Cannot read property 'mobile' of undefined - Vue/Vuetify/Storybook

Transition using this.router.push with tracking end of animation in VUE CLI

I really hope for your help! I'm a beginner, this is my first experience in creating web applications.
I work with Vue Cli, there is a lottie element that should be animated by click (I did it), then I should go to the “other page” (I did it) But, how do I implement the transition to the page only after the animation finishes? Help! You are welcome! For animation I use Anime.js
<script>
import { translate } from '../js/animate'
export default {
methods: {
go () {
translate(this.$refs.square)
this.$router.push('Comprestore')
}
}
}
</script>
/vue
<template>
<div id="animate" v-on:click = "go" ref="square">
<app-lottie></app-lottie>
</div>
</template>
<style scoped>
</style>
import anime from 'animejs'
export function translate (element) {
anime({
targets: element,
translateX: 500
})
}
You can use complete callback to wait until the animation is completed.
Now your code may looks like this:
...
go () {
translate(this.$refs.square, () => {
this.$router.push('Comprestore')
})
}
...
And
export function translate (element, callback) {
anime({
targets: element,
translateX: 500,
complete: callback
})
}
I create the example here.
In the example I also use page transition by using Vue built-in transition to transition between page. See Enter/Leave & List Transitions and Transitions in Vue Router.

Using paperjs on a vuejs project based on SFC

I have a vuejs project based on single file components. I want to add a canvas and dinamically draw things with paperjs, based on my component data. What is the proper way to do it?
Self response. A working SFC.
<template>
<canvas resize id="main-canvas">{{circle_diameter}}</canvas>
</template>
<script>
import paper from 'paper'
export default {
data: () => ({ x: 20, y: 20 }),
props: ['circle_diameter'],
methods: {
updateDrawing() {
paper.setup(document.getElementById('main-canvas'))
// Now, draw your things based on component state.
const point = new paper.Point(this.x, this.y)
const circle = new paper.Path.Circle(point, this.circle_diameter/2)
circle.fillColor = 'grey'
circle.strokeColor = 'black'
},
},
updated() {
this.updateDrawing()
},
}
</script>
EDIT
Since paperjs will render outside vue scope, drawing is not reactive until you place {{circle_diameter}} into the canvas html tags. This way, you force Vue to call update() each time a prop changes.

V-model with datepicker input

Trying to build a component that works with daepicker and using v-model to bind the input value. But the input event does not appear to be firing and I can’t seem to figure out why. Here’s my component:
<div id="app">
<datepicker v-model="date"></datepicker>
</div>
Vue.component('datepicker', {
template: '<input type="text" class="form-control pull-right" placeholder="dd/mm/aaaa" autocomplete="off">',
mounted: function() {
$(this.$el).datepicker({
autoclose: true,
startView: 'years',
}).on('changeDate', function(e) {
this.$emit('input', e.format('dd/mm/yyyy'));
});
},
destroyed: function () {
$(this.$el).datepicker('destroy');
}
});
var app = new Vue({
el: '#app',
data: {
date: '2018-03-01'
}
})
In addition, the following error appears in the console:
Uncaught TypeError: this.$emit is not a function
If you're mixing jQuery and Vue (just a guess from the code fragment), you're mixing up your contexts. One (of many) ways to fix:
mounted: function() {
const self = this;
$(this.$el).datepicker({
autoclose: true,
startView: 'years',
}).on('changeDate', function(e) {
self.$emit('input', e.format('dd/mm/yyyy'));
});
},
I failed with jacky's answer, but thanks to https://github.com/Xelia, problem sovled (even in Vue 1.0, using ready life cycle instead of mounted)
Manually update vue data in datepicker changeDate event listener, like this
var app = new Vue({
el: '#app',
data: {
startDate: '',
},
mounted() {
$("#startDate").datepicker().on(
"changeDate", () => {this.startDate = $('#startDate').val()}
);
},
})
https://jsfiddle.net/3a2055ub/
And by the way, if you are working on legacy company project using ES5 function instead of ES6 fat arrow function. Need to bind this, which is vue instance, into the function. For example:
mounted() {
var self = this; // the vue instance
$("#startDate").datepicker().on(
"changeDate", function() {self.startDate = $('#startDate').val()}
);
},
Of course there are other ways to reach this goal, as this blog written by Jason Arnold
shows.
Reference: https://github.com/vuejs/vue/issues/4231
Probable related question: v-model not working with bootstrap datepicker