My vue component, you can see below :
<template>
<div>
<div class="panel-group" v-for="item in list">
...
<div :class="'alert ' + item.created_at ? 'alert-success' : 'alert-warning'">
...
</div>
</div>
</template>
<script>
export default {
...
computed: {
list: function() {
return this.$store.state.transaction.list
},
...
}
}
</script>
When executed, it display alert-success. Whereas item.created_at = NULL
Should it display alert-warning
If the above conditions are incorrect?
How the correct writing?
if alert should always be present you could write:
<div :class="['alert', item.created_at ? 'alert-success':'alert-warning']">...</div>
Don't concatenate in the bindings, use the list notation!
Related
I have a JobComponent.vue component where I fetch data from a VUEX Store. This component is used on two separate pages, first page Home.vue and second page AllJobs.vue.
In AllJobs.vue I used JobComponent.vue and everything is works fine, it's rendering all the jobs, but, here comes the problem...
In Home.vue I want to render only the last 5 jobs, so in store I make a getter that slice me only the latest 5 jobs.
How can I use this latestJobs from getters on the same component?
When I import the component in Home.vue page I can't use another v-for direct on the component...
here you can see my project structure and files
Home.vue
<template>
<div class="cards-container">
<JobComponent />
</div>
</template>
JobComponent.vue
<template>
<div v-for="job in allJobs" :key="job.id" class="card">
<div class="position">{{ job.position }}</div>
<div class="department">{{ job.department }}</div>
<div class="location">
<span class="material-symbols-outlined">location_on</span>
{{ job.location }}
</div>
<span class="material-symbols-outlined right-arrow">arrow_right_alt</span>
<span #click="deleteJob(job.id)" class="material-symbols-outlined right-arrow">delete</span>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
methods: {
...mapActions(['fetchJobs', 'deleteJob']),
},
computed: mapGetters(['allJobs']),
created() {
this.fetchJobs();
}
}
</script>
store.js (vuex)
const getters = {
allJobs: (state) => state.jobs,
latestJobs: (state) => {
const response = state.jobs.slice(0, 5);
return response;
}
};
Your component should be as independent as possible from the store. It's role is to display what ever is provided so it could be reused as you want, using props :
JobComponent.vue
<template>
<div class="card">
<div class="position">{{ position }}</div>
<div class="department">{{ department }}</div>
<div class="location">
<span class="material-symbols-outlined">location_on</span>
{{ location }}
</div>
<span class="material-symbols-outlined right-arrow">arrow_right_alt</span>
<span #click="$emit('deleteJob', id)" class="material-symbols-outlined right-arrow">delete</span>
</div>
</template>
<script>
export default {
props: {
id: string,
position: string,
department: string,
location: string
}
}
</script>
In this component you only display the provided data, and leave the responsibility of the parent component to choose how many components to display.
Home.vue
<template>
<div class="cards-container">
<JobComponent v-for="job in jobs" :key="job.id" :id="job.id" :position="job.position" :department="job.department" :location="job.location" #delete-job="deleteJob" />
</div>
</template>
<script>
export default {
created() {
this.$store.dispatch('fetchJobs')
},
computed: {
jobs() {
return this.$store.getters['latestJobs'] // Or allJobs, just make sure your getter returns an array even if no jobs are loaded yet.
}
},
methods: {
deleteJob() {
// Your logic for job delete
}
}
}
</script>
I have this link to another component with params :
<div class="dropdown-menu bg-light" aria-labelledby="navbarDropdown">
<div v-for="category in categories" :key="category.id">
<div v-if="lang=='ku'"><li><a class="dropdown-item font-weight-bold py-2" href="#" ><router-link :to="{name:'category',params:{id:category.id}}">{{category.catagory_ku}}</router-link></a></li></div>
<div v-else><li><a class="dropdown-item font-weight-bold py-2" href="#" ><router-link :to="{name:'category',params:{id:category.id}}">{{category.catagory_ar}}</router-link></a></li></div>
</div>
</div>
the category component like this :
<template>
<div style="margin-top:132px">
Categories {{id}}
</div>
</template>
<script>
export default {
data(){
return {
id :''
}
},
created(){
this.id=this.$route.params.id
}
}
</script>
when i pressed the route link the id value changed in url but in the page view it just take first id value I clicked and not be changed after I clicked another same link by different id value
Try to define the id as computed property :
<template>
<div style="margin-top:132px">
Categories {{id}}
</div>
</template>
<script>
export default {
computed:{
id(){
return this.$route.params.id
}
}
}
</script>
this should be in the mounted hook
created(){
this.id=this.$route.params.id
}
// replace with
mounted(){
this.id = this.$route.params.id
}
also if you wanna perform some extra actions related to the id changes, you can watch the route
<template>
<div style="margin-top:132px">
Categories {{ id }}
</div>
</template>
<script>
export default {
data() {
return {
id: ''
}
},
mounted() {
this.id = this.$route.params.id
},
watch: {
$route(to) {
this.id = to.params.id
// do other logics here
}
}
</script>
My vue component (second component) like this :
<template>
<div class="row">
<div v-for="item in options">
<div class="panel panel-default panel-product">
....
</div>
</div>
<div>
<a href="#" class="panel-more">
<span>{{priceMin}} test {{priceMax}}</span>
</a>
</div>
</div>
</template>
<script>
...
export default {
...
computed: {
...mapGetters([
'getListByPrice', 'getPriceMin', 'getPriceMax'
]),
options() {
return this['getListByPrice']
},
priceMin() {
return this['getPriceMin']
},
priceMax() {
return this['getPriceMax']
},
},
...
}
</script>
If the code executed, the data shown does not match
If I console.log(this['getListByPrice']), there are 5 data. But shown in loops of more than 5 data
If I remove the code :
<span>{{priceMin}} test {{priceMax}}</span>
The result is correct
Why if I call priceMin and priceMax by computed, the result shown does not match?
I think that you don't need:
options() {
return this['getListByPrice']
},
priceMin() {
return this['getPriceMin']
},
priceMax() {
return this['getPriceMax']
},
Just use the items in ...mapGetters directly in your mustache tags. Also, use vue's chrome plugin to examine your vuex store.
You posted your vuex store so this comment addresses that. Your store is incorrect. price should be in your store, not priceMax and priceMin. Those are mutations of the state. Please read through the vuex docs.
works with my other routes like "/dashboard", etc, but is appearing in all routes. I basically want this template to only appear when the url is "/". Have tried it throughout my project and just plum doesn't work. PLease help and thank you!! for any suggestions.
<template v-if="main">
<div id="accordion-nav">
<div class="accordion-panels">
Dashboard <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
<div class="accordion-panels">
Shifts <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
<div class="accordion-panels">
Other <i class="fa fa-caret-right" aria-hidden="true"></i>
</div>
</div>
</template>
<script>
export default {
name: 'accordion-nav',
computed: {
main: function () {
return this.$route.path.indexOf('/') === 0
}
}
}
</script>
<style scoped>
</style>
Setup the v-if in the sidebar component itself
'<template>
<div id="sidebar" class="sidebar"
:class="{ isOpen: isOpen }">
<div class="sidebar-opener"
#click="toggle">{{openerText}}</div>
<accordion-nav v-if="main"></accordion-nav>
<accordion></accordion>
</div>
</template>'
<script>
export default {
data () {
return {
}
},
computed:{
main(){
return this.$route.path === '/'
}
}
}
</script>
With this.$route.path you get a string that equals the path of the current route resolved as absolute path in any component of your app.
So you can use this to check whether you are in the root route using:
this.$route.path === '/'
Here is the example fiddle
Use v-if="main" as a method v-if="main()" instead of a computed property
methods: {
main: function () {
return this.$route.path.indexOf('/') === 0
}
Methods do such complex updates much better than computed properties. Computed = lazy
Using VUE 2.0 and VUEX I am a bit confused about how to pass data from parent to child.
<template>
<div id="app" class="container">
<div class="card" v-for="(triad, index) in triads">
<div class="row">
<div class="col-sm-4">
<people />
</div>
<div class="col-sm-4">
<places />
</div>
<div class="col-sm-4">
<equipment />
</div>
</div>
</div>
</div>
</template>
I am looping through an array named "triads":
state: {
triads: [
{
people: [],
places: [],
equipment: []
}
]
}
I want to send the triad variable to <people />, <places /> and <equipment />.
How do I get the content from the parent template to the child template? Thank you.
You just need to add PROP to your child components and then bind data.
E.g. <people :yourProp='triad'>
In your child components (as per docs: https://v2.vuejs.org/v2/guide/components.html#Props):
Vue.component('people', {
// declare the props
props: ['yourProp'],
// just like data, the prop can be used inside templates
// and is also made available in the vm as this.message
template: '<span>{{ yourProp }}</span>'
})
you do not need vuex to just pass data. You need Vuex to share states between components (bi-directional).
you can pass the properties down by the means of props
<template>
<div id="app" class="container">
<div class="card" v-for="(triad, index) in triads">
<div class="row">
<div class="col-sm-4">
<people :someproperty='triad'></people>
</div>
<div class="col-sm-4">
<places :someproperty='triad'></places>
</div>
<div class="col-sm-4">
<equipment :someproperty='triad'></equipement>
</div>
</div>
</div>
</div>
</template>
and inside each of these children components, mention the props like so:
export default {
props: ['someproperty']
}
I think your parent component too doesnt have access to the property directly, so you could use mapGetters in the parent to have access to it, at the same time, it follows that your state too has a getter.
state: {
triads: [
{
people: [],
places: [],
equipment: []
}
]
},
getters: {
getTriads: (state) => {
return state.triads
}
}
Now, you can use mapGetters in your parent:
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
'triads': 'getTriads'
})
}
}
If that is too much of a setup, just try this
export default {
computed: {
triads () {
/**
* You could also try, return this.$store.state.triads
* but DONT do that, that defeats the purpose of using vuex.
*/
return this.$store.getters.getTriads
}
}
}