Import jquery plugin in Vue component - vue.js

I'm trying to import an external jQuery plugin in a Vuejs component.
The plugin is nested.js
How can I do?
Thanks

You can import in script the plugin and use it in your functions, I will give you an example of datepicker which is a jquery based plugin.
<template>
<div class="input-group date">
<input type="text" class="form-control datepicker" :name="name" :value="value" #keyup.enter="validate" #blur="validate">
</div>
</template>
<script>
import "bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css"
import "bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"
import Moment from 'moment'
export default {
props: {
value: String,
name: String,
orientation: {
type: String,
default: "top"
}
},
data() {
return {}
},
mounted() {
var vm = this;
$(this.$el).find(".datepicker").datepicker({
language: this.$store.state.currentLanguage,
format: "dd/mm/yyyy",
autoclose: true,
orientation: vm.orientation
}).on("show", () => { do what ever you want }
}
</script>
Hope this will help.

Maybe you can consider a directive for that.
First load jquery and nested.js.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery.nested/1.01/jquery.nested.min.js"></script>
Then create a new directive.
Vue.directive('nested', function(el, binding) {
$(el).nested(binding.value)
})
Example usage:
<div v-nested="nestedJsOptions">
...
</div>
In your component:
data: {
return {
nestedJsOptions: {
minWidth: 100,
gutter: 10,
// ..
}
}
}

Related

How to use v-model on component in vue 3 script setup

I want to add a v-model on a component but I got this warning:
[Vue warn]: Component emitted event "input" but it is neither declared in the emits option nor as an "onInput" prop.
Here is my code:
// Parent.vue
<template>
<h2>V-Model Parent</h2>
<Child v-model="name" label="Name" />
<p>{{ name }}</p>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const name = ref('')
</script>
// Child.vue
<template>
<input
class="input"
type="text"
:placeholder="props.label"
:value="props.value"
v-on:input="updateValue($event.target.value)"
/>
</template>
<script setup>
import { defineProps, defineEmit } from 'vue'
const props = defineProps({
label: String,
value: String
})
const emit = defineEmit('input')
function updateValue(value) {
emit('input', value)
}
</script>
I was trying to reproduce this tutorial but I'am stuck and got no idea what I am missing.
I want to display {{ name }} in the Parent.vue component. Do you got an idea how to solve this?
In vue 3 value prop has been changed to modelValue and the emitted event input to update:modelValue:
// Child.vue
<template>
<input
class="input"
type="text"
:placeholder="props.label"
:value="props.modelValue"
v-on:input="updateValue($event.target.value)"
/>
</template>
<script setup>
const props = defineProps({
modelValue: String
})
const emit = defineEmits(['update:modelValue'])
function updateValue(value) {
emit('update:modelValue', value)
}
</script>
I like to use with computed as well
<template>
<div>
<input v-model="model">
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: {
type: [String, Number],
default: ''
}
})
const emit = defineEmits(['update:modelValue'])
const model = computed({
get () {
return props.modelValue
},
set (value) {
return emit('update:modelValue', value)
}
})
</script>
I have the similar issues and finally I got it work. Here are one solution for one or multiple checkbox for Vue 3 and TypeScript.
ref: https://v2.vuejs.org/v2/guide/forms.html?redirect=true#Checkbox
solution : for one or multiple checkbox
CheckBox Component:
<template>
<input
type="checkbox"
:value="inputValue"
:disabled="isDisabled"
v-model="model"
:class="[defaultClass, inputClass, checkboxClass]"
/>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
export default defineComponent({
components: {},
props: {
inputValue: {
type: String,
required: false,
default: '',
},
modelValue: {
type: [Object, Boolean] as PropType<String[] | Boolean>,
required: false,
default: (() => ({})) || false,
},
isDisabled: {
type: Boolean,
required: false,
default: false,
},
checkboxClass: {
type: String,
required: false,
default: '',
},
},
data() {
return {
defaultClass: 'h-4 w-4 rounded text-primary shadow-sm',
};
},
emits: ['update:modelValue'],
computed: {
model: {
get() {
return this.modelValue;
},
set(value) {
this.$emit('update:modelValue', value);
},
},
inputClass() {
if (this.isDisabled) {
return 'bg-dark-17 border-dark-13';
}
return 'bg-dark-23 border-dark-10 hover:bg-dark-25 focus:border-primary';
},
},
});
</script>
import CheckBox and use it
import CheckBox in other components;
<div>
<div v-for="(option, index) in options" :key="index">
<div
class="flex items-center justify-between p-6 py-4 border-b border-b-dark-13"
>
<div class="w-10">
<Checkbox :inputValue="option.name" v-model="selectedOptions" />
</div>
</div>
</div>
</div>
data() {
return {
selectedOptions: [],
};
},

