I'm pretty new to VueJS and have an understanding problem i couldn't find any help for.
Its pretty simple: I'm getting a JSON through an API with axios. This item contains a description that I want to output on the page.
My code looks something like this:
<template>
<div v-for="item in listitems" :key="item.id">
{{ item.description }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios'
export default defineComponent({
name: 'AllCoupons',
components: {
},
data: function() {
return {
listitems :[]
}
},
mounted: function() {
axios.get('https://api.com/endpoint',
{
headers: {
'Accept': 'application/json'
}
}).then((response) => {
console.log(response);
this.listitems = response.data.data
}).catch(error => {
console.log("ERRR:: ", error.response.data)
});
}
});
</script>
It works fine so far. The problem is that the item.description has too many characters, which I'd like to limit with something like substr. What is the right / best way to do something like this in vue?
I thought about adding a custom function in methods which will be run after the api fetched the data to iterate trough the data and make the modifications then, before passing it back to this.listitems. - But is there a way to do something like this in the template: ?
{{ item.description.substring(1, 4); }}
I knew something like this was possible with Vue 2 and filters if I'm right... But how can I do something like this in Vue 3?
Thanks a lot!!
As suggested in migration guide, you could use a computed property like :
data: function() {
return {
listitems :[]
}
},
computed:{
customItems(){
return this.listitems.map(item=>{
return {...item, description:item.description.substring(1, 4)}
}
}
}
then render that computed property :
<div v-for="item in customItems" :key="item.id">
{{ item.description }}
</div>
There is the following code when working with v-model and html with <input type ="text"> tags:
<template>
<InputTextApp class="inputTextAdditionData" placeholder_text="" v-model="cell_phone_number">
</InputTextApp>
</template>
<script>
import InputTextApp from '~/components/FormElements/InputTextApp';
export default{
data () {
return {
loading_cell_phone_number: '',
}
},
computed: {
cell_phone_number: {
get () {
return this.loading_cell_phone_number;
},
set (value) {
this.loading_cell_phone_number = value;
}
},
}
</script>
Question:
If in the content of calculated properties it is necessary to have the above code, how should I proxy the data from getters the what would it is code working fine?
As a primitive test, I tried to do something like this:
// vuex storage: tracker.js
const axios = require("axios");
export const getters = {
personTypeInput3: (state) => {
return {index: {
get () {
return this.loading_cell_phone_number;
},
set (value) {
this.loading_cell_phone_number = value;
}
},
}}
};
<template>
<InputTextApp class="inputTextAdditionData" placeholder_text="" v-model="cell_phone_number">
</InputTextApp>
</template>
<script>
import InputTextApp from '~/components/FormElements/InputTextApp';
export default{
data () {
return {
loading_cell_phone_number: '',
}
},
computed: {
cell_phone_number: {
...mapGetters("tracker", [
"personTypeInput3",
])
}
</script>
Then I accepted the content code in a computed property of the following form:
What needs to be written in the storage getter in order to get the code specified in the very first implementation (at the beginning of the post) in the computed property at the output?
(something like this:)
I have a <form> in vue. I send that form to server, get a JSON response, print it to console. It works fine.
However I need to take that JSON response and display it on another page. For instance, I have two .vue files: GetAnimal.vue that has the form and retrieves the animal data from an API and a DisplayAnimal.vue that displays animal's data. I need to direct the response animal data from GetAnimal.vue to DisplayAnimal.vue.
GetAnimal.vue:
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal"
name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default {
name: 'App',
data: function() {
return {
info: '',
animal: ''
}
},
methods: {
getAnimal: function() {
axios
.get('http://localhost:8088/animalsapi?animal=' + this.animal)
.then(response => (this.info = response.data));
console.log(this.info);
}
}
}
</script>
response:
retrieves a JSON with animal data, say like this:
{
"fur-color": "yellow",
"population": 51000,
"isExtinct": false,
"isDomesticated": true
}
and I now want to give that JSON to a DisplayAnimal.vue at /viewanimal endpoint:
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: {{animal}}}</p>
<p>Fur color: {{furColor}}</p>
<p>Population: {{population}}</p>
<p>Is extinct: {{isExtinct}}</p>
<p>Is domesticated: {{isDomesticated}}</p>
</div>
</template>
How would I do that? I know I can redirect via this.$router.push({ path });, but I've only used it for navigation, while here JSON response needs to be passed. Is this even a correct / good practice way of approaching this?
EDIT:
I tried this:
in GetAnimal.vue I added this data:
data: function() {
return {
animal: {
name: 'Cat',
furColor: 'red',
population: '10000',
isExtinct: false,
isDomesticated: true
}
and in DisplayAnimal.vue this:
<script>
export default {
props: {
animal: {
name: {
type: String
},
furColor: {
type: String
},
population: String,
isExtinct: String,
isDomesticated: String
}
}
}
</script>
and in GetAnimal.vue I added this:
methods: {
animals: function() {
alert("animals");
this.$router.push({name: 'viewanimal',
query: {animal: JSON.stringify(this.animal)}});
},
to try to display that test animal using the display component. However it just didn't work - I get an empty page.
Using Vuex, you can solve this easily
Working example on netlify
https://m-animalfarm.netlify.app/
code on github
https://github.com/manojkmishra/animalfarm
GetAnimal.vue ( I have disabled axios call for testing and hardcoded info)
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal" name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default
{
name: 'App',
data: function() { return { info: '', animal: '' } },
methods: {
getAnimal: function() {
// axios
// .get('http://localhost:8088/animalsapi?animal=' + this.animal)
// .then(response => (this.info = response.data),
this.info={"fur-color": "yellow","population": 51000,"isExtinct":
false,"isDomesticated": true },
this.$store.dispatch('storeAnimals', this.info)
//);
}
}
}
</script>
DisplayAnimal.vue
<template>
<div>
<p>Animal name: {{stateAnimal.animal}}</p>
<p>Fur color: {{stateAnimal.furColor}}</p>
<p>Population: {{stateAnimal.population}}</p>
<p>Is extinct: {{stateAnimal.isExtinct}}</p>
<p>Is domesticated: {{stateAnimal.isDomesticated}}</p>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex';
export default {
computed:{ ...mapState({ stateAnimal:state => state.modulename.stateAnimal }),
},
}
</script>
modulename.js ( store module)
export default
{
state: {stateAnimal:null, },
getters:{ },
mutations:
{ ['STORE_ANIMALS'] (state, payload)
{ state.stateAnimal = payload;
console.log('state=',state)
},
},
actions:
{ storeAnimals: ({commit}, data) =>
{ console.log('storeanim-data-',data);
commit( 'STORE_ANIMALS', data );
},
}
}
Index.js (for vuex store), you can disable persistedstate as its for saving state if page is refreshed
import Vue from 'vue'
import Vuex from 'vuex'
import modulename from './modules/modulename'
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex)
export default new Vuex.Store({
plugins: [createPersistedState({ storage: sessionStorage })],
state: { },
mutations: { },
actions: { },
modules: { modulename }
})
State is available/shared for all the components
well first of all create a second folder call it services and create service.js for you axios call- good practice and cleaner code overall.
second use vuex. this kind of data is best used with vuex.
As far as I understand GetAnimal.vue is the parent component and you wish to display it in the child component DisplayAnimal.vue.
If so and you wish to see if this works just use props.
you can also send that same information or any other information for the child back to the parent using an $emit().
STRONGLY recommended to use vuex in order to manage the state
Vue.component('product',{
props:{
message:{
type:String,
required:true,
default:'Hi.'
}
},
template:`<div>{{message}}</div>`,
data(){...}
})
//html in the other component you axios call is in this component //<product meesage="hello"></product>
I would pass the animal name/id as a route param to the display page and have that component responsible for fetching and displaying the relevant animal data. This avoids the situation where a user could visit the display page directly via the URL and see an incomplete page.
In situations where you want to share local state between pages, as others have pointed out you'd probably want to use Vuex.
EDIT:
I'm adding some code to my answer as requested by the OP.
Routes:
const routes = [
{ path: "/", component: SearchAnimals },
{ path: "/viewanimal/:name", component: DisplayAnimal, name: "displayAnimal" }
];
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: {{animal.name}}</p>
<p>Fur color: {{animal.furColor}}</p>
<p>Population: {{animal.population}}</p>
<p>Is extinct: {{animal.isExtinct}}</p>
<p>Is domesticated: {{animal.isDomesticated}}</p>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "DisplayAnimal",
data: () => ({
animal: {}
}),
methods: {
fetchAnimal(name) {
axios
.get(`http://localhost:8088/animalsapi?animal=${name}`)
.then(response => {
this.animal = response.data;
});
}
},
created() {
this.fetchAnimal(this.$route.params.name);
}
};
</script>
SearchAnimals.vue:
<template>
<form v-on:submit.prevent="onSubmit">
<textarea
v-model="animal"
name="animal"
type="animal"
id="animal"
placeholder="Enter your animal here"
></textarea>
<button type="submit">Get animal</button>
</form>
</template>
<script>
export default {
name: "SearchAnimal",
data: () => ({
animal: ""
}),
methods: {
onSubmit() {
this.$router.push({
name: "displayAnimal",
params: { name: this.animal }
});
}
}
};
</script>
Obviously this is a bare-bones example, so doesn't contain any error handling etc., but it should get you up and running.
I have a json response from an laravel api with 800 items on it.
I wish to show 15 items to the user. The user ll have to click 'Load More' button to show more 15.
Everything is working as expected but Vue Js throws this warning :
[Vue warn]: Error in render: "TypeError: Cannot read property 'slice' of undefined"
Code:
<div class="col" v-for="value in products.products.slice( 0, productsShow)">
//logic {{value.content}}
</div>
<button
v-if="products.products.length > 15 &&
productsShow < products.products.length"
#click="loadMore">
Load more products
</button>
VueJs
<script>
import axios from 'axios'
export default {
data() {
return {
products: [],
productsShow: ''
}
},
methods: {
loadMore () {
this.productsShow += 15
}
},
created() {
axios.get('/api/products/pt').then(response => this.products = response.data)
this.productsShow = 15
}
}
</script>
Also Tried this :
<script>
import axios from 'axios'
export default {
data() {
return {
products: [],
productsShow: 15
}
},
methods: {
loadMore () {
this.productsShow += 15
}
},
created() {
axios.get('/api/products/pt').then(response => this.products = response.data)
}
}
</script>
Edit
Api response : Api Laravel Response
It's because you are instantiating products as an array, when it's intended to be an object with the property 'products'. So you should change your data declarations to look like this.
export default {
data() {
return {
products: {
products: []
},
productsShow: 15
}
}
}
also in your template, you can do this as well.
<div
class="col"
v-if="products.products"
v-for="value in products.products.slice( 0, productsShow)"
>
Either one will work.
Check if you are returning a json object and not a php one meaning does your api endpoint has something like this return response()->json($response);
I want some help in getting data form json array file is in the link
Html
<div>
<div v-for="data in myJson.id " >{{ data }}</div>
</div>
js
import json from '.././json/data.json'
export default {
components: {
MainLayout,
},
data: function(){
return {
myJson:json
}
},
method:{
getjson:function(){
this.json = JSON.parse(myJson);
}
}
}
i want to access only the data with some specific id and i cannot access it using the syntax i am using
edit
Json file
Apparently, you do not even need JSON.parse. It seems to work without it... Put your JSON file in the same directory as your component and try this:
import data from './data.json'
export default {
created () {
for (const item of data[0]['file']) {
console.log(`
Name: ${item.name}
Type: ${item.type}
Size: ${item.filesize}
Dimensions: ${item.dimension[0].width}x${item.dimension[0].height}
`)
}
}
}
You should see information from your JSON file in your console when the page loads.
<script>
import MainLayout from '../layouts/Main.vue'
import json from '.././json/data.json'
export default {
components: {
MainLayout,
},
data: function(){
return {
myJson: json[0].file
}
},
method:{
}
}
</script>
html
<div v-for="data in myJson">
{{ data.name }}
{{ data.filesize}}
{{ data.dimension[0].width}}x{{data.dimension[0].height}}
</div>
using the above code i utilized and used to implemented according to my needs and it worked