PHP API WITH VUE.JS - javascript

I Created my API with PHP and here is the link: https://monstajams.co/streaming/rest/api/album/read.php
But anytime i put it in my Vue.js (Home.vue) file using axios No data is displayed on the front-end.
Here is my code below:
<ul class="ta-track-list" v-if="faqs && faqs.length">
<li class="ta-track-card column col-2 flex-column" v-for="faq of faqs">
<div class="inner">
<div class="artwork" role="link">
<span role="link" style="background-image: url(http://localhost/mymusic/assets/images/artwork/Wizkid-Soco.jpg);">
</span>
<div class="hover flex align-center justify-center">
<button id="webutton" class="ta-secondary play" onclick='playSong()'>
<i class="material-icons">play_arrow</i>
</button>
</div>
</div>
<div class="info">
<div class="title white-primary-hover" role="lin">{{ faqs }}</div>
<div class="username light-white-hover" role="link">{{ faq.artist }}</div>
<div class="released">{{ faq.duration }}</div>
</div>
</div>
</li>
</ul>
<script>
import axios from 'axios';
export default {
name: 'home',
data: () =>({
faqs: [],
errors: []
}),
created() {
axios.get('https://monstajams.co/streaming/rest/api/album/read')
.then(response => {
this.faqs = response.data;
})
.catch(e => {
this.errors.push(e)
})
}
}
</script>

The problem is your code incorrectly assumes axios.get() resolves to the raw response, but it actually resolves to a response wrapper, where the raw response is contained in a data subproperty of the wrapper, which coincidentally has the same name as the target property within the response.
You can either change your Axios response handler to get the inner data field:
axios.get('https://monstajams.co/streaming/rest/api/album/read')
.then(response => {
// this.faqs = response.data; // response.data is the raw response, but you need the array within the response (also named "data")
this.faqs = response.data.data;
})
demo
Or leave your frontend alone, and update your PHP backend to send only the array in the response:
// FROM THIS RESPONSE:
{
data: [/* PLAYLIST DATA */]
}
// TO THIS RESPONSE:
[/* PLAYLIST DATA */]