How to get component data? How to access the components from the outside?

I derive the component:
<my-component> </my-component>
The question is how to get the properties of this particular component, knowing only its tag "my-component"?
A more detailed description of the problem:
Using the vue-cli-service build --target wc --name my-component my-component.vue command, I compile in js file
Then I connect this script in the header of the site.
Then I use the component
But how to get the properties of this component now and generally how to access this component? How to get the input field value in this component?
Sorry, I probably didn’t explain it well.
I need something like this:
<my-component id="my-component"> </my-component>
<script>
let inputValue = $("#my-component").find("input").val();//but this not work
</script>
Or
<script>
let props = <my-component></my-component>// this component props
</script>
In the my-component.vue file, this code:
<template>
<input :placeholder="test" type="text" name="test" value="">
</template>
<script>
export default {
name: 'MyInputComponent',
props: {
placeholder: {
type: String,
default: "00"
}
},
data () {
return {
}
},
}
</script>
usage
<template>
<input :placeholder="placeholder" type="text" #input="emitInputValue">
</template>
<script>
export default {
name: 'MyInputComponent',
props: {
placeholder: {
type: String,
default: "00"
}
},
methods: {
emitInputValue ($event) {
this.$emit('input', $event.target.value)
}
}
}
</script>
get value
<my-component #input"getValue"> </my-component>
methods: {
getValue (payload) {
console.log(payload)
}
}
<template>
<input :placeholder="test" :id="id" type="text" name="test" value="">
</template>
<script>
export default {
name: 'MyInputComponent',
props: {
placeholder: {
type: String,
default: "00"
},
id: {
type: String
}
},
data () {
return {
}
},
}
</script>
Now your id would be available and you can do whatever you want.
Only one suggestion i would like to give is: when you are using vue.js then try avoiding jquery for getting input value. there are many ways in vue.js itself you can get input text value.
Let me know if you need something else

VueJS display dynamic modal component

I have posts and replys s.t. replies belong to posts via the attribute reply.posts_id.
I am attempting to show the reply form as a modal for the user to enter a reply. However, I want to create a generic Modal component that I can use everywhere with content that is specified in another component built for a specific context.
Reply to post is the first place I woul like this to work.
Currently, the Vuex correctly returns Modal visible:true when the reply button is clicked, but the modal does not render and I get the error message showing that the Modal component is not found:
Unknown custom element: <ModalReplyForm> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I am using vuex to manage the visibility of the modal. Here are the relevant files:
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
...
Vue.use(Vuex)
export default new Vuex.Store({
state: {
status: '',
...
modalVisible: false,
modalComponent: null
},
mutations: {
...
showModal(state, componentName) {
console.log('showing the modal')
state.modalVisible = true;
state.modalComponent = componentName;
},
hideModal(state) {
console.log('hiding the modal')
state.modalVisible = false;
}
},
actions: {
...
}
},
getters: {
isAuthenticated: state => !!state.user,
authStatus: state => state.status,
user: state => state.user,
token: state => state.token,
posts: state => {
return state.posts;
}
...
}
})
App.vue
<template>
<div id="app">
<app-modal></app-modal>
<NavigationBar />
<div class="container mt-20">
<router-view />
</div>
<vue-snotify></vue-snotify>
</div>
</template>
<script>
import AppModal from '#/components/global/AppModal';
import NavigationBar from '#/components/layout/NavigationBar'
export default {
name: "App",
components: {
AppModal,
NavigationBar
}
};
</script>
<style>
body {
background-color: #f7f7f7;
}
.is-danger {
color: #9f3a38;
}
</style>
Post.vue (houses the button to call the reply modal):
<template>
<div class="row ui dividing header news">
<!-- Label -->
<div class="m-1 col-md-2 ui image justify-content-center align-self-center">
<img v-if="post.avatar_url" :src="post.avatar_url" class="mini rounded"/>
<v-gravatar v-else :email="post.email" class="mini thumbnail rounded image rounded-circle z-depth-1-half"/>
</div>
<!-- Excerpt -->
<div class="col-md-9 excerpt">
...
<!-- Feed footer -->
<div class="feed-footer row">
<div class="small"> {{ post.created_at | timeAgo }}</div>
<button type="button" flat color="green" #click="showModal('ModalReplyForm')">
<i class="fa fa-reply" ></i>
...
<div v-show="postOwner(post)" class="">
<button type="button" flat color="grey" #click="deletePost(post.id)">
<i class="fa fa-trash " ></i>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
import PostsService from '../../services/PostsService'
import RepliesService from '../../services/RepliesService'
import Replies from '#/components/Reply/Replies'
import ReplyForm from '#/components/Reply/ReplyForm'
export default {
name: "Post",
props: {
post: {
type: Object,
required: true
}
},
components: {
Replies,
ReplyForm
},
computed: {
me() {
return this.$store.getters.user
}
},
methods: {
...mapMutations(['showModal']),
...
}
};
</script>
AppModal.vue - generic Modal component
<template>
<div class="c-appModal">
<div class="c-appModal__overlay" v-if="visible"></div>
<div class="c-appModal__content" v-if="visible" #click.self="hideModal"></div>
<div class="c-appModal__innerContent">
<component :is="component"></component>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';
export default {
name: 'AppModal',
data() {
return {
component: null
}
},
computed: {
...mapState({
visible: 'modalVisible',
modalComponent: 'modalComponent'
}),
},
methods: {
...mapMutations(['hideModal'])
},
watch: {
modalComponent(componentName) {
if (!componentName) return;
Vue.component(componentName, () => import(`#/components/modals/${componentName}`));
this.component = componentName;
}
},
created() {
const escapeHandler = (e) => {
if (e.key === 'Escape' && this.visible) {
this.hideModal();
}
};
document.addEventListener('keydown', escapeHandler);
this.$once('hook:destroyed', () => {
document.removeEventListener('keydown', escapeHandler);
});
},
};
</script>
ModalReplyForm - specific reply modal content
<template>
<div>
<div class="c-modalReply">
<div>
<label for="reply">Your comment</label>
<div class="field">
<textarea name="reply" v-model="reply" rows="2" placeholder="Compose reply"></textarea>
</div>
</div>
<button class="c-modalReply__cancel" #click="hideModal">Cancel</button>
<button class="c-modalReply__post" :disabled="!isFormValid" #click="createReply">Reply</button>
</div>
</div>
</template>
<script>
import RepliesService from '#/services/RepliesService'
import { mapMutations } from 'vuex';
export default {
name: "ModalReplyForm",
// props: {
// post: {
// type: Object,
// required: true
// }
// },
data() {
return {
reply: ""
};
},
computed: {
isFormValid() {
return !!this.reply;
},
currentGroup() {
return this.$store.getters.currentPost;
}
},
methods: {
...mapMutations([
'hideModal'
]),
async createReply () {
let result = await RepliesService.addReply({
reply: {
body: this.reply,
postId: this.post.id
}
});
this.$emit("reply-created");
this.hideModal();
}
}
};
</script>
Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
This message says that you never imported/defined ModalReplyForm, which you have not.
In my own generic modal, I ended up having to import all the components that might appear within the modal itself.
If you add a:
import ModalReportForm from ...
and a:
components: {
ModalReplyForm
}
to AppModal.vue, the modal should then do what you expect.

How to share ajax results between two components with the first one using the second?

