I am new to vue.js I am going to make a news app using a API.
In here I used v-for to iterate some codes. I think there is a problem in v-for. because it gives error. error has been included end of this question.
I used following codes to show search results
<template>
<div class="col-md-12">
<div>
<h2>Results</h2>
<div class="card mb-3" v-for="item in resultList">
<img class="card-img-top" src="" alt="Card image cap" height="100" width="200">
<div class="card-body">
<h5 class="card-title">{{ item.name }}</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<div class="button">
<button type="button" class="btn btn-primary">Show more</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
props: ['resultList']
}
</script>
following codes used to get the api data(search api data)
<template>
<div class="container1">
<div class="form-group row">
<label for="exampleInputPassword1">Search Music</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="exampleInputPassword1" placeholder="Type here"
#input="keypressed">
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default{
data () {
return {
newset: []
}
},
methods: {
keypressed () {
var key = event.target.value
axios.get('http://newsapi.org/v2/everything?q=' + key +
'&sortBy=publishedAt&apiKey=b5ac77726d0a4460bd82b57210b2efb7')
.then(response => {
this.newset = response.data.articles
})
.catch(e => {
this.error.push(e)
})
this.$emit('newDataset', this.newset)
}
}
}
</script>
but it gives an error. error is
https://google.com/#q=vue%2Frequire-v-for-key Elements in iteration expect to have 'v-
bind:key'
directives
src\components\ResultArea.vue:5:5
<div class="card mb-3" v-for="item in resultList">
^
You need to add :key binding:
<div class="card mb-3" v-for="(item, index) in resultList" :key="index">
key value should be unique for every item. If your list items has any id it is good idea to use this id here:
<div class="card mb-3" v-for="item in resultList" :key="item.id">
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item. check the link for better understanding
https://v2.vuejs.org/v2/guide/list.html#Maintaining-State
Related
I'm new to Angular and I can't really understand what is the problem I'm facing. I'm trying to pass object from an *ngFor to his component.
Here is a simple *ngFor that iterate an Array
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor }}</span>
</span>
</div>
</div>
I want to avoid this long interpolation so I want pass the current let alarm to the component and assign three attributes to an object and display it,
customMethod(alarm) {
this.location.floor = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
this.location.room = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].room;
this.location.bed = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].bed;
}
Here is what I expect:
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ location.floor }}</span>
</span>
</div>
</div>
And show the attribute's object location with string interpolation for each object alarm.
What is the best way to do this?
You want to avoid having any logic in your template (.html) file so I'll advise doing the logic in your component file.
You can prepare the alarms array before it's sent into the template.
#Component(..)
export class SomeComponent {
private _alarms;
#Input()
set alarms(alarms) {
this._alarms = alarms.map(alarm => customMethod(alarm))
}
get alarms() {
return this._alarms
}
}
function customMethod(alarm) {
return {
...alarm, // <<< remove this if you just want locations
locations: {
floor: alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor,
room: ....,
bed: ...
}
}
Then in your template
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.location.floor }}</span>
</span>
</div>
</div>
Create a helper method to get you the value you want to display, and then just call that from the template.
You can do anything to the object to get the value you want to display in here since it's just a funciton:
createMyString(alarm) {
return alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
}
Then in your template
{{createMyString(alarm)}}
In my project I use medium-zoom with pagination. On first page it works well but on second, third, fourth... I have to click several times for close image...on second page...two times, on third 3 times...
it seems to be a problem with maybe any index number?
Here is my code:
<template>
<div>
<div v-if="loading" class="text-center">
<i class="fas fa-spinner fa-pulse fa-5x"></i>
</div>
<div v-else>
<div v-for="(item, imageIndex) in pageOfItems" :key="item.id" class="m-3">
<div class="row mt-3">
<div class="col-lg-9 my-auto" v-html="item.mytext"></div>
<div class="col-lg-3 my-auto text-center">
<article class="container">
<img
class="img-thumbnail"
:src="'http://localhost:4000/api/galeria/' + item.galeriaId + '_f.jpg'"
/>
</article>
</div>
</div>
<hr class="hr1" />
</div>
</div>
<div class="pb-0 pt-3 text-center">
<jw-pagination :items="info" :page-size="10" #changePage="onChangePage"></jw-pagination>
</div>
</div>
</template>
<script>
import mediumZoom from 'medium-zoom'
import axios from 'axios'
export default {
data() {
return {
info: [],
customLabels,
pageOfItems: [],
loading: true,
}
},
mounted() {
axios
.get('http://localhost:4000/api/fetch_galeria.php/')
.then((response) => (this.info = response.data))
.finally(() => (this.loading = false))
},
updated() {
mediumZoom('article img', {
background: 'transparent',
})
},
methods: {
onChangePage(pageOfItems) {
// update page of items
this.pageOfItems = pageOfItems
},
},
}
</script>
You will pretty much need to detach the event listeners here. Because it should be a lot of them added everytime due to the updated hook.
A naive implementation would be to add mediumZoom on the mounted hook. And when you do have a new changePage event, to detach it from all the images, then to apply it to the new ones with the same mediumZoom call.
Below is a way to see which event listeners (and probably how many) you have linked to a specific VueJS component. Select it in the Vue devtools and then, you will have access to the element's properties via $vm0.
I have this problem:
I render a list obtained by an API call with a v-for, and if you write into a form, only the elements that match the key written into the form are showed
Now, I need to sort this elements by name and by price too using a dropdown with buttons
is it possible?
Sorry for the external link, but I have some trouble pasting code into StackOverflow, maybe due the vue-boostrap
HTML part
code part
<div>
<b-dropdown id="dropdown-1" text="Dropdown Button" class="m-md-2">
<b-dropdown-item>Default Sort</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item #click="sortByName">Sort by Name</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item>Sot by Price</b-dropdown-item>
</b-dropdown>
</div>
<div class="d-flex flex-wrap justify-content-center">
<div class="card" v-for="product in filteredCatalogue" :key="product.id">
<img class="product pimage" :src="product.images.small" />
<hr class="product black-line" />
<h5 class="product name text-uppercase">{{product.name}}</h5>
<h5 class="product short-description">{{product.descriptions.short}}</h5>
<h5
class="product price"
v-if="product.price.currency_symbol=='€'"
>€ {{product.price.sell}}</h5>
<b-button id="button-shop" squared variant="warning">
<i class="fas fa-shopping-cart"></i>
<div id="yellow-button-text">ADD TO CART</div>
</b-button>
</div>
</div>
<form class="form-inline justify-content-center">
<div class="form-group">
<input
class="form-control bg-white border border-secondary"
type="text"
v-model="key"
placeholder="Cerca tra i prodotti"
value
autocomplete="off"
/>
</div>
</form>
import axios from "axios";
import { cacheAdapterEnhancer } from "axios-extensions";
export default {
data() {
return {
catalogue: [],
key: ""
};
},
created() {
axios
.get(
API_URL,
cacheAdapterEnhancer
)
.then(response => {
this.catalogue = response.data;
console.log(this.catalogue);
})
.catch(error => console.log(error));
},
computed: {
filteredCatalogue: function() {
return this.catalogue.filter(product => {
return product.name.toLowerCase().match(this.key.toLowerCase());
});
}
}
};
Check sort method on JavaScrtipt array here.
So I have this shallowMounted vue component:
<div class="card p-relative">
<div class="card-header">
<div class="card-title h4">
a cute title
<!---->
<!---->
</div>
</div>
<!---->
<div class="card-body">
<h3 class="circle" style="background-color: rgb(237, 15, 59);"></h3>
</div>
<div>
<h6 class="card-body">Value: 35</h6>
</div>
</div>
I am doing a shallowMount:
const wrapper = shallowMount(Component, { proposData: { 'shape': 'circle'}})
Later trying to find all the classes, so I can somehow find the class circle. But what I got:
const results = wrapper.classes()
console.log(results) // ['card', 'p-relative']
How to find the h3 or class 'circle' :/
Completely Noob to frontend. Please forgive for using wrong vocabulary.
As mentioned in https://vue-test-utils.vuejs.org/api/selectors.html to access direct descendants.
I did the following:
const shape = wrapper.find('.card-body > h3')
console.log(shape.classes()) //['circle']
I want to print out the value in my array, not the ['value']. It should create a div='col-md' box for each index in the array.
const app = new Vue({
el: "#app",
data() {
return {
step: 1,
ansPurchaseonly: [
['Leasehold', 'Freehold'],
['Leasehold', 'Freehold']
],
HTML template:
<div class="row white-boxes justify-content-center">
<div class="col-md-3 col-sm-12 h-100 d-table" v-for="(opt, index) in ansPurchaseonly">
<span>{{ opt }}</span>
</div>
</div>
</div>
Instead I get an output like [ "Leasehold", "Freehold" ] in the html rendered page. I want just:
Leasehold
Freehold
Seems you need to run another loop
<div class="col-md-3 col-sm-12 h-100 d-table" v-for="opt in ansPurchaseonly">
<div v-for="elem in opt">
<span>{{ elem }}</span>
</div>
</div>
You can use another v-for, because your "opt" is still an array or alternatively you can use join the values like
<div class="row white-boxes justify-content-center">
<div class="col-md-3 col-sm-12 h-100 d-table"
v-for="(opt, index) in ansPurchaseonly">
<span>{{ opt.join(' ') }}</span>
</div>
</div>