vue prop display columns with different sizes wrapped in container - javascript

I'm currently working on a page for our company's new website. In this design we have a blog page which displays our blog entries. I request these blogs with Cockpit CMS & axios in my NuxtJs project that makes it a object.
At this moment I'm struggling with the following: In the design the blogs are displayed in rows of 3 items, and after that 2 items. I'm using the BULMA framework and to display my columns the correct way I need to wrap the columns like follow:
<div class="columns">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
<div class="columns">
<div class="column"></div>
<div class="column"></div>
</div>
<div class="columns">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
A short version of my code can be found here:
https://jsfiddle.net/06o5nvkd/
At this moment I have a component which gets my blogs through a prop called 'blogs'. Me and my colleague can't find a good working method to split the blogs array into chunks of 2 & 3 to display them correctly in a wrapping columns div.
Is anyone here able to help us out? Any more information that's needed is welcome.

Use a computed property to chunk your blogs array on the fly and use that array with the chunks to create the columns.
Computed properties detect addtions to the blogs array automatically (when using this.blogs inside), so fetching some new blog entries will be no problem.
new Vue({
el: "#app",
data: {
blogs: [
{ title: "Learn JavaScript" },
{ title: "Learn Vue" },
{ title: "Play around in JSFiddle" },
{ title: "Build something awesome" },
{ title: "a" },
{ title: "b" },
{ title: "c" },
{ title: "d" },
{ title: "e" },
{ title: "f" },
]
},
computed: {
blogsChunked() {
let blogs = this.blogs;
let chunkSize = 2;
let blogsChunked = [];
while (blogs.length > 0) {
let chunk = blogs.slice(0, chunkSize);
blogs = blogs.slice(chunkSize);
blogsChunked.push(chunk);
chunkSize == 2 ? chunkSize++ : chunkSize--;
}
return blogsChunked;
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
div.column {
color: white;
background-color: grey;
margin: 5px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<section class="blogs has-padding-bottom-xxl">
<div class="container">
<div class="columns is-mobile" v-for="(chunk, index) in blogsChunked" :key="index">
<div class="column" v-for="(blog, key) in chunk" :key="key">
{{ blog.title }}
</div>
</div>
</div>
</section>
</div>

One solution is to have nested arrays & v-for loops.
<div id="app">
<section class="blogs has-padding-bottom-xxl">
<div class="container">
<div class="columns" v-for="(blogs, key) in blogsArr" :key="key">
<div class="column" v-for="(blog, index) in blogs" :key="index">
{{ blog.title }}
</div>
</div>
</div>
</section>
</div>
new Vue({
el: "#app",
data: {
blogsArr: [
[{ title: "Learn JavaScript" },
{ title: "Learn Vue" }],
[{ title: "Play around in JSFiddle" },
{ title: "Build something awesome" }]
]
}
})
https://jsfiddle.net/3vqydakw/

Related

CDK Drag&Drop nested lists

I have two objects, Users and Info.
I intend to present users in different columns (individualize them) and within each User I intend to put the respective information where the User ID is the same as the IDUser in the info object. Basically, I intend to present the Obejto Info information within the list of each user, respectively.
At the moment I have two lists (users and info) I want to drag and drop between placing them vertically and horizontally, but without success.
Someone can help me solve this problem in order to pass the cards from one column to another (from user to user).
Example: In the column named Name1 I intend to place the card with the text Expand in the column named Name2.
Thank you
DEMO
html
<div style="width:100%; height:100%; display:flex; justify-content:center">
<div *ngFor="let usr of Users" style="width: 20%;">
<div class="card">
<div class="card-header" style="display: flex; align-items: center; justify-content: center;">
<span>{{usr.name}}</span>
</div>
<div class="card-body" style="height:100%" cdkDropList
cdkDropListOrientation="vertical" [cdkDropListData]="Info"
(cdkDropListDropped)="drop($event)">
<div *ngFor="let item of Info">
<div *ngIf="usr.id == item.idUser" cdkDrag>
<div class="card">
<div class="card-header" style="padding: 0px;">
<span>{{item.text}}</span>
</div>
<div class="card-body" style="padding: 0px;position: relative;">
<span>{{item.text}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
.ts
Users = [
{ id: 1, name: "Name1" },
{ id: 2, name: "Name2" },
{ id: 3, name: "Name3" }
];
Info = [
{ idUser: 1, text: "Expand1" },
{ idUser: 1, text: "Expand11" },
{ idUser: 2, text: "Expand2" },
{ idUser: 2, text: "Expand22" },
{ idUser: 3, text: "Expand33" },
{ idUser: 3, text: "Expand33" }
];
drop(event: CdkDragDrop<string[]>) {
console.log("TO", event.previousContainer.data[event.previousIndex]);
console.log("FROM", event.previousContainer.data[event.currentIndex]);
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
You can do multiple changes to your approach to solve this issue:
You technically just have a single data source for data and that will not work so transform your data structure so that each user will have an array to UserInfo items.
Use cdkDropListGroup on container element which contains all cdkDropList
and that's all!
import {
Component
} from "#angular/core";
import {
CdkDragDrop,
moveItemInArray,
transferArrayItem
} from "#angular/cdk/drag-drop";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
Users = [{
id: 1,
name: "Name1",
items: [{
idUser: 1,
text: "Expand1"
}, {
idUser: 1,
text: "Expand11"
}]
},
{
id: 2,
name: "Name2",
items: [{
idUser: 2,
text: "Expand2"
}, {
idUser: 2,
text: "Expand22"
}]
},
{
id: 3,
name: "Name3",
items: [{
idUser: 3,
text: "Expand33"
}, {
idUser: 3,
text: "Expand33"
}]
}
];
drop(event: CdkDragDrop < string[] > ) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
}
<div style="width:100%; height:100%; display:flex; justify-content:center" cdkDropListGroup>
<div *ngFor="let usr of Users" style="width: 20%;">
<div class="card">
<div class="card-header" style="display: flex; align-items: center; justify-content: center;">
<span>{{usr.name}}</span>
</div>
<div class="card-body" style="height:100%" cdkDropList id="{{usr.id}}" cdkDropListOrientation="vertical" [cdkDropListData]="usr.items" (cdkDropListDropped)="drop($event)">
<div *ngFor="let item of usr.items">
<div cdkDrag>
<div class="card">
<div class="card-header" style="padding: 0px;">
<span>{{item.text}}</span>
</div>
<div class="card-body" style="padding: 0px;position: relative;">
<span>{{item.text}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Take a look at this stackblitz forked from yours.

How to filter posts in Vue with components and v-bind:class

I'm trying to make an example based on this pen I got from here:
https://codepen.io/conradolandia/pen/YzyPmrv
But I want to use vue-router, I've tried this: (pen: https://codepen.io/conradolandia/pen/vYNERPW)
HTML:
<main class="wrap">
<div id="app">
<router-view></router-view>
</div>
</main>
<template id="post-list-template">
<div class="container">
<div class="row">
<h4>Filter by album:</h4>
<div class="filters">
<button class="btn" v-bind:class="{ active: currentFilter === 'ALL' }" v-on:click="setFilter('ALL')">all</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'art' }" v-on:click="setFilter('art')">art</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'doodles' }" v-on:click="setFilter('doodles')">doodles</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'workshops' }" v-on:click="setFilter('workshops')">workshops</button>
</div>
</div>
<div class="columns is-multiline">
<div class="column is-3" v-if="currentFilter === post.category || currentFilter === 'ALL'" v-bind:key="post.title" v-for="post in posts">
<div class="card post">
<img class="card-img-top" v-bind:src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
</div> <!-- .container -->
</template>
CSS:
body{
background-color: #ccc;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
}
.post {
margin-bottom: 20px;
}
.post img{ width: 100%;}
.tags {background-color: #ccc; padding: 3px 5px;}
.filters {
margin-bottom: 20px;
}
JS:
var postList = Vue.extend({
template: "#post-list-template",
data: function(){
return {
currentFilter:'ALL',
posts: [
{title: "Artwork", image: "https://picsum.photos/g/200?image=122", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=116", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=121", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=133", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=134", category: 'doodles'},
{title: "Pen", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Inking", image: "https://picsum.photos/g/200", category: 'workshops'},
{title: "Artwork", image: "https://picsum.photos/g/200?image=121", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=124", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=13", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=14", category: 'doodles'},
]
}
},
methods: {
setFilter: function(filter) {
this.currentFilter = filter;
}
},
})
// Start a new instance of router (instead of router.map)
var router = new VueRouter({
routes: [
{ path: '/', component: postList }
]
})
// Start a new instance of the Application required (instead of router.start)
new Vue({
el: '#app',
router: router,
})
So far, no luck. The filter kind of works, the first click I make activates a filtering option, but then all filters stop working, and firefox complains with "TypeError: "e is undefined"".
Can somebody point me in the right direction, please? I don't understand why the first codepen link works but the second doesn't.
Clarifying: When I click any filter, filters kind of work, but if I click the "ALL" filter, everything stops working.
Try using a computed function
computed:{
filteredPosts:function(){
if(this.currentFilter==='ALL'){
return this.posts;
}
return this.posts.filter(post=>{
return post.category === this.currentFilter;
})
}
}
You can use filteredPosts instead of posts while looping
<div class="columns is-multiline">
<div class="column is-3" :key="post.title" v-for="post in filteredPosts">
<div class="card post">
<img class="card-img-top" :src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
You don't need to use any condition while looping, since the computed function will do the job.

Understanding how to use pagination in Bootstrap-vue

I have written the following code:
<div>
<div id="app" class="container">
<div class="grid">
<article v-for="tool in tools">
<div class="title">
<h3>{{capitalizeFirstLetter(tool.name)}}</h3>
</div>
<div class="description">
{{tool.description}}
</div>
<br>
<div>
<toggle-button :value=tool.status color="#82C7EB" :width=100 :height=30 :sync="true" :labels="{checked: 'Following', unchecked: 'Unfollowing'}" #change="onChange(tool)"/>
</div>
</article>
</div>
</div>
</div>
Recently I started using Bootstrap-Vue. I'm trying to figure out how to add pagination on the bottom.
I'm not sure how aria-controls works. My goal is to have 9 blocks of tools on each page. How should I add the pagination so I could move to the next 9 blocks of tools?
Since it wasn't clear if you needed client-side pagination or serverside i made an example of both in the snippet.
For simplicity I've made it 3 per page, but you could change it to 9.
The first one gets the initial page on load, and then calls the API every time the page changes by using a watcher, that calls a method with the new page which then retrieves that place and replaces our old data with the new.
The second one loads all the data on page load, and instead slices the data array based on the per_page property, so that only the items for that page is shown.
For this I've used a computed property which automatically updates based on the properties used inside it.
Both paginations have aria-controls defined with the id of the container of our page elements. This is used to tell screen readers what elements the pagination changes.
The classes row, col-*, border, mx-auto, h2 and text-center is classes used for styling and layout and isn't part of the actual solution, so you can freely change or remove them.
new Vue({
el: '#app',
computed: {
pagination2CurrentItems() {
const startIndex = (this.pagination2.current_page - 1) * this.pagination2.per_page;
const endIndex = startIndex + this.pagination2.per_page;
return this.pagination2.items.slice(startIndex, endIndex)
}
},
created() {
this.getPagination1Data()
this.getPagination2Data()
},
filters: {
capitalizeFirstLetter(value) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
},
data() {
return {
pagination1: {
items: [],
per_page: 3,
total_rows: 0,
current_page: 1
},
pagination2: {
items: [],
per_page: 3,
total_rows: 0,
current_page: 1
}
}
},
methods: {
getPagination1Data(page = 1) {
fetch(`https://reqres.in/api/unknown?page=${page}&per_page=3`)
.then((response) => {
return response.json();
})
.then((data) => {
this.pagination1.total_rows = data.total;
this.pagination1.items = data.data;
});
},
getPagination2Data() {
/*
This endpoint only has 12 items total,
so this will get all in one call
*/
fetch(`https://reqres.in/api/unknown?per_page=12`)
.then((response) => {
return response.json();
})
.then((data) => {
this.pagination2.total_rows = data.total;
this.pagination2.items = data.data;
});
}
},
watch: {
'pagination1.current_page'(newPage) {
this.getPagination1Data(newPage)
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.5.0/dist/bootstrap-vue.js"></script>
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.5.0/dist/bootstrap-vue.css" rel="stylesheet"/>
<div id="app" class="container">
<div id="tools_list_1" class="row">
<div class="col-12 h2 text-center">
Server pagination
</div>
<article class="col-3 mx-auto border" v-for="tool in pagination1.items">
<div class="title">
<h3>{{ tool.name | capitalizeFirstLetter }}</h3>
</div>
<div class="description">
{{ tool.pantone_value }}
</div>
</article>
</div>
<div class="row mt-2">
<div class="col-12">
<b-pagination
v-model="pagination1.current_page"
:per-page="pagination1.per_page"
:total-rows="pagination1.total_rows"
aria-controls="tools_list_1"
>
</b-pagination>
</div>
</div>
<div id="tools_list_2" class="row">
<div class="col-12 h2 text-center">
Client pagination
</div>
<article class="col-3 mx-auto border" v-for="tool in pagination2CurrentItems">
<div class="title">
<h3>{{ tool.name | capitalizeFirstLetter }}</h3>
</div>
<div class="description">
{{ tool.pantone_value }}
</div>
</article>
</div>
<div class="row mt-2">
<div class="col-12">
<b-pagination
v-model="pagination2.current_page"
:per-page="pagination2.per_page"
:total-rows="pagination2.total_rows"
aria-controls="tools_list_2"
>
</b-pagination>
</div>
</div>
</div>
If you are interested in server side pagination with url changes of query params (using vue-router in history mode) and you need browser history (back/forward) to work properly, you can check my answer to a similar question. I think it can be adapted to not use b-table.
Place pagination number in url Vuejs

vue.js insert block for every 6th loop element

I have offers cards list rendering thru the loop. Every 3rd col (bootstrap) elements i add row div. Now i need to add another col element (banner block) for every 6th element. For render some thing like that:
How i can implement that?
My code now
<div class="row" v-for="i in Math.ceil(offers.length / 3)">
<div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="offer in offers.slice((i-1)*3, i*3)">
<h2>{{offer.name}}</h2>
<h2>{{offer.desc}}</h2>
</div>
</div>
for loop:
<div class="mycol" v-for="(offer,ind) in offers">
<template v-if="ind % 5 == 0">
<h2>banner</banner>
</template>
<template v-else>
<h2>{{offer.name}}</h2>
<h2>{{offer.desc}}</h2>
</template>
</div>
for new line for every third col you can use css
.mycol:nth-child(3n+1){
clear:left;
}
I would recommend you do less programming in the view and more in the view model. Create a computed that splits up your data into series of offers and banners, and also into rows, then use that computed in a straightforward way.
const chunk = (arr, size) =>
arr
.reduce((acc, _, i) =>
(i % size) ?
acc :
[...acc, arr.slice(i, i + size)], []);
new Vue({
el: '#app',
data: {
offers: []
},
computed: {
rows() {
const withBanners = chunk(this.offers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b), []);
return chunk(withBanners, 3);
}
},
mounted() {
setTimeout(() => {
this.offers = [{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
},
{
name: 'offer'
}
];
}, 500);
}
});
#app {
display: grid;
}
.row {
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(3, auto);
justify-content: left;
}
.box {
width: 8rem;
height: 8rem;
}
.banner {
background-color: #f9c;
}
.offer {
background-color: #99f;
}
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<div class="row" v-for="row in rows">
<div class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12" v-for="item in row">
<div v-if="item.type === 'Banner'" class="banner box">
<h2>{{item.name}}</h2>
</div>
<div v-else class="offer box">
<h2>{{item.name}}</h2>
</div>
</div>
</div>
</div>
This should do exactly what you want.. I had to manipulate the data some because Vue's templating language is not designed to handle the logic for this kind of use case
HTML
<div id="app">
<div v-for="items in rows" class="row">
<div v-for="item in items" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">{{item}}</div>
</div>
</div>
SCRIPT
created () {
while (this.items.length > 0) {
const howMany = (this.rows.length % 3 === 0) ? 3 : 2
const row = this.items.splice(0, howMany)
if (howMany === 2) row.push('banner')
this.rows.push(row)
}
},
https://jsfiddle.net/jamesharrington/k6c0rgL3/17/
I assume that you want to add a banner every 6 elemtns, but you want to show the 6th. I would handle this on my data object, inserting the banner inside it. It is easier. You could split your array on this way.
let firstPart = myData.slice(0,5)
let lastPart = myData.slice(5,)
let newData = [...firstPart, banner, ...lastPart]
Now, you just need to do this every 6 elements.
I recommend to use flex if it is possible.
So the code will look like: http://jsfiddle.net/n89dbo37/
new Vue({
el: '#app',
data() {
return {
items: _.times(20, i => ({type: 'offer'})),
};
},
computed: {
itemsWithBanners() {
let result = [];
this.items.forEach((item, idx) => {
if (idx && idx % 5 === 0) {
result.push({type: 'banner'});
}
result.push(item);
});
return result;
},
},
});
Thanks for everyone, i took Roy J solution, rebuild for my case and get result. My code:
<template>
<div class="section-space80 results-col" >
<div class="container" >
<div class="row">
<div class="col-md-12">
<div class="wrapper-content bg-white pinside40">
<div class="row" v-for="row in rows">
<div v-for="offer in row" class="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">
<div class="lender-listing" v-if="offer.type && offer.type === 'Banner'">
<div class="lender-head">
Banner
</div>
</div>
<div class="lender-listing" v-if="offer.mfoName">
<div class="lender-head">
<div class="lender-logo">Offer</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
const chunk = (arr, size) =>
arr
.reduce((acc, _, i) =>
(i % size) ?
acc :
[...acc, arr.slice(i, i + size)], []);
import axios from 'axios'
export default {
data() {
return {
showOffers: true,
loanOffers: [],
isVisible: false,
loadMore: true,
offset: 0,
rows: ''
}
},
methods: {
getOffersList: function () {
let dataElements = this
dataElements.loading = true
axios.get('/api/v1/getUserOffers')
.then(function (response) {
dataElements.loanOffers = response.data
const withBanners = chunk(dataElements.loanOffers, 5).map((arr) => [...arr, {name: 'banner', type: 'Banner'}]).reduce((a, b) => a.concat(b));
dataElements.rows = chunk(withBanners, 3);
})
},
},
beforeMount(){
this.getOffersList()
}
}
</script>
I offer to use template and loop over it.
Then inside you check v-if="i%6" --> your article v-else --> yuor ad.

Vue "item is not defined" in a "v-for"

I'm trying to use v-for to render for each item, but I got this:
vue.js:616 [Vue warn]: Error in render: "ReferenceError: item is not defined"
found in
---> <Welcome>
<Main>
<Root>
I tried to comment some codes like this:
<div style="padding-top: 20px" v-for="(item,index) in weekRank" v-bind:key="index">
<b>{{item.username}} </b> {{item.point}} / 10
<div v-if="item.point>10" class="progress deep-purple lighten-3" style="flex-grow: 1;height: 16px;">
<!--<div class="determinate deep-purple darken-1" :style="getProgressBarStyle(item.point)"></div>-->
</div>
<div v-else class="progress blue lighten-3" style="flex-grow: 1;height: 16px;">
<!--<div class="determinate blue darken-1" :style="getProgressBarStyle(item.point)"></div>-->
</div>
</div>
But the errors are still there. It seems the problem is not caused by getProgressBarStyle but by <div v-if="item.point>10" or codes above it, because they point where item was referred.
So I commented these:
<!--<<div v-else class="progress blue lighten-3" style="flex-grow: 1;height: 16px;">
<div class="determinate blue darken-1" :style="getProgressBarStyle(item.point)"></div>
</div>-->
And now the errors disappear, but why? I commented these html codes which are supposed to be not related.
I've reproducted this problem with all required code here (Press F12 to see the errors, please)
Preview:
<div style="padding-top: 20px" v-for="(item,index) in weekRank" v-bind:key="index">
<b>{{item.username}} </b> {{item.point}} / 10
<div v-if="item.point>10" class="progress deep-purple lighten-3" style="flex-grow: 1;height: 16px;">
<div class="determinate deep-purple darken-1" :style="getProgressBarStyle(item.point)"></div>
</div>
<div v-else class="progress blue lighten-3" style="flex-grow: 1;height: 16px;">
<div class="determinate blue darken-1" :style="getProgressBarStyle(item.point)"></div>
</div>
</div>
The problem is you are attempting to reference item inside method getProgressBarStyle(), but you name the parameter to this method as todo. You just need to update todo to item. Also I'd consider returning an object for the :style assignment instead of a string. Also you need to probably pass item instead of index to this method in the template as you are attempting to use properties on item such as point:
HTML:
<div class="determinate blue darken-1" :style="getProgressBarStyle(item)"></div>
JS
new Vue({
el: "#app",
data: {
weekRank: [
{ index: 0, username: "Learn JavaScript", point: 9 },
{ index: 1, username: "Learn Vue", point: 7 },
{ index: 2, username: "Play around in JSFiddle", point: 5 },
{ index: 3, username: "Build something awesome", point: 1 }
]
},
methods: {
getProgressBarStyle: function(item) { // change this to 'item'
if (item.point >= 10) return { 'width': 100%' };
return { 'width': item.point * 10 + '%' };
}
}
})
Here is a working example.
Hopefully that helps!
Looking at your Vue component code, you seem to have some errors on your getProgressBarStyle method where you're giving a todo parameter but are referencing item which throws that error. I've used the template code you've provided in the snippet below as well
new Vue({
el: "#app",
data: {
weekRank: [
{ index: 0, username: "Learn JavaScript", point: 9 },
{ index: 1, username: "Learn Vue", point: 7 },
{ index: 2, username: "Play around in JSFiddle", point: 5 },
{ index: 3, username: "Build something awesome", point: 1 }
]
},
methods: {
getProgressBarStyle: function(point){
if (point >= 10) return 'width: 100%';
return 'width: ' + point * 10 + '%'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<h3>Rank</h3>
<body>
<div class="" style="display: flex;">
<div style="min-width: 300px;flex-grow: 1;">
<h6><b>details: </b></h6>
<div style="padding-top: 20px" v-for="(item,index) in weekRank" v-bind:key="index">
<b>{{item.username}} </b> {{item.point}} / 10
<div v-if="item.point>10" class="progress deep-purple lighten-3" style="flex-grow: 1;height: 16px;">
<div class="determinate deep-purple darken-1" :style="getProgressBarStyle(item.point)"></div>
</div>
<div class="determinate blue darken-1" :style="getProgressBarStyle(item.point)"></div>
</div>
</div>
</div>
</div>
</body>
</div>
</div>

Categories

Resources