You are not updating your data accordingly to Vue docs.
For reactive changes see this document.
In the example below i update my list before Vue is mounted so rendering can occur accordingly.
let vm = new Vue({
el: "#app",
data: {
todos: []
},
methods: {
updateList() {
axios.get('https://monstajams.co/streaming/rest/api/album/read')
.then(res => {
res.data.data.forEach(item => {
Vue.set(vm.todos, vm.todos.length, {
text: item.title,
done: true
})
})
})
}
},
beforeMount() {
this.updateList()
},
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<span>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>

Related

how to pass data from api as prop in vuejs

I am getting data from api which I want to pass as prop to a child component
Parent component
<template>
<div class="dashboard">
<items name="Admins" value={{data.items.hubs}} bgColor="#a80c0c" />
</div>
</template>
import Items from './Items.vue'
import { Admin } from '#/services/AdminService';
export default {
name: "AdminDashboard",
components: {
Items
},
setup(){
onMounted(() => {
showLoader(true);
Admin.getDashboardItems()
.then((response) => {
data.items = response.data.data
})
.catch((error) => {
})
.finally(() => {
showLoader(false);
});
});
return {
data
}
}
}
I have gotten the value I need from the api and passed it to data.items
If i display it on the parent component.
It works fine but on the child component
it does not work
Child Component
<template>
<div class="col-md-3">
<div class="items" :style="{ backgroundColor: bgColor }">
<div class="d-flex space-between">
<div></div>
<div>
<h5>{{ value }}</h5>
<span>{{ name }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Items",
props: ["bgColor", "value", "name"]
}
</script>
The child components display {{data.items.hubs}} instead of the value of hub
The data from the api
{"data":{"users":1,"incubatees":1,"hubs":2,"investors":1,"events":0,"admins":3,"programs":0}}
After some research
I found out I was not supposed to use {{}}
instead I should do it this way on the parent component
<items name="Hubs" :value="data.items.hubs" bgColor="#d79a2b" />

Vue.js update contents in div dynamically

I am attempting to do a SPA using Vue.js but unfortunately I know almost nothing about it, I followed a tutorial and got something up and running. This should hopefully be relatively simple!
I'm trying to create a simple page that:
Does a REST API call and pulls some JSON
A list with links of a particular field in the list of results is displayed on the left side of the screen
(I've managed until here)
Now I would like to be able to click on one of the links and see on the right side of the screen the value of another field for the same record.
For instance, suppose my JSON is:
{
"jokes":{
[
"setup":"setup1",
"punchline":"punchline1"
],
[
"setup":"setup2",
"punchline":"punchline2"
],
[
"setup":"setup3",
"punchline":"punchline3"
]
}
}
So in my screen I would see:
setup1
setup2
setup3
So if I click in setup1 I see punchline1, setup2 displays punchline2 and so on.
Here is my code - I'm basically trying to display the punchline in the moduleinfo div. I realise the current solution does not work. I've been searching but can't find any similar examples. Any pointers would be greatly appreciated.
<template>
<div class="home">
<div class="module-list">
<input type="text" v-model.trim="search" placeholder="Search"/>
<div>
<ul>
<li class="modules" v-for="value in modulesList" :key="value.id">
{{ value.setup }}
</li>
</ul>
</div>
</div>
<div class="moduleinfo">
<h2>Module info</h2>
<!-- <p>{{ value.punchline }}</p> -->
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Home',
data: function(){
return {
jokes: [],
search : ""
}
},
mounted() {
this.getModules();
},
methods: {
getModules() {
var self = this
const options = {
method: 'GET',
url: 'https://dad-jokes.p.rapidapi.com/joke/search',
params: {term: 'car'},
headers: {
'x-rapidapi-key': '...',
'x-rapidapi-host': 'dad-jokes.p.rapidapi.com'
}
};
axios.request(options)
.then(response => {
self.jokes = response.data;
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
}
},
computed: {
modulesList: function () {
var jokes = this.jokes.body;
var search = this.search;
if (search){
jokes = jokes.filter(function(value){
if(value.setup.toLowerCase().includes(search.toLowerCase())) {
return jokes;
}
})
}
return jokes;
}
},
};
</script>
Thanks!
I was building a sample Single File Component in my Vue 2 CLI app, and when I came back to post it, Ryoko had already answered the question with the same approach that I recommend, adding a new property to track showing the punchline.
Since I already built it, I figured that I might as well post my component, which does change the layout, using a table instead of a list, but the functionality works.
<template>
<div class="joke-list">
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>SETUP</th>
<th>PUNCHLINE</th>
</tr>
</thead>
<tbody>
<tr v-for="(joke, index) in jokes" :key="index">
<td>
{{ joke.setup }}
</td>
<td>
<span v-if="joke.showPunchline">{{ joke.punchline }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
jokes: [
{
setup: "setup1",
punchline: "punchline1"
},
{
setup: "setup2",
punchline: "punchline2"
},
{
setup: "setup3",
punchline: "punchline3"
}
]
}
},
methods: {
getPunchline(index) {
this.jokes[index].showPunchline = true;
},
addPropertyToJokes() {
// New property must be reactive
this.jokes.forEach( joke => this.$set(joke, 'showPunchline', false) );
}
},
mounted() {
this.addPropertyToJokes();
}
}
</script>
You can add a new property inside the data object and then make a new method to set it accordingly when you click the <a> tag. Have a look at the code below, it was a copy of your current solution, edited & simplified to show the addition that I made to make it easier for you to find it.
The select method will insert the object of the clicked joke to the selectedJoke so you can render it below the Module Info.
Because it's defaults to null, and it might be null or undefined, you have to add v-if to the attribute to check wether there is a value or not so you don't get error on the console.
<template>
<div class="home">
<div class="module-list">
<input type="text" v-model.trim="search" placeholder="Search"/>
<div>
<ul>
<li class="modules" v-for="value in modulesList" :key="value.id">
{{ value.setup }}
</li>
</ul>
</div>
</div>
<div class="moduleinfo">
<h2>Module info</h2>
<p v-if="selectedJoke">{{ selectedJoke.punchline }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Home',
data: function(){
return {
jokes: [],
search : "",
selectedJoke: null,
}
},
methods: {
select(joke) {
this.selectedJoke = joke;
},
},
};
</script>

How to parse json in Vue js to use it in template

<template>
<div class="row w-20 " >
<div class="card col-4 ">
<ul>
<li v-for="message in conversations.messages" :key="message.messages">
{{message.text}}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ['conversation_index_route'],
data() {
return {
conversations: [],
url: 'http://127.0.0.1:8000/comms/conversation/',
}
},
beforeMount() {
this.$eventBus.$on('selectConversation', this.getConversations)
this.getConversations();
},
methods: {
getConversations(id) {
console.log(this.url+id);
axios.get(this.url+ id)
.then(response => {
this.conversations = response.data;
this.conversations = JSON.parse(this.conversations.message);
console.log(this.conversations);
});
}
}
}
</script>
conversation_index_route:"http://127.0.0.1:8000/comms/conversation"
conversations:Object
all_staff_attended:false
centre_id:5
children:""
classes:""
cover_image:"https://via.placeholder.com/150x150"
created_at:"2020-05-30 19:01:59"
exited_users:null
id:257
last_id:null
messages:Array[1]
0:"{"_id":1854,"text":"This is the beginning of this conversation","createdAt":"2020-05-30 19:01:59","system":true}"
parent_users:"3016"
parents:Array[1]
staff_users:"180,181"
staffs:Array[2]
status_id:1
title:"Test"
updated_at:"2020-05-30 19:01:59"
url:"http://127.0.0.1:8000/comms/conversation/"
So what shall I code to use the message text in my template to display the text messages?
You'd have to do JSON.parse(conversations.messages[0]).text. This way you parse the object inside messages and have access to its properties.
Simply JSON.parse the string
var myJson = "[{\"id\":72,\"food_item_id\":\"56\",\"variation_id\":\"20\",\"price\":\"50\",\"created_at\":\"2021-06-29T05:29:14.000000Z\",\"updated_at\":\"2021-06-29T05:29:14.000000Z\",\"variant\":null}]";
var myJson2 = JSON.parse(myJson);
console.log(myJson2);

Laravel 5 vue.js: Property or method "comment" is not defined on the instance but referenced during render

I am creating commenting system using vue.js and laravel5.8.
I have done with models and seeding, so I have now 10 comments to one post (id is 51).
But I got this error,
Property or method "comment" is not defined on the instance but
referenced during render
and
Cannot read property 'user' of undefined
I have problems with fetching data.
I created a new endpoint for a comment function.
web.php
Route::get('results/{post}', 'ResultsController#show')->name('posts.show');
Route::get('results/{post}/comments', 'CommentsController#index');
I want to show comments in show.blade.php.
ResultsController.php
public function show(Post $post)
{
$recommended_posts = Post::latest()
->whereDate('date','>',date('Y-m-d'))
->where('category_id','=',$post->category_id)
->where('id','!=',$post->id)
->limit(7)
->get();
$posts['particular_post'] = $post;
$posts['recommended_posts'] = $recommended_posts;
$post->comments()->with('user')->get();
return view('posts.show',compact('posts'));
}
show.blade.php
<comments-component :post="{{ $posts['particular_post']->comments }}"></comments-component>
comments.vue
<div class="reply-comment" :v-for="comment in comments">
<div class="user-comment" >
<div class="user">
<!--<img src="" alt="" >-->
<avatar :username="comment.user.name" :size="30" ></avatar>
</div>
<div class="user-name">
<span class="comment-name">{{ comment.user.name }}</span>
<p> {{ comment.body }} </p>
</div>
</div>
<div class="reply">
<div class="seemorecomments">
see more
</div>
<button class="reply-button">
<i class="fas fa-reply"></i>
</button>
</div>
</div>
<script>
import Avatar from 'vue-avatar'
export default {
props: ['post'],
components: {
Avatar
},
mounted() {
this.fetchComments()
},
data: () => ({
comments: {
data: []
}
}),
methods: {
fetchComments() {
axios.get(`/results/${this.post.id}/comments`).then(({data}) => {
this.comments = data
})
}
}
}
CommentsController.php
public function index(Post $post)
{
return $post->comments()->paginate(5);
$post->comments()->with('user')->get();
}
comment.php
protected $with = ['user'];
I cannot get data object here.
Within axios, you may need to access data from the response that is returned (see console.log examples here), try the following within your comments component:
methods: {
fetchComments() {
axios.get(`/results/${this.post.id}/comments`).then((response) => {
this.comments = response.data.data
})
}
}
Note response.data.data is used.
I assume returning the ->paginate() will put the results within a data key in the returned array. If not, then just use response.data.
Also, in the controller getting the comments change to the following:
public function index(Post $post)
{
return $post->comments()->with('user')->paginate(5);
}
This will eager load the users with the queried comments.

The problem of data transfer between two child components

Good afternoon, I have two child components Header and Pagination. In Header, I have an input search engine and two inputs (title and body) in order to be able to add a post to Pagination. I managed to transfer the search value to the Pagination component, but I don’t know how to transfer the value from two inputs (title, body). I use to transfer the event bus. Help me please pass the value of the two inputs (title, body) into the Pagination component when you click the AddPost button.
My code on GitHub
Screenshot of app
My code of component Header:
<template>
<div class="header">
<input type="text" v-model="search" class="header_input_search" placeholder="Search" #input="saveMessage" />
<img src="src/assets/milk.png">
<div class="header_div_inputs">
<input type="text" v-model="createTitle" class="created"/>
<p><input type="text" v-model="createBody" class="createBody"/></p>
</div>
<button #click="addPost()" class="addPost">AddPost</button>
</div>
</template>
<script>
import axios from 'axios';
import {eventEmitter} from './main'
export default {
name: 'Header',
data () {
return {
search: '',
createTitle: '',
createBody: '',
}
},
methods:{
saveMessage(){
eventEmitter.$emit('messageSave', this.search)
},
}
}
</script>
My code of component Pagination:
<template>
<div class = "app">
<ul>
<li v-for="(post, index) in paginatedData" class="post" :key="index">
<router-link :to="{ name: 'detail', params: {id: post.id, title: post.title, body: post.body} }">
<img src="src/assets/nature.jpg">
<p class="boldText"> {{ post.title }}</p>
</router-link>
<p> {{ post.body }}</p>
</li>
</ul>
<div class="allpagination">
<button type="button" #click="page -=1" v-if="page > 0" class="prev"><<</button>
<div class="pagin">
<button class="item"
v-for="n in evenPosts"
:key="n.id"
v-bind:class="{'selected': current === n.id}"
#click="page=n-1">{{ n }} </button>
</div>
<button type="button" #click="page +=1" class="next" v-if="page < evenPosts-1">>></button>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
import {eventEmitter} from './main'
export default {
name: 'app',
data () {
return {
current: null,
page: 0,
visiblePostID: '',
pSearch: ''
}
},
mounted(){
this.$store.dispatch('loadPosts')
},
computed: {
...mapState([
'posts'
]),
evenPosts: function(posts){
return Math.ceil(this.posts.length/6);
},
paginatedData() {
const start = this.page * 6;
const end = start + 6;
return this.filteredPosts.slice(start, end);
},
filteredPosts() {
return this.posts.filter((post) => {
return post.title.match(this.pSearch);
});
},
},
created(){
eventEmitter.$on('messageSave', (string) => {
this.pSearch = string
})
}
}
</script>
You can wrap title and body in an object
addPost() {
const post = {
title: this.createTitle,
body: this.createBody
}
eventEmitter.$emit('postAdd', post)
}
and then listen as normal
created(){
eventEmitter.$on('postAdd', (post) => {
console.log(post)
// do whatever you want
})
}
I have not worked on vue js but agreed with #ittus answer. You can make an object consisting of your required data which you want to share across the component and pass it as an event data.

Categories