{{ obj.data }} not displaying in vue template after axios get - laravel-5

I am trying to build a carousel using Laravel 5.6 and Vue.js. I can call the data from db, and console.log response.data. It works like expect it to. Script below.
<script>
$(document).ready(function() {
$("#availability").owlCarousel();
});
export default {
props: {
areaId: null,
tutorId: null,
},
data () {
return {
availability: []
}
},
methods: {
getAvailability () {
var that = this;
axios.get( '/' + this.areaId + '/' + this.tutorId + '/availability').then((response) => {
console.log(response.data)
that.availability = response.data;
});
}
},
mounted () {
this.getAvailability();
}
}
</script>
Now I would expect to be able to display the data like
{{availability.monday_begin}}
but it displays nothing, empty tags.
When I add a second .data to response, so change
that.availability = response.data;
to
that.availability = response.data.data;
The data object shows up as undefined in the vue-dev tools, and {{ availability.monday_begin }} throws an error cannot read property of undefined.
I also tried adding a v-if to the template, based on a couple different articles I read, but nothing I tried worked.
Thanks for your help.

Related

Watch Value In Vue.js 3, Equivalent In Pinia?

I have a checkbox list of domain tlds, such as com, net, io, etc. I also have a search text input, where I can drill down the list of 500 or so domains to a smaller amount. For example, if I start to type co in to my search text input, I will get back results that match co, such as co, com, com.au, etc. I am using Laravel and Vue,js 3 to achieve this with a watcher. It works beautifully. How can an achieve the same within a Pinia store?
Here is my code currently:
watch: {
'filters.searchedTlds': function(after, before) {
this.fetchsearchedTlds();
}
},
This is inside my vue component.
Next is the code to fetch searched tlds:
fetchsearchedTlds() {
self = this;
axios.get('/fetch-checked-tlds', { params: { searchedTlds: self.filters.searchedTlds } })
.then(function (response) {
self.filters.tlds = response.data.tlds;
console.log(response.data.tlds);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
},
And finally, the code inside my Laravel controller:
public function fetchCheckedTlds(Request $request)
{
$data['tlds'] = Tld::where('tld', 'LIKE','%'.$request->input('searchedTlds').'%')->pluck('tld');
return response()->json($data);
}
I am converting my code to use a Pinia store and I am stuck on how to convert my vue component watcher to Pinia?
Many thanks in advance.
To watch a pinia status, you may watch a computed attribute based on pinia or use watch getter
Your pinia may look like the one below.
~/store/filters.js
export const useFilters = defineStore('filters', {
state: () => {
return {
_filters: {},
};
},
getters: {
filters: state => state._filters,
},
...
}
In where you want to watch
<script setup>
import { computed, watch } from 'vue';
import { useFilters } from '~/store/filters.js';
const filters = useFilters();
// watch a computed attributes instead
const searchedTlds = computed(() => {
return filters.filters?.searchedTlds || '';
});
watch(
searchedTlds,
(newValue, oldValue) {
fetchsearchedTlds();
}
);
// or use watch getter
watch(
() => {
return filters.filters?.searchedTlds || '';
},
(newValue, oldValue) {
fetchsearchedTlds();
}
);
</script>
The first parameter of watch() can be a single ref or a getter function, or an array of getter functions, for more details, please view the Watch Source Types.

Vue js function countSubcategories() returns [object Promise]

countSubcategories() function returns [object Promise] where it should return row counts of mapped subcategories.
This code is in vue.js & Laravel, Any suggestions on this?
<div v-for="(cat,index) in cats.data" :key="cat.id">
{{ countSubcategories(cat.id) }} // Here subcategories row counts should be displayed.
</div>
<script>
export default {
data() {
return {
cats: {},
childcounts: ""
};
},
created() {
this.getCategories();
},
methods: {
countSubcategories(id) {
return axios
.get("/api/user-permission-child-count/" + `${id}`)
.then(response => {
this.childcounts = response.data;
return response.data;
});
},
getCategories(page) {
if (typeof page === "undefined") {
page = 1;
}
let url = helper.getFilterURL(this.filterpartnerForm);
axios
.get("/api/get-user-permission-categories?page=" + page + url)
.then(response => (this.cats = response.data));
}
}
};
</script>
As Aron stated in the previous answer as you are calling direct from the template the information is not ready when the template is rendered.
As far as I understood you need to run getCategories first so then you can fetch the rest of your data, right?
If that's the case I have a suggestion:
Send an array of cat ids to your back-end and there you could send back the list of subcategories you need, this and this one are good resources so read.
And instead of having 2 getCategories and countSubcategories you could "merge" then like this:
fetchCategoriesAndSubcategories(page) {
if (typeof page === "undefined") {
page = 1;
}
let url = helper.getFilterURL(this.filterpartnerForm);
axios
.get("/api/get-user-permission-categories?page=" + page + url)
.then(response => {
this.cats = response.data;
let catIds = this.cats.map(cat => (cat.id));
return this.countSubcategories(catIds) // dont forget to change your REST endpoint to manage receiving an array of ids
})
.then(response => {
this.childcounts = response.data
});
}
Promises allow you to return promises within and chain .then methods
So in your created() you could just call this.fetchCategoriesAndSubcategories passing the data you need. Also you can update your template by adding a v-if so it doesn't throw an error while the promise didn't finish loading. something like this:
<div v-if="childCounts" v-for="(subcategorie, index) in childCounts" :key="subcategorie.id">
{{ subcategorie }} // Here subcategories row counts should be displayed.
</div>
Hello!
Based on the provided information, it could be 2 things. First of all, you may try replacing:
return response.data;
with:
console.log(this.childcounts)
and look in the console if you have the correct information logged. If not, it may be the way you send the information from Laravel.
PS: More information may be needed to solve this. When are you triggering the 'countSubcategories' method?
I would do all the intial login in the component itself, and not call a function in template like that. It can drastically affect the performance of the app, since the function would be called on change detection. But first, you are getting [object Promise], since that is exactly what you return, a Promise.
So as already mentioned, I would do the login in the component and then display a property in template. So I suggest the following:
methods: {
countSubcategories(id) {
return axios.get("..." + id);
},
getCategories(page) {
if (typeof page === "undefined") {
page = 1;
}
// or use async await pattern
axios.get("...").then(response => {
this.cats = response.data;
// gather all nested requests and perform in parallel
const reqs = this.cats.map(y => this.countSubcategories(y.id));
axios.all(reqs).then(y => {
// merge data
this.cats = this.cats.map((item, i) => {
return {...item, count: y[i].data}
})
});
});
}
}
Now you can display {{cat.count}} in template.
Here's a sample SANDBOX with similar setup.
This is happen 'cause you're trying to render a information who doesn't comeback yet...
Try to change this method inside created, make it async and don't call directly your method on HTML. Them you can render your variable this.childcounts.

Get 2 data from API laravel

i have 2 data from API
1. Category Food
2. Finish Good
how can i show 2 data from API in 1 page vue,
I only can show 1 data from API
this is what i tried
export default {
data(){
items:[],
finish_goods:[],
created() {
let uri = 'http://192.168.10.75:8000/api/finish_goods'; // Data 1
this.axios.get(uri).then(response => {
this.items = response.data.data;
});
},
created() {
let uri = 'http://192.168.10.75:8000/api/cat_foods'; // Data 2
this.axios.get(uri).then(response => {
this.finish_goods = response.data.data;
});
}
},
methods: {}
}
You're along the right lines, but it looks like your template syntax is a bit messed up...
// Make sure axios is installed via npm, you can skip this step
// if you've declared window.axios = axios somewhere in your app...
import axios from 'axios';
export default {
// Data must be a function that returns the initial state object...
data() {
return {
finishGoods: [],
catFoods: []
};
},
// Created is a hook and can only be defined once, think of it like an event listener...
created() {
let finishGoodsUri = 'http://192.168.10.75:8000/api/finish_goods';
// Fetch finish goods, note that I'm not calling this.axios...
axios.get(finishGoodsUri).then(response => {
this.finishGoods = response.data.data;
});
let catFoodsUri = 'http://192.168.10.75:8000/api/cat_foods';
// Fetch cat foods...
axios.get(catFoodsUri).then(response => {
this.catFoods = response.data.data;
});
}
}
Now in your template you can do the following:
<template>
<div>
<div v-for="finishGood in finishGoods">
{{ finishGood.attribute }}
</div>
<div v-for="catFood in catFoods">
{{ catFood.attribute }}
</div>
</div>
</template>
my advice, combine the API as 1
created() {
let uri = 'http://192.168.10.75:8000/api/combine_data'; // sample
this.axios.get(uri).then(response => {
this.finish_goods = response.data.data.goods;
this.items = response.data.data.foods;
});
}

return data object to vue component using laravel 5.6 and axios

I am trying to build an availability carousel. It will show the days of the week, and what time someone is available. I am using Laravel and vue.js. I have done the web api, and I can get the data object following the route
Route::group(['prefix' => '/{area}'], function () {
Route::get('/{tutor}/availability','Tutor\AvailabilityController#show');
});
with this in my availability controller
public function show(Request $request, Area $area, Tutor $tutor)
{
$availability = $tutor->availability()->get();
return response()->json([
'data' => $availability
], 200);
}
That all works.
But when I try and pull it into Vue, nothing shows up. I can't seem to figure out what I might be missing.
I pulled the vue component into blade using the following, and passing in the area and tutor id
<availability area-id="{{ $area->slug }}" tutor-id="{{ $tutor->slug }}">
</availability>
and in Availability.vue, I think where I am going wrong is pulling the data in with props, but I am really not sure anymore.
<script>
$(document).ready(function() {
$("#availability").owlCarousel();
});
export default {
props: {
areaId: null,
tutorId: null
},
data () {
return {
availability: []
}
},
methods: {
getAvailability () {
axios.get( '/' + this.areaId + '/' + this.tutorId + '/availability').then((response) => {
console.log(response.json());
});
}
},
ready () {
this.getAvailability();
}
}
</script>
Thank you for the help.
Axios response object has data field which contains the response from the server. To get the data use
response.data
Also for Vue 2.0 components use mounted instead of ready for when the component is ready. If you are only loading data from the server (and not manipulating the DOM) you can use created instead.
export default {
props: {
areaId: null,
tutorId: null
},
data () {
return {
availability: []
}
},
methods: {
getAvailability () {
var that = this;
axios.get( '/' + this.areaId + '/' + this.tutorId + '/availability')
.then((response) => {
console.log(response.data); // should print {data: availability_object}
// Set this component's availability to response's availability
that.availability = response.data.data;
//OR
//Add response's availability to the components' availability
that.availability.push(response.data.data);
});
}
},
mounted () {
this.getAvailability();
}
}
</script>

Vue 2, Cannot reference Prop Object in template

Problem: Although from the Vue DevTools I am passing the prop correctly and the router-view component has access to the data that it needs and in the correct format, whenever I try to access any of the data properties from within the template I get Uncaught TypeError: Cannot read property 'name' of null. It's really confusing because from the DevTools everything is a valid object and the properties are not null.
App.js
const game = new Vue({
el: '#game',
data: function() {
return {
meta: null,
empire: null,
planets: null
};
},
created: () => {
axios.get('/api/game').then(function (response) {
game.meta = response.data.meta;
game.empire = response.data.empire;
game.planets = response.data.planets;
});
},
router // router is in separate file but nothing special
});
main.blade.php
<router-view :meta="meta" :empire="empire" :planets="planets"></router-view>
script section of my Component.vue file
export default {
data: function() {
return {
}
},
props: {
meta: {
type: Object
},
empire: {
type: Object
},
planets: {
type: Array
}
}
}
Any ideas? Thanks in advance.
Because of your data is async loading so when my Component.vue renders your data in parent component may not be there. So you need to check if your data is loaded. You can try this code:
{{ meta != null && meta.name }}
PS: Your created hook should be:
created() {
axios.get('/api/game').then((response) => {
this.game.meta = response.data.meta;
this.game.empire = response.data.empire;
this.game.planets = response.data.planets;
});
},
router-view is a component from view-router which can help render named views. You can not pass empire and planets to it as those are props of your component.
You have to have following kind of code to pass empire and planets to your component:
<my-component :meta="meta" :empire="empire" :planets="planets"></my-component>
You can see more details around this here.

Resources