Method not executing inside another method using Vue.js event - vuejs2

I'm learning how to use vue.js to pull movie information and display it.
Inside the main application mc I have a method getMovie which isn't being called when another method updateMovie is called. The updateMovie method is called from the event 'switch' which is emitted by a child component details-card
I can see that the title on my application gets changed and the method updateMovie is working if you click on a director and then a movie under that director. The input field also changes value. Why won't the getMovie work?
var mc = new Vue({
el: "#movie-card",
data: {
title: '',
valid: false,
loading: false,
error: false,
mc: {},
directorArray: [],
actorArray: [],
},
computed: {
checkMulti: function(item) {
if (Object.keys(item).length <= 1) {
return false;
} else {
return true;
}
}
},
methods: {
getMovie: function() {
this.cm = {};
console.log("getMovie called")
if (this.title !== "") {
this.loading = true;
this.error = false;
searchString = 'https://www.omdbapi.com/?t=' + this.title;
var that = this;
axios.get(searchString)
.then(function(res) {
that.cm = res.data;
that.directorArray = res.data.Director.trim().split(/\s*,\s*/);
that.actorArray = res.data.Actors.trim().split(/\s*,\s*/);
that.valid = true;
that.loading = false;
})
.catch(function(error) {
console.log(error.message);
that.loading = false;
that.error = true;
})
}
},
updateMovie: function(movie) {
console.log(movie);
this.title = movie;
this.getMovie;
}
}
})
Vue.component('details-card', {
props: [
'name',
'title'
],
template: `
<div>
<a href=""
#click="handleShowDetails($event)"
>
{{ name }}
</a>
<div v-if="visible" class="detailsCard">
<h3 class="removeTopMargin">{{ name }}</h3>
<img :src="picUrl">
<h4>Known for</h4>
<p v-for="movie in knownForArray">
<a href=""
#click="switchMovie(movie.original_title, $event)"
>{{ movie.original_title }}</a>
</p>
</div>
</div>
`,
data: function() {
return {
picUrl: "",
knownForArray: [],
visible: false
}
},
methods: {
handleShowDetails: function($event) {
this.visible = !this.visible;
this.callPic($event);
},
switchMovie( movie , $event) {
if ($event) $event.preventDefault();
console.log("switching to...", movie);
this.$emit('switch', movie);
},
callPic: function(event) {
if (event) event.preventDefault();
let that = this;
let searchString = "https://api.themoviedb.org/3/search/person?api_key=9b8f2bdd1eaf20c57554e6d25e0823a2&language=en-US&query=" + this.name + "&page=1&include_adult=false";
if (!this.picUrl) { //only load if empty
axios.get(searchString)
.then(function(res) {
let profilePath = res.data.results[0].profile_path;
if (profilePath === null) {
that.picUrl = "http://placehold.it/150x200"
} else {
that.picUrl = 'https://image.tmdb.org/t/p/w150/' + profilePath;
}
that.personPic = profilePath;
that.knownForArray = res.data.results[0].known_for;
}).catch(function(err){
console.log(err);
})
}
},
hideDetails: function () {
this.visible= false;
}
}
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
*:focus {
outline: none;
}
ul {
padding-left: 1em;
}
.loading {
margin: auto;
max-width: 450px;
}
.details {
display:block;
margin: 1em auto;
text-align: center;
}
.searchBar {
padding: .5em;
-webkit-box-shadow: 0px 2px 16px 2px rgba(168,168,168,0.45);
-moz-box-shadow: 0px 2px 16px 2px rgba(168,168,168,0.45);
box-shadow: 0px 2px 16px 2px rgba(168,168,168,0.45);
text-align: center;
}
.searchBar input {
padding: .5em;
width: 300px;
font-size: 1em;
border: none;
border-bottom: 1px solid gray;
}
.searchBar button {
padding: .2em;
border: 2px solid gray;
border-radius: 8px;
background: white;
font-size: 1em;
color:#333;
}
img {
display: block;
margin: auto;
width: 150px;
padding-bottom: .33em;
}
.card {
max-width: 500px;
margin: 2em auto;
-webkit-box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
-moz-box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
padding: 2em;
}
.detailsCard {
-webkit-box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
-moz-box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
box-shadow: 0px 6px 16px 2px rgba(168,168,168,0.45);
padding: 1em;
}
/* ======= Typography */
html {font-size: 1em;}
body {
background-color: white;
font-family: roboto;
font-weight: 400;
line-height: 1.45;
color: #333;
}
p {margin-bottom: 1.3em;}
h1, h2, h3, h4 {
margin: 1.414em 0 0.5em;
font-weight: inherit;
line-height: 1.2;
}
h2, h3, h4 {
border-bottom: 1px solid gray;
}
h1 {
margin-top: 0;
font-size: 3.998em;
text-align: center;
}
h2 {font-size: 2.827em;}
h3 {font-size: 1.999em;}
h4 {font-size: 1.414em;}
small, .font_small {font-size: 0.707em;}
.removeTopMargin {
margin-top: .5em;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="movie-card">
<div class="searchBar">
<input type="text" ref="input" v-model="title" placeholder="Enter a movie title here..." v-on:keyup.enter="getMovie">
<button type="submit" #click="getMovie">Search</button>
</div>
<div class="loading" v-if="loading">
<BR><BR>
<h1>Loading...</h1>
</div>
<div class="loading" v-if="error">
<BR><BR>
<h1>Something went wrong!</h1>
</div>
<div class="card" v-if="valid && !loading">
<h1> {{ cm.Title }}</h1>
<div v-if="!(cm.Poster === 'N/A')" class="poster">
<img v-bind:src="cm.Poster">
</div>
<div class="details">
<p>{{ cm.Year + " – " + cm.Rated + " – " + cm.Runtime }}</p>
</div>
<p>{{ cm.Plot }}</p>
<div class="directors" v-if="cm.Director">
<h3 v-if="(directorArray.length > 1)">Director</h3>
<h3 v-else>Director</h3>
<p>
<p v-for="(director, index) in directorArray">
<details-card :name="director" v-on:switch="updateMovie"></details-card>
</p>
</p>
</div>
<div class="actors" v-if="cm.Actors">
<h3 v-if="actorArray.length > 1">Actors</h3>
<h3 v-else>Actor</h3>
<p>
<p v-for="(actor, index) in actorArray">
<details-card :name="actor"></details-card>
</p>
</p>
</div>
<div class="ratings" v-if="cm.Ratings">
<h3>Ratings</h3>
<ul>
<li v-for="rating in cm.Ratings">{{ rating.Source }}: {{ rating.Value }}</li>
</ul>
</div>
</div>
</div>

Related

Migrating the code of vue2.x to vue3.x, encountered Unexpected mutation of "task" prop in the v-model module

I used the Composition API when migrating the project from vue2.x to vue3.0, but the page does not work properly, in vue3.0
The environment prompts me to have an "Unexpected mutation of "task" prop" error, I want to know how to write the correct compos API
This is Vue2.x code
<template>
<transition name="fade">
<div class="task" v-if="!task.deleted">
<input :id="id" type="checkbox" v-model="task.done" />
<label :for="id">{{ task.title }}</label>
<transition name="fade">
<span
class="task_delete"
v-show="task.done"
#click="deleteTask({ task })"
>
<i class="fa fa-trash"></i>
</span>
</transition>
</div>
</transition>
</template>
<script>
import { mapMutations } from "vuex";
let GID = 1;
export default {
props: {
task: {
type: Object,
required: true,
},
},
data() {
return {
id: `task-${GID++}`,
};
},
methods: {
...mapMutations(["deleteTask"]),
},
};
</script>
<style lang="scss">
.task {
display: flex;
padding: 12px 0;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.task input {
display: none;
}
.task label {
flex: 1;
line-height: 20px;
}
.task label:before,
.task label:after {
content: "";
display: inline-block;
margin-right: 20px;
margin-top: 1px;
width: 14px;
height: 14px;
vertical-align: top;
}
.task label:before {
border: 1px solid #ccc;
border-radius: 2px;
background-color: white;
}
.task label:after {
content: "\f00c";
position: relative;
display: none;
z-index: 10;
margin-right: -16px;
width: 10px;
height: 10px;
padding: 3px;
border-radius: 2px;
font: normal normal normal 10px/1 FontAwesome;
color: white;
background-color: #ccc;
float: left;
}
.task input:checked + label:after {
display: inline-block;
}
.task_delete {
padding: 0 10px;
color: #ccc;
font-size: 16px;
}
.fade-leave-to,
.fade-enter {
opacity: 0;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
</style>
This is Vue3.0 code use Composition API, but not work
<template>
<transition name="fade">
<div class="task" v-if="!data.task.deleted">
<input :id="id" type="checkbox" v-model="data.task.done" />
<label :for="id">{{ data.task.title }}</label>
<transition name="fade">
<span
class="task_delete"
v-show="data.task.done"
#click="deleteTask({ task })"
>
<i class="fa fa-trash"></i>
</span>
</transition>
</div>
</transition>
</template>
<script>
import { reactive } from "vue";
import { mapMutations } from "vuex";
let GID = 1;
export default {
name: "Task",
props: {
task: {
type: Object,
required: true,
},
},
setup(props) {
const data = reactive({
task: props.task,
id: `task-${GID++}`,
});
return { data };
},
methods: {
...mapMutations(["deleteTask"]),
},
};
</script>
<style lang="scss">
.task {
display: flex;
padding: 12px 0;
border-bottom: 1px solid #eee;
font-size: 14px;
}
.task input {
display: none;
}
.task label {
flex: 1;
line-height: 20px;
}
.task label:before,
.task label:after {
content: "";
display: inline-block;
margin-right: 20px;
margin-top: 1px;
width: 14px;
height: 14px;
vertical-align: top;
}
.task label:before {
border: 1px solid #ccc;
border-radius: 2px;
background-color: white;
}
.task label:after {
content: "\f00c";
position: relative;
display: none;
z-index: 10;
margin-right: -16px;
width: 10px;
height: 10px;
padding: 3px;
border-radius: 2px;
font: normal normal normal 10px/1 FontAwesome;
color: white;
background-color: #ccc;
float: left;
}
.task input:checked + label:after {
display: inline-block;
}
.task_delete {
padding: 0 10px;
color: #ccc;
font-size: 16px;
}
.fade-leave-to,
.fade-enter {
opacity: 0;
}
.fade-enter-to,
.fade-leave {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
</style>
I think the problem is you're using v-model for props on checkbox, it will change props value directly and vue not allow it. Try update props value manual by emit event. And u dont need to use props with reactive in child component, but need to reactive that props in parent component
<input :id="id" type="checkbox" v-value="task.done" #change="updateCheckbox($event)")/>
In script:
export default {
name: "Task",
props: {
task: {
type: Object,
required: true,
},
},
emits: ['updateCheckbox'],
setup(props) {
const data = reactive({
id: `task-${GID++}`,
});
return { data };
},
methods: {
updateCheckbox(e) {
this.$emit('updateCheckbox', e.target.value)
}
},
};

vue js pagination with simple vuejs plugin

I am trying to create a paginated flexbox using data from an API but struggle with it although I read the setup step-by step.
Here is my code without styles:
<template>
<div id="app">
<paginate name="articles" :list="articles" class="paginate-list">
<li v-for="item in paginated('articles')">
{{ item }}
</li>
</paginate>
<paginate-links for="items" :show-step-links="true"></paginate-links>
<paginate-links for="items" :limit="2" :show-step-links="true">
</paginate-links>
<paginate-links for="items" :simple="{ next: 'Next »', prev: '« Back' }">
</paginate-links>
</div>
</template>
<script>
import axios from 'axios';
import VuePaginate from 'vue-paginate'
export default {
data() {
return {
items:[],
paginate: [articles]
}
},
created() {
axios.get(https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5)
.then(response => {
this.items = response.data
})
}
}
</script>
Step 1: Install npm install --save vue-paginate
Step 2: Import vue-paginate component in main.js
import VuePaginate from "vue-paginate";
Vue.use(VuePaginate);
Step 3: HTML template will be like,
<template>
<div id="app">
<paginate ref="paginator" class="flex-container" name="items" :list="items">
<li
v-for="(item, index) in paginated('items')"
:key="index"
class="flex-item">
<h4>{{ item.pub_date }}, {{ item.title }}</h4>
<img :src="item.image && item.image.file" />
<div class="downloads">
<span
v-for="downloadable in item.downloadable.filter(
(d) => !!d.document_en
)"
:key="downloadable.id">
<a :href="downloadable.document_en.file">Download</a>
</span>
</div>
</li>
</paginate>
<paginate-links
for="items"
:limit="2"
:show-step-links="true"></paginate-links>
</div>
</template>
Step 4: Your component script like
<script>
import axios from "axios";
export default {
data() {
return {
items: [],
paginate: ["items"],
};
},
created() {
this.loadPressRelease();
},
methods: {
loadPressRelease() {
axios.get(`https://zbeta2.mykuwaitnet.net/backend/en/api/v2/media-center/press-release/?page_size=61&type=5`)
.then((response) => {
this.items = response.data.results;
});
}
}
};
</script>
Step 5: CSS style
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
ul.flex-container {
padding: 0;
margin: 0;
list-style-type: none;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-direction: row wrap;
flex-wrap: wrap;
justify-content: space-around;
}
li img {
display: initial;
height: 100px;
}
.flex-item {
background: tomato;
width: calc(100% / 3.5);
padding: 5px;
height: auto;
margin-top: 10px;
color: white;
font-weight: bold;
text-align: center;
}
.downloads {
margin-top: 10px;
}
ul.paginate-links.items li {
display: inline-block;
margin: 5px;
}
ul.paginate-links.items a {
cursor: pointer;
}
ul.paginate-links.items li.active a {
font-weight: bold;
}
ul.paginate-links.items li.next:before {
content: " | ";
margin-right: 13px;
color: #ddd;
}
ul.paginate-links.items li.disabled a {
color: #ccc;
cursor: no-drop;
}
</style>
DEMO Link

vue.js, vuetify scroll event not firing when using css scroll snap

UPDATE dropped this approach and went with vue-awesome-swiper script
I"m been stuck on this for days. Basically I want to use css scroll snap and I want to monitor scroll also.
In this basic example with just javascript it works fine scroll event fires and div snaps with css. The other pen below with vue.js does not and that is my problem. Losing hair about this... any help appreciated!
https://codepen.io/travis-pancakes/pen/pGYOZK?editors=0011
var i = 0;
function Onscrollfnction(event) { document.getElementById("demo").innerHTML = i;
i = i + 1;
};
/* setup */
html, body, .holster {
height: 100%;
}
.holster {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: column nowrap;
font-family: monospace;
}
.container {
display: flex;
overflow: auto;
outline: 1px dashed lightgray;
flex: none;
}
.container.x {
width: 100%;
height: 128px;
flex-flow: row nowrap;
}
.container.y {
width: 256px;
height: 256px;
flex-flow: column nowrap;
}
/* scroll-snap */
.x.mandatory-scroll-snapping {
scroll-snap-type: x mandatory;
}
.y.mandatory-scroll-snapping {
scroll-snap-type: y mandatory;
}
.x.proximity-scroll-snapping {
scroll-snap-type: x proximity;
}
.y.proximity-scroll-snapping {
scroll-snap-type: y proximity;
}
.container > div {
text-align: center;
scroll-snap-align: center;
flex: none;
}
.x.container > div {
line-height: 128px;
font-size: 64px;
width: 100%;
height: 128px;
}
.y.container > div {
line-height: 256px;
font-size: 128px;
width: 256px;
height: 256px;
}
/* appearance fixes */
.y.container > div:first-child {
line-height: 1.3;
font-size: 64px;
}
/* coloration */
.container > div:nth-child(even) {
background-color: #87EA87;
}
.container > div:nth-child(odd) {
background-color: #87CCEA;
}
<div><p>Scrolled <span id="demo">0</span> times.</p></div>
<div class="container y mandatory-scroll-snapping" onscroll="Onscrollfnction();" dir="ltr">
<div>Y Mand. LTR</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
The vue.js, vuetify version does not
https://codepen.io/travis-pancakes/pen/BMbqPq?editors=1111
new Vue({
el: '#app',
data: function(){
return {
i: 0
}
},
created () {
},
methods: {
Onscrollfnction (event) {
document.getElementById("demo").innerHTML = this.i;
this.i = this.i + 1;
console.log('i ', i)
}
}
});
/* setup */
html, body, .holster {
height: 100%;
}
.holster {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: column nowrap;
font-family: monospace;
}
.container {
display: flex;
overflow: auto;
outline: 1px dashed lightgray;
flex: none;
}
.container.x {
width: 100%;
height: 128px;
flex-flow: row nowrap;
}
.container.y {
width: 256px;
height: 256px;
flex-flow: column nowrap;
}
/* scroll-snap */
.x.mandatory-scroll-snapping {
scroll-snap-type: x mandatory;
}
.y.mandatory-scroll-snapping {
scroll-snap-type: y mandatory;
}
.x.proximity-scroll-snapping {
scroll-snap-type: x proximity;
}
.y.proximity-scroll-snapping {
scroll-snap-type: y proximity;
}
.container > div {
text-align: center;
scroll-snap-align: center;
flex: none;
}
.x.container > div {
line-height: 128px;
font-size: 64px;
width: 100%;
height: 128px;
}
.y.container > div {
line-height: 256px;
font-size: 128px;
width: 256px;
height: 256px;
}
/* appearance fixes */
.y.container > div:first-child {
line-height: 1.3;
font-size: 64px;
}
/* coloration */
.container > div:nth-child(even) {
background-color: #87EA87;
}
.container > div:nth-child(odd) {
background-color: #87CCEA;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!-- could use v-scroll="Onscrollfnction" with vuetify" --->
<div class="container y mandatory-scroll-snapping"
v-on:scroll.native="Onscrollfnction" dir="ltr">
<div>Y Mand. LTR</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<p>Scrolled <span id="demo">0</span> times.</p>
</div>
</div>
vue-awesome-swiper does the functionality I'm going for

vue-pagination-2 not working

I am brand new to VueJS and almost everything is working, except for pagination. As a matter of fact, I have zero warnings. The only thing appearing in the console is "[HMR] Waiting for update signal from WDS... log.js?4244:23" followed by a ">" on the next line.
With that said, the pagination is showing the correct number of pages - given the data coming from the JSON, but I do not know how to connect the pagination to the UL or the app.
At least when there is an error, I can figure something out. Any help is appreciated and thanks in advance.
<template>
<div class="container" id="app">
<span>VueJS-Example</span>
<ul class="list-group list-inline mHeaders">
<li class="list-group-item">Title</li>
<li class="list-group-item">Band</li>
<li class="list-group-item">Date Posted</li>
<li class="list-group-item">Downloads</li>
<li class="list-group-item">YouTube</li>
<li class="list-group-item">MP3</li>
</ul>
<ul :key="item.id" class="list-group list-inline" v-for="item in items">
<li class="list-group-item">
{{item.title}}
</li>
<li class="list-group-item">
{{item.original_band}}
</li>
<li class="list-group-item">
{{item.date_posted}}
</li>
<li class="list-group-item mZip">
<a v-bind:href="''+item.download_midi_tabs+''" target="_blank"></a>
</li>
<li class="list-group-item mYt">
<a v-bind:href="''+item.youtube_link+''" target="_blank"></a>
</li>
<li class="list-group-item mAudio">
<a v-bind:href="''+item.download_guitar_m4v+''" target="_blank"></a>
</li>
</ul>
<pagination :records="288" :per-page="30" #paginate="getPostsViaREST"></pagination>
</div>
</template>
<script>
import axios from 'axios'
import {Pagination} from 'vue-pagination-2'
export default {
name: 'App',
data: function () {
return {
items: [{
title: '',
original_band: '',
date_posted: '',
download_midi_tabs: '',
youtube_link: '',
download_guitar_m4v: ''
}]
}
},
created: function () {
this.getPostsViaREST()
},
methods: {
getPostsViaREST: function () {
axios.get('http://local.sites/getSongs.php')
.then(response => { this.items = response.data })
}
},
components: {
Pagination
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
a {
color: #999;
}
.current {
color: red;
}
ul {
padding: 0;
list-style-type: none;
}
li {
display: inline;
margin: 5px 5px;
}
ul.list-group:after {
clear: both;
display: block;
content: "";
}
.list-group-item {
float: left;
}
.list-group li{
max-width: 30%;
min-width: 50px;
min-height: 48px;
max-height: 48px;
}
.list-group li:first-child{
width: 200px;
cursor: pointer;
}
.list-group li:nth-child(2){
width: 200px;
}
.list-group li:nth-child(3){
width: 110px;
}
.list-group li:nth-child(4){
width: 48px;
}
.list-group li:nth-child(5){
width: 48px;
}
.list-group li:last-child{
width: 48px;
}
.mZip{
background: url("http://www.kronusproductions.com/songs_angular/assets/images/mZip.png");
display: block !important;
max-width: 48px;
height: 48px;
cursor: pointer;
}
.mYt{
background: url("http://www.kronusproductions.com/songs_angular/assets/images/youtube-icon_48x48.png");
display: block !important;
width: 48px;
height: 48px;
cursor: pointer;
}
.mAudio{
background: url("http://www.kronusproductions.com/songs_angular/assets/images/volume.png");
display: block !important;
width: 48px;
height: 48px;
cursor: pointer;
}
.mZip a{
display: block !important;
width: 48px;
height: 48px;
}
.mYt a{
display: block !important;
width: 48px;
height: 48px;
}
.mAudio a{
display: block !important;
width: 48px;
height: 48px;
}
.mHeaders li{
background-color: cornflowerblue;
font-size: 0.85rem;
color: white;
}
OK - this is somewhat of a hack, but it works.
The following URL is a working example:
Needed help from some old fashion native JavaScript on the index.html file. First, I needed to be able to read a hidden field that contained the number of entries coming from the JSON., followed by setting all the ULs to display none - the setTimeout is to make sure that the JSON file was loaded
<script type="text/javascript">
var mTO = setTimeout(function () {
for (var x = 31; x <= $(".numRows").val() - 1; x++) {
if (typeof (document.getElementById('sp_' + x)) === 'undefined') {
} else {
document.getElementById('sp_' + x).style.display = 'none'
}
}
}, 1000);
mTO;
</script>
This is followed by calling a computed user created method to set this.mVar to the number of elements/entries/properties - whatever name you want to use for it - for Vue to know how many elements, so that we could divide by the number of pages to paginate
computed: {
mFunc: function () {
this.mVar = Object.keys(this.items).length
return Object.keys(this.items).length
}
}
This is another portion of the aforementioned hack - depending on page clicked in the pagination section, this determines what to hide and what to show
setPage: function (page) {
this.page = page
// console.log(page)
for (var y = 0; y <= this.mVar - 1; y++) {
if (typeof (document.getElementById('sp_' + y)) === 'undefined') {
} else {
document.getElementById('sp_' + y).style.display = 'none'
}
}
for (var x = (30 * (this.page - 1)); x <= 30 * (this.page); x++) {
if (typeof (document.getElementById('sp_' + x)) === 'undefined' || (document.getElementById('sp_' + x)) == null) {
break
} else {
document.getElementById('sp_' + x).style.display = 'block'
}
}
}
In case you were wondering what the "30" is for, that is the number of ULs that I wanted to show per page.
The last portion of the hack is within the template section
<pagination :records="mFunc" :per-page="30" #paginate="setPage"></pagination>
<span style="display: none;"><input type="hidden" class="numRows" :value="this.mVar" /></span>
If you would like to use the entire, then you can find it on my github:
Github repo for vuejs-example

Error when trying to use ReactiveProp in vue-chartjs

I'm trying to use a component called "Vue-Chartjs" to create a LineChart.[
I'm passing some data from a MySql database to the 'chartData' prop, defined in the Chart.js file.
But I'm getting this error. What I understood (I think), is that chartData doesn't get updated.
Does anyone know why it doesn't work? Thank you very much!
This are my Chart.js file and my Forecast.vue file
import {
Line,
mixins
} from 'vue-chartjs'
const {
reactiveProp
} = mixins
export default {
name: 'line-chart',
extends: Line,
mixins: [reactiveProp],
props: {
chartData: {
type: Array,
required: true
},
chartLabels: {
type: Array,
required: true
}
},
data() {
return {
options: {
scales: {
yAxes: [{
display: true
}],
xAxes: [{
display: false
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
mounted() {
this.renderChart({
labels: this.chartLabels,
datasets: [{
label: 'Temperature',
colors: '#000000',
backgroundColor: '#000000',
data: this.chartData
}]
}, this.options)
}
}
<template>
<div class="FiveDaysForecast">
<div class="tabs is-fullwidth">
<ul>
<li><router-link to="OneDayForecast"><span class="icon is-small"><i class="fas fa-cloud"></i></span>One day forecast</router-link></li>
<li class="is-active"><router-link to="FiveDaysForecast"><span class="icon is-small"><i class="fas fa-cloud"></i></span>Five days forecast</router-link></li>
<li><router-link to="FilterByDate"><span class="icon is-small"><i class="fas fa-calendar-alt"></i></span>Filter forecast by date</router-link></li>
</ul>
</div>
<h1>FIVE DAYS FORECAST</h1>
<form>
<div class="box">
<div class="field">
<div class="control">
<input class="input is-rounded" type="text" placeholder="Place" v-model="place">
</div>
<br>
<div class="control">
<input class="input is-rounded" type="text" placeholder="Country" v-model="country">
</div>
<br>
<div class="control">
<input class="input is-rounded" type="text" placeholder="Unit of measure (Celsius = 'metric' | Fahrenheit = 'imperial')" v-model="unitOfMeasure" required>
</div>
<br>
<div class="control">
<input class="input is-rounded" type="text" placeholder="Latitude" v-model="latitude">
</div>
<br>
<div class="control">
<input class="input is-rounded" type="text" placeholder="Longitude" v-model="longitude">
</div>
</div>
<button class="button is-medium is-rounded" #click="getFiveDaysForecast">Search</button>
</div>
</form>
<br>
<table class="table is-narrow">
<thead>
<tr>
<th>Temperature</th>
<th>TemperatureMin</th>
<th>TemperatureMax</th>
<th>Humidity</th>
<th>Pressure</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr v-for="forecast in forecastData" :key="forecast.Pressure">
<td>{{forecast.temperature}}</td>
<td>{{forecast.temperatureMin}}</td>
<td>{{forecast.temperatureMax}}</td>
<td>{{forecast.humidity}}</td>
<td>{{forecast.pressure}}</td>
<td>{{forecast.timeStamp}}</td>
</tr>
</tbody>
</table>
<line-chart
:chart-data="tempRows"
:chartLabels="weatherDate"
></line-chart>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "FiveDaysForecast",
data() {
return {
place: "",
country: "",
unitOfMeasure: "",
latitude: "",
longitude: "",
forecastData: [],
temperature: [],
weatherDate: [],
tempRows: []
};
},
methods: {
getFiveDaysForecast() {
axios({
method: "get",
url: "http://localhost:55556/api/ForecastActions/fiveDaysForecast",
params: {
Place: this.place,
Country: this.country,
UnitOfMeasure: this.unitOfMeasure,
Lat: this.latitude,
Lon: this.longitude
}
})
.then(response => {
console.log(response);
this.forecastData = response.data;
this.forecastData.forEach(item => {
var tempArray = [];
this.tempRows.push(item.temperature);
this.weatherDate.push(item.timeStamp);
});
})
.catch(error => {
console.log(error);
});
}
}
};
</script>
<style scoped>
.FiveDaysForecast {
width: 1200px;
margin: 30px auto;
}
.tabs {
width: 600px;
margin-left: auto;
margin-right: auto;
}
h1 {
font-size: 50px;
}
#forecast-params {
margin-top: 30px;
margin-bottom: 50px;
text-align: left;
font-size: 20px;
}
.param-names {
font-weight: bold;
color: black;
font-size: 20px;
}
.box {
background-color: transparent;
width: 600px;
margin: 0 auto;
border: 3px solid royalblue;
box-shadow: 0px 0px 30px royalblue;
}
::placeholder {
color: rgb(170, 170, 170);
}
input,
button {
background-color: #fcfcfc;
border: 2px solid rgb(170, 170, 170);
}
input:focus {
border: 2px solid royalblue;
box-shadow: 0px 0px 30px royalblue;
}
input:hover {
border: 2px solid royalblue;
}
button:focus {
border: 2px solid royalblue;
box-shadow: 0px 0px 30px royalblue;
}
button:hover {
border: 2px solid royalblue;
}
.table {
margin: 0 auto;
width: 1000px;
}
td,
th {
text-align: center;
}
thead {
font-size: 20px;
display: table-header-group;
vertical-align: middle;
border-bottom: 3px solid royalblue !important;
}
tr {
font-weight: 600;
transition: background-color 0.5s ease;
}
tr:hover {
background-color: rgb(153, 179, 255);
}
#chart {
display: inline-block;
padding: 0px;
margin: 0px;
}
#tempChart {
padding: 0 auto;
}
#charts {
padding: 0px auto;
}
</style>
Well your "problem" is that your data is async. So the chart will be rendered without any data or without proper data.
You have to put a
v-if="loaded"
on your chart component.
And in your axios call you need to set it to true.