First of all, I'm a beginner with VueJS, so I may presenting you a bunch of non-sens. :-) I read all the beginner doc, but I'm still stuck for this case.
I have 2 template component managed by a functionnal component:
<template>
<h2>PageSpeed performance score: {{ results.score }}.</h2>
</template>
The second one, using the first one (the first one is needed to be used elsewhere to display score only:
<template>
<div>
<template v-if="results">
<hosting-performance-score :results="results"/>
<div
v-for="(result, rule) in results.rules"
v-if="result.ruleImpact > 0"
:key="rule"
class="panel panel-default"
>
<div class="panel-heading">{{ result.localizedRuleName }}</div>
<div class="panel-body">
<p>
{{ result.summary.format }}
<b>{{ result.ruleImpact }}</b>
</p>
</div>
</div>
</template>
<i
v-else
class="fa fa-spin fa-spinner"
/>
</div>
</template>
<script>
import HostingPerformanceScore from './HostingPerformanceScore';
export default {
components: {
HostingPerformanceScore,
},
};
</script>
And then, the functional one with the AJAX logic:
<script>
import axios from 'axios';
import axiosRetry from 'axios-retry';
import HostingPerformanceScore from './HostingPerformanceScore';
import HostingPerformancePage from './HostingPerformancePage';
axiosRetry(axios);
export default {
functional: true,
props: {
scoreOnly: {
default: false,
type: Boolean,
},
slug: {
required: true,
type: String,
},
},
data: () => ({
results: null,
}),
created() {
axios.get(Routing.generate('hosting_performance_pagespeed', {
slug: this.slug,
})).then((response) => {
this.results = {
rules: Object.entries(response.data.formattedResults.ruleResults).map((entry) => {
const result = entry[1];
result.ruleName = entry[0];
return result;
}).sort((result1, result2) => result1.ruleImpact < result2.ruleImpact),
score: response.data.ruleGroups.SPEED.score,
};
});
},
render: (createElement, context) => {
return createElement(
context.props.scoreOnly ? HostingPerformanceScore : HostingPerformancePage,
context.data,
context.children
);
},
};
</script>
The issue is: I can't access the result and I don't know how to pass it properly: Property or method "results" is not defined on the instance but referenced during render.
Or maybe functional components are not designed for this, but I don't know how to achieve it otherway. How would you do it?
Thanks! :-)
You appear to have this a little backwards in terms of which components can be functional and which not.
Since your HostingPerformanceScore and HostingPerformancePage components are really only rendering data, they can be functional components by just rendering props they accept.
Your other component has to maintain state, and so it cannot be a functional component.
I put together an example of how this might work.
HostingPerformanceScore
<template functional>
<h2 v-if="props.results">
PageSpeed performance score: {{ props.results.score }}.
</h2>
</template>
HostingPerformancePage
<template functional>
<div>
<h2>Hosting Performance Page</h2>
<HostingPerformanceScore :results="props.results"/>
</div>
</template>
<script>
import HostingPerformanceScore from "./HostingPerformanceScore.vue";
export default {
components: {
HostingPerformanceScore
}
};
</script>
PerformanceResults.vue
<template>
<HostingPerformanceScore :results="results" v-if="scoreOnly" />
<HostingPerformancePage :results="results" v-else />
</template>
<script>
import HostingPerformancePage from "./HostingPerformancePage.vue";
import HostingPerformanceScore from "./HostingPerformanceScore.vue";
export default {
props: {
scoreOnly: Boolean
},
data() {
return {
results: null
};
},
created() {
setTimeout(() => {
this.results = {
score: Math.random()
};
}, 1000);
},
components: {
HostingPerformancePage,
HostingPerformanceScore
}
};
</script>
And here is a working example.

How to use same template on different components in vue js?

Currently I am using as
<template> ... </template>
<script src="test1.js"> </script>
Where all my business logics are written in test1.js. Now I need to use test2.js with same template. I need to reuse the template with different component.
My current code goes like this...
common.vue
<template>
<div>
{{ page }}
</div>
<template>
<script src="../scripts/test1.js"></script>
Where in test1.js
export default {
name: 'home',
components: {
test: test
},
data() {
return {
page: "test1",
}
}
}
But also i need to use common.vue in my test2.js. Which i am not able to import both the .js seperately.
In angular we can write the fallowing late bindig which binds .html and .js(in ui.router)
.state('home', {
url:'/',
templateUrl: 'templates/home.html',
controller: 'HomeController'
})
Is there something similar to this?
You can share the template through the id attribute.
Vue.component('my-comp1', {
template: '#generic',
data () {
return {
text: 'I am component 1'
}
}
})
Vue.component('my-comp2', {
template: '#generic',
data () {
return {
text: 'I am component 2'
}
}
})
new Vue({
el: '#app'
})
<div id="app">
<my-comp1></my-comp1>
<my-comp2></my-comp2>
</div>
<template id="generic">
<div>
<p>{{ text }}</p>
</div>
</template>
<script src="https://unpkg.com/vue"></script>