Display and search through a JSON's items in Vue.js
I have put together this small application that displays a "Users" JSON in an HTML5 table.
I use Bootstrap 3, Axios and Vue.js 2 for this purpose.
Here is the code:
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
It works, but I am certain there is room for improvement.
twitter-bootstrap vue.js axios
add a comment |
I have put together this small application that displays a "Users" JSON in an HTML5 table.
I use Bootstrap 3, Axios and Vue.js 2 for this purpose.
Here is the code:
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
It works, but I am certain there is room for improvement.
twitter-bootstrap vue.js axios
add a comment |
I have put together this small application that displays a "Users" JSON in an HTML5 table.
I use Bootstrap 3, Axios and Vue.js 2 for this purpose.
Here is the code:
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
It works, but I am certain there is room for improvement.
twitter-bootstrap vue.js axios
I have put together this small application that displays a "Users" JSON in an HTML5 table.
I use Bootstrap 3, Axios and Vue.js 2 for this purpose.
Here is the code:
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
It works, but I am certain there is room for improvement.
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
var app = new Vue({
el: '#app',
data: {
users: ,
loading: true,
errored: false,
url: "https://randomuser.me/api/?&results=500&inc=name,location,email,cell,picture",
search: '',
page: 1,
perPage: 25,
pages: ,
},
methods: {
getUsers() {
axios
.get(this.url)
.then(response => {
this.users = response.data.results
})
.catch(error => {
console.log(error)
this.errored = true
})
.finally(() => this.loading = false)
},
setPages(users) {
this.pages.length = 0;
var numberOfPages = Math.ceil(users.length / this.perPage);
for (var index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(users) {
var page = this.page;
var perPage = this.perPage;
var from = (page * perPage) - perPage;
var to = (page * perPage);
return users.slice(from, to);
},
scrollToTop() {
$("html, body").animate({
scrollTop: 0
}, 500);
return false;
},
},
created() {
this.getUsers();
},
watch: {
displayedUsers() {
this.setPages(this.searchResults);
}
},
computed: {
displayedUsers() {
return this.paginate(this.searchResults);
},
searchResults() {
this.page = 1;
return this.users.filter((user) => {
const {
first,
last
} = user.name;
const {
email
} = user;
const {
city
} = user.location;
const lowerCaseSearch = this.search.toLowerCase()
return `${first} ${last}`.toLowerCase().match(lowerCaseSearch) ||
email.toLowerCase().match(lowerCaseSearch) ||
city.toLowerCase().match(lowerCaseSearch);
});
}
},
filters: {
lowercase(value) {
return value.toLowerCase();
},
capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
titlecase(value) {
return value.toLowerCase().replace(/(?:^|[s-/])w/g, function(match) {
return match.toUpperCase();
})
}
}
});
.table-container {
margin: 10px;
}
.table-container .panel-heading {
font-weight: bold;
}
.table-container .panel-heading {
display: flex;
align-items: center;
}
.table-container .panel-heading h2 {
margin: 0 auto 0 0;
font-size: 18px;
font-weight: bold;
}
.table-container .panel-heading .searchbox {
margin-left: 10px;
}
.table-container .panel-body {
padding: 0;
}
.table-container table {
margin-bottom: 0;
border: none;
}
.table-container table tr:last-child td {
border-bottom: none;
}
.table-container table tr th {
font-weight: bold;
}
.table-container table tr th:first-child, .table-container table tr td:first-child {
border-left: none;
}
.table-container table tr th:last-child, .table-container table tr td:last-child {
border-right: none;
}
.table-container table tr td {
padding: 2px 8px !important;
vertical-align: middle;
}
.table-container table tr td .picture {
padding-right: 10px;
}
.table-container table tr td img {
max-height: 30px;
width: auto;
border: 1px solid #c7c7c7;
}
.pagination {
margin-top: 5px;
}
.pagination li a:focus, .pagination li a:hover {
background: inherit;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app" class="container">
<div class="panel panel-default table-container">
<div class="panel-heading clearfix">
<h2 class="pull-left">Users</h2>
<div class="searchbox">
<input type="text" v-model="search" class="form-control" placeholder="Search...">
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th class="text-right">#</th>
<th>Name</th>
<th>Email</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, index) in displayedUsers">
<td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
<td>
<span class="picture">
<img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
</span>
<span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
</td>
<td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
<td>{{user.location.city | titlecase}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<nav class="text-center" aria-label="Page navigation">
<ul class="pagination pagination-sm">
<li @click="scrollToTop">
<a href="#" @click="page = 1;" aria-label="First">
<span aria-hidden="true">«</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
<span aria-hidden="true">‹</span>
</a>
</li>
<li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}" @click="scrollToTop"><a href="#" @click="page = pageNumber;">{{pageNumber}}</a></li>
<li @click="scrollToTop">
<a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
<span aria-hidden="true">›</span>
</a>
</li>
<li @click="scrollToTop">
<a href="#" @click="page = pages.length;" aria-label="Last">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
twitter-bootstrap vue.js axios
twitter-bootstrap vue.js axios
asked 31 mins ago
Razvan Zamfir
9210
9210
add a comment |
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210483%2fdisplay-and-search-through-a-jsons-items-in-vue-js%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210483%2fdisplay-and-search-through-a-jsons-items-in-vue-js%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown