Vue: Register part of package as component - vue.js

I have got a wrapper around a package called vue-awesome-swiper, as follows:
Slider.vue
<template>
<div class="media-slider">
<slot :sliderSetting="sliderSettings" :name="name">
<swiper :options="sliderSettings[name]"
class="swiper"
v-if="slides"
ref="default-slider">
<slot name="slides" :slides="slides" :code="code">
<swiper-slide v-for="image in slides" :key="image" v-if="endpoint"
:style="{'background-image': `url('${image}')`}">
</swiper-slide>
</slot>
<div class="swiper-button-next swiper-button-white" slot="button-next"></div>
<div class="swiper-button-prev swiper-button-white" slot="button-prev"></div>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-scrollbar" slot="scrollbar"></div>
</swiper>
</slot>
</div>
</template>
<script>
import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
import 'swiper/css/swiper.css';
import Axios from '../../../../axiosConfig';
// https://github.surmon.me/vue-awesome-swiper/
export default {
components: { Swiper, SwiperSlide },
data: function() {
return {
code: null,
images: [],
defaults: {
'default-slider': {
loop: true,
loopedSlides: 5,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
},
scrollbar: {
el: '.swiper-scrollbar',
hide: true
}
}
},
sliderSettings: {}
}
},
props: {
endpoint: {
type: String,
default: null
},
settings: {
type: Object,
default: {}
},
theme: {},
name: {},
hash: {},
numberOfImages: {},
imageFormat: {},
vehicleId: {}
},
computed: {
slides() {
if (this.images.length) {
return this.images;
}
return [...Array(parseInt(this.numberOfImages))].map(
(_, i) => {
i++;
return this.imageFormat.replace('#', i);
}
);
}
}
}
</script>
As you can see I have got a slot within this component, however it must use an instance of SwiperSlide for it to work. I need to register this as a component to use it.
However this isn't working as expected:
Vue.component('slider', () => import('./components/Media/Slider/Index'));
Vue.component('slide', () => import('vue-awesome-swiper'));
How can I do this?
Edit
<slider class="app">
<template v-slot:slides="props">
<slide :style="{'background-image': `url('img-src/${props.code}/theme/slide-1.jpg')`}"></slide>
</template>
</slider>

An import like this import() is gonna import the default export of the package, what you have done here is that you have destructured the import with import { .. } from ".." that means it has an named export.
However try it like this
Vue.component('slider', () => import('./components/Media/Slider/Index'));
Vue.component('slide', async () => (await import('vue-awesome-swiper')).SwiperSlide);

Related

Use moment with Vue.js and return the date as UTC

I have a component that lists all the tasks.
When I create a task I want to show the date of creation on the added task and I want to list all the tasks.
The issue is all the tasks dates are converted to datetime now UTC.
<template>
<div class="tasks-wrapper">
<div class="tasks-header">
<h4>{{ $t('client.taskListingTitle') }}</h4>
<b-button variant="custom" #click="showAddTaskModal">{{ $t('client.addTask') }}</b-button>
</div>
<b-table
striped
hover
:items="tasks"
:fields="fields"
show-empty
:empty-text="$t('common.noResultsFound')">
<template #cell(createdOn)="data">
{{ formatDate(data.createdOn) }}
</template>
</b-table>
<AddTaskModal />
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import AddTaskModal from '#/components/modals/AddTaskModal'
import moment from 'moment'
export default {
name: 'TaskListing',
components: {
AddTaskModal
},
data () {
return {
tasks: [],
fields: [
{ key: 'createdOn', label: this.$t('tasks.tableFields.date'), formatter: 'formatDate' },
{ key: 'domain', label: this.$t('tasks.tableFields.task') },
{ key: 'comment', label: this.$t('tasks.tableFields.comment') },
{ key: 'status', label: this.$t('tasks.tableFields.status') }
]
}
},
computed: {
...mapGetters('users', ['user'])
},
methods: {
...mapActions('tasks', ['fetchTasks']),
...mapActions('users', ['fetchUserById']),
formatDate: function (date) {
return moment(date).utc(true).format('DD.MM.YYYY HH:mm')
},
showAddTaskModal () {
this.$bvModal.show('addTaskModal')
}
},
async mounted () {
const currUserId = this.$router.history.current.params.id
if (this.user || this.user.userId !== currUserId) {
await this.fetchUserById(currUserId)
}
if (this.user.clientNumber !== null) {
const filters = { clientReferenceNumber: { value: this.user.clientNumber } }
this.tasks = await this.fetchTasks({ filters })
}
}
}
</script>
If I delete this:
<template #cell(createdOn)="data">
{{ formatDate(data.createdOn) }}
</template>
the dates are displayed correctly on the task lists, however, when a task is added an Invalid Date is shown. I need to refresh the page of it works.
Any ideas?

How do I trigger an AJAX request when props is changed?

I have a this App component
<template>
<div id="app">
<Component1 #addItem="addItem" />
<Component2 :items="items" />
</div>
</template>
<script>
import Component1 from './components/Component1'
import Component2 from './components/Component2'
export default {
name: 'app',
components: { Component1, Component2 },
data: function () {
return {
items: [],
}
},
methods: function () {
addItem(item) {
items.push(item)
},
},
}
</script>
This is my Component2 component:
<template>
<div>
{{ ajax_data }}
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Component2',
props: ['items'],
data: function () {
return {
ajax_data: null
}
},
mounted () {
this.callAJAX()
},
methods: {
callAJAX() {
axios
.get('/api/get-some-data', {
params: {
items: items
}
})
.then((response) => {
this.ajax_data = response.data
})
},
},
}
</script>
I want to trigger the AJAX everytime I add an item. The problem with my code is since Component2 is already mounted and when an item is added the AJAX is not running. So then I added this hook:
updated () {
this.callAJAX()
},
The problem with this is its running an infinite loop.
Is there a proper way to do this?
You can simply detect if value change with a watcher
https://v2.vuejs.org/v2/guide/computed.html#Watchers
https://v2.vuejs.org/v2/api/#watch
in your case, you may set the deep property to true...

Vue pie chart show after a while (like show console with a warning)

I am trying to fill a pie chart on my vue application, I can correctly fill data into it, but the page didn't show immediately the pie chart, but after a while (like if a show console), and I got a warning in console :
vue.esm.js?efeb:628 [Vue warn]: Invalid prop: type check failed for
prop "chartData". Expected Object, got Null
found in
--->
at src/components/StastCard.vue
at src/App.vue
Here my code (Maybe there was another way to fill data, but I only succesfully done it in this way):
StastCard.vue:
<template>
<div>
<div class="container">
<div class="row">
<div class="col-sm">
<pie-chart :chartData="dataChart"></pie-chart>
</div>
<div class="col-sm"></div>
<div class="col-sm"></div>
</div>
</div>
</div>
</template>
<script>
import DataService from '#/services/DataService'
import PieChart from "#/plugins/PieChart.js";
export default {
name: 'StastCard',
props: {
username: {
type: String
}
},
components: {
PieChart
},
data: function() {
return {
dataChart: {
labels: ["Km", "KJ", "HB"],
datasets: [
{
label: "Data One",
backgroundColor: ["#41B883", "#E46651", "#00D8FF"],
data: [1, 10, 5]
}
]
},
}
},
methods: {
async addData() {
this.firstValue=DataService.getFirstValue()
this.secondValue=DataService.getSecondValue()
this.thirdValue=DataService.getThirdValue()
this.dataChart.labels.pop()
this.dataChart.labels.pop()
this.dataChart.labels.pop()
this.dataChart.labels.push(["Km"])
this.dataChart.labels.push(["KJ"])
this.dataChart.labels.push(["HB"])
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.push(this.firstValue)
this.dataChart.datasets[0].data.push(this.secondValue)
this.dataChart.datasets[0].data.push(this.thirdValue)
},
},
mounted() {
this.addData()
}
}
</script>
And here my PieChart.js
import { Pie, mixins } from 'vue-chartjs'
export default {
extends: Pie,
props: ['chartData', 'options'],
mounted() {
this.renderChart(this.chartData, this.options)
}
}
What am I doing wrong? Why my pie chart is not immediately displayed? Thank you
First, I think you might want to use reactiveProp to make your chart reactive with data changes.
Secondly, because of vue-chartjs will render child component before parent component, so you will get the Invalid prop warning. To fix it, you can change from mounted to created hook. You can find more information here.
import { Pie, mixins } from 'vue-chartjs'
export default {
extends: Pie,
mixins: [mixins.reactiveProp],
created() {
this.renderChart(this.chartData, {})
}
}
Lastly, you should assign chartData object to a new reference to make Vue reactive. An easy way is using JSON.parse(JSON.stringify())
methods: {
async addData() {
this.firstValue=DataService.getFirstValue()
this.secondValue=DataService.getSecondValue()
this.thirdValue=DataService.getThirdValue()
this.dataChart.labels.pop()
this.dataChart.labels.pop()
this.dataChart.labels.pop()
this.dataChart.labels.push(["Km"])
this.dataChart.labels.push(["KJ"])
this.dataChart.labels.push(["HB"])
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.pop()
this.dataChart.datasets[0].data.push(this.firstValue)
this.dataChart.datasets[0].data.push(this.secondValue)
this.dataChart.datasets[0].data.push(this.thirdValue)
this.dataChart = JSON.parse(JSON.stringify(this.dataChart))
},
},
I finally found a solution, I change the .js file with this:
import { Pie } from 'vue-chartjs'
export default {
extends: Pie,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
methods: {
renderpie() {
this.renderChart(this.chartdata, this.options)
}
},
mounted() {}
}
Here my view:
<template>
<div>
<div class="container">
<div class="row">
<div class="col-sm">
<pie-chart :chartData="dataChart"></pie-chart>
</div>
<div class="col-sm"></div>
<div class="col-sm"></div>
</div>
</div>
</div>
</template>
<script>
import DataService from '#/services/DataService'
import PieChart from "#/plugins/PieChart.js";
export default {
name: 'StastCard',
props: {
username: {
type: String
}
},
components: {
PieChart
},
data: function() {
return {
dataChart: {},
firstValue:'',
secondValue:'',
thirdValue:''
}
},
methods: {
addData() {
this.firstValue=DataService.getFirstValue()
this.secondValue=DataService.getSecondValue()
this.thirdValue=DataService.getThirdValue()
var hrate = []
this.heart_rate.forEach(el => {
hrate.push(el.rate)
})
this.dataChart = {
labels: ['Km', 'Kj', 'HB'],
datasets: [
{
label: 'Data One',
backgroundColor: ['#41B883', '#E46651', '#00D8FF'],
data: [this.firstValue,this.secondValue,this.thirdValue]
}
]
}
},
},
async created() {
await this.addData()
this.$refs.pie.renderpie()
}
}
</script>

problem with - TypeError: XXX is not a function

I am having an issue with calling a parent function:
Error in v-on handler: "TypeError: self.$parent.testAddCompontnet222 is not a function"
So i have setup a test function (method) in the following file called testAddCompontnet222()
parent file: PageAdd.vue
<template>
<b-container>
<b-container>
testVar2: (( {{ testVar2 }} ))
<b-button #click="testAddCompontnet222();">Add Test 2</b-button>
<SingleBlockTemplate v-if="componentTypeSelected == 1"></SingleBlockTemplate>
<TripleBlockTemplate v-if="componentTypeSelected == 2"></TripleBlockTemplate>
</b-container>
</b-container>
</template>
<script>
import axios from 'axios';
import SingleBlockTemplate from './component_templates/SingleBlockTemplate.vue';
import TripleBlockTemplate from './component_templates/TripleBlockTemplate.vue';
import ComponentAddForm from './ComponentAddForm.vue';
export default {
data(){
return {
title: 'Case Studies',
excerpt: 'some text here for reference',
slug: 'unique',
meta_title: 'title for search engines (should be the same as the page title)',
meta_description: 'meta descriptions for search engines',
meta_keywords: 'keywords',
order: '1',
status: '1',
showAddComponentForm: false,
error: false,
errors: {},
testVar2: '2',
newContentData: {},
componentTypeSelected: '2',
componentTypes: {},
componentList: {}
};
},
mounted: function () {
this.getComponentTypes();
//this.componentTypeToCreate =
},
methods: {
testAddCompontnet222(){
this.testVar2 = '222!';
console.log("test 222222!")
},
addPage(){
axios({
method: 'post',
url: this.$appAPI+'/twg-cms/page',
data: {
title: this.title,
excerpt: this.excerpt,
slug: this.slug,
meta_title: this.meta_title,
meta_description: this.meta_description,
meta_keywords: this.meta_keywords,
order: this.order,
status: this.status
}
}).then(response => {
console.log(response.data)
}).catch(e => {
console.log(e)
this.errors.push(e)
});
},
getComponentTypes(){
axios.get(this.$appAPI+`/twg-cms/component_types`)
.then((response) => {
this.componentTypes = response.data.data;
})
.catch(() => {
console.log('handle server error from here');
});
},
componentTypeOnChange(value){
//console.log(this.componentTypeSelected)
}
},
components: {
ComponentAddForm,
SingleBlockTemplate,
TripleBlockTemplate
}
}
</script>
I then attempt to call the function from a child element (imported file): TripleBlockTemplate.vue
I have tried using just this.$parent.testAddCompontnet222(); and as you can see below currently self.$parent.testAddCompontnet222();
But both return the same error. I have this working in exactly the same way on other components
<template>
<form autocomplete="off" #submit.prevent="addComponent" method="post">
<b-button #click="testAddCompontnet();">Add Test</b-button>
<p>This is a triple block component</p>
<ckeditor :editor="editor" v-model="content[0]" :config="editorConfig"></ckeditor>
<ckeditor :editor="editor" v-model="content[1]" :config="editorConfig"></ckeditor>
<ckeditor :editor="editor" v-model="content[2]" :config="editorConfig"></ckeditor>
<b-button #click="addComponent" variant="outline-primary">Save component</b-button>
</form>
</template>
<script>
import axios from 'axios';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export default {
data(){
return {<template>
<form autocomplete="off" #submit.prevent="addComponent" method="post">
<b-button #click="testAddCompontnet();">Add Test</b-button>
<p>This is a triple block component</p>
<ckeditor :editor="editor" v-model="content[0]" :config="editorConfig"></ckeditor>
<ckeditor :editor="editor" v-model="content[1]" :config="editorConfig"></ckeditor>
<ckeditor :editor="editor" v-model="content[2]" :config="editorConfig"></ckeditor>
<b-button #click="addComponent" variant="outline-primary">Save component</b-button>
</form>
</template>
<script>
import axios from 'axios';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export default {
data(){
return {
editor: ClassicEditor,
name: 'Name here',
class: 'Class here',
html_id: 'ID here',
content:[
'<div><h1>Title 1</h1><br /><p>some simple text here</p></div>',
'<div><h1>Title 2</h1><br /><p>some simple text here</p></div>',
'<div><h1>Title 3</h1><br /><p>some simple text here</p></div>'
],
editorConfig: {
// The configuration of the editor.
}
};
},
methods: {
testAddCompontnet(){
var self = this;
self.$parent.testAddCompontnet222();
console.log("test 222!")
},
addComponent(){
axios({
method: 'post',
url: this.$appAPI+'/twg-cms/component',
data: {
name: this.name,
content: JSON.stringify({content: this.content}),
class: this.class,
html_id: this.html_id
}
}).then(response => {
console.log(response.data)
}).catch(e => {
console.log(e)
this.errors.push(e)
});
}
}
}
</script>
editor: ClassicEditor,
name: 'Name here',
class: 'Class here',
html_id: 'ID here',
content:[
'<div><h1>Title 1</h1><br /><p>some simple text here</p></div>',
'<div><h1>Title 2</h1><br /><p>some simple text here</p></div>',
'<div><h1>Title 3</h1><br /><p>some simple text here</p></div>'
],
editorConfig: {
// The configuration of the editor.
}
};
},
methods: {
testAddCompontnet(){
var self = this;
self.$parent.testAddCompontnet222();
console.log("test 222!")
},
addComponent(){
axios({
method: 'post',
url: this.$appAPI+'/twg-cms/component',
data: {
name: this.name,
content: JSON.stringify({content: this.content}),
class: this.class,
html_id: this.html_id
}
}).then(response => {
console.log(response.data)
}).catch(e => {
console.log(e)
this.errors.push(e)
});
}
}
}
</script>
Finally here is a working method which i am currently not using...
The following code, would allow me to use the same/similar code to update/change the parent variable testVar1 to update it's parent: ComponentAddForm.vue below
testAddCompontnet(){
var self = this;
self.$parent.testVar1 = '11111! test;
console.log("test 222!")
},
ComponentAddForm.vue:
<template>
<b-container>
testVar1: (( {{ testVar1 }} ))
<b-button #click="testAddCompontnet222();">Add Test 2</b-button>
<SingleBlockTemplate v-if="this.componentTemplateId == 1"></SingleBlockTemplate>
<TripleBlockTemplate v-if="this.componentTemplateId == 2"></TripleBlockTemplate>
</b-container>
</template>
<script>
import axios from 'axios';
import SingleBlockTemplate from './component_templates/SingleBlockTemplate.vue';
import TripleBlockTemplate from './component_templates/TripleBlockTemplate.vue';
export default {
props: ['componentTemplateId'],
data(){
return {
name: 'Case Studies',
testVar1: '1'
};
},
mounted: function () {
this.showComponentTemplate();
},
methods: {
testAddCompontnet222(){
this.$parent.testVar2 = '222!';
console.log("we made it here <--------");
},
showComponentTemplate(){
if(this.componentTemplateId === '1'){
console.log('test 1')
}
if(this.componentTemplateId === '2'){
console.log('test 2')
}
}
},
components: {
SingleBlockTemplate,
TripleBlockTemplate
}
}
</script>

Call function from parent template in vue.js

I have a button in parent component template like below.
<template>
<div class="data_table">
<button class="mini ui button" #click="show">
</div>
</template>
This show() is kept in child component like below
<script>
export default {
data:
function () {
return {
value: this.active1
}
},
props: {
active1: true
},
methods: {
show () {
this.active1 = true
}
},
}
</script>
How can I call that show() function ?
I am using vue-cli.
Thanks
Child Component
<template>
<div class="data_table">
<button class="mini ui button" #click="show">
</div>
</template>
data: => ({
value: this.active1
}),
props: {
active1: {
type: Boolean
}
},
methods: {
show () {
this.$emit('someEventName')
}
}
Parent Component
<template>
<child-component
:active1="booleanValue"
#someEventName="show"
/>
</template>
data: => ({
booleanValue: false
}),
method: {
show () {
this.booleanValue = true
}
}