my code is working fine but i want to know how can i handle pagination page-links (page Numbers) using jQuery Ajax.Can anybody know how to render page numbers and handle page links. Pagination Next button and Previous button working fine but page-links are not working. how can i render page-numbers and handle page-links using ajax?
Now it looks like this:
[Previous, 1, 2, 0, 5, 6, 7, 0, 10, 11, Next]
What do I do to display only 4 page numbers and not all of it ranging from the current page number, like this:
Previous 1 2 3 4 ... 11 Next
index.html
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item">
<a class="page-link" href="#" aria-label="Previous" id="Next">
<span aria-hidden="true"><i class="fa fa-chevron-left"></i></span>
</a>
</li>
<li class="page-item"><a class="page-link active" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#" aria-label="Next" id="Next">
<span aria-hidden="true"><i class="fa fa-chevron-right"></i></span>
</a>
</li>
</ul>
</nav>
index.js
const fakeData = {
data: [{
row: 1,
name: 'a'
}, {
row: 2,
name: 'b'
}, {
row: 3,
name: 'c'
}, {
row: 4,
name: 'd'
}, {
row: 5,
name: 'e'
}, {
row: 6,
name: 'f'
}, {
row: 7,
name: 'g'
}],
totalRecords: 7
};
// output Html
const Story = document.querySelector('#approvedList');
const pagination = document.querySelector('.pagination');
$(function () {
var page = 1,
records = 1,
totalRecords = 0,
search = '';
// Run on page load
fetchData();
// Previous Page
$('[aria-label="Previous"]').click(function () {
if (page > 1) {
page--;
}
fetchData();
});
// Next page
$('[aria-label="Next"]').click(function () {
if (page * records < totalRecords) {
page++;
}
fetchData();
});
// data fetching from API
function fetchData() {
totalCount = fakeData.totalCount;
Story.innerHTML = '';
fakeData.data.slice((page - 1) * records, page * records).map((object) => {
Story.innerHTML +=
`<tr >
<td>${object.row}</td>
<td>${object.name}</td>
</tr >
`;
})
renderPagination();
}
$(document).on('click', '.page-item-numbers a', function () {
page = parseInt($(this)[0].text);
fetchData();
});
function renderPagination() {
$('.page-item-numbers').remove();
let pagesNumbers = Math.ceil(totalRecords / records);
for (let i = 1; i <= pagesNumbers; i++) {
$(`.pagination > li: nth - child(${i})`).after(` < li class="page-item page-item-numbers ${i == page ? 'active' : ''}" > <a class="page-link" href="#">${i}</a></ > `);
}
}
})
I created a fake data variable, your api result should be like that, contain a array of your data and a number that show total count of your data.
const fakeData = {
data: [{
row: 1,
name: 'a'
}, {
row: 2,
name: 'b'
}, {
row: 3,
name: 'c'
}, {
row: 4,
name: 'd'
}, {
row: 5,
name: 'e'
}, {
row: 6,
name: 'f'
}, {
row: 7,
name: 'g'
}],
totalCount: 7
};
const Story = document.querySelector('#approvedList');
$(function() {
var page = 1,
records = 3,
totalCount = 0,
search = '';
// Run on page load
fetchData();
$(document).on('click', '.page-item-numbers a', function() {
page = parseInt($(this)[0].text);
fetchData();
});
// Previous Page
$('[aria-label="Previous"]').click(function() {
if (page > 1) {
page--;
}
fetchData();
});
// Next page
$('[aria-label="Next"]').click(function() {
if (page * records < totalCount) {
page++;
}
fetchData();
});
// data fetching from API
function fetchData() {
totalCount = fakeData.totalCount;
Story.innerHTML = '';
fakeData.data.slice((page - 1) * records, page * records).map((object) => {
Story.innerHTML +=
`<tr>
<td>${object.row}</td>
<td>${object.name}</td>
</tr>`;
})
renderPagination();
}
function renderPagination() {
$('.page-item-numbers').remove();
let pagesNumbers = Math.ceil(totalCount / records);
for (let i = 1; i <= pagesNumbers; i++) {
$(`.pagination > li:nth-child(${i})`).after(`<li class="page-item page-item-numbers ${i == page ? 'active': ''}" ><a class="page-link" href="#">${i}</a></li>`);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" />
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody id="approvedList">
</tbody>
</table>
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item">
<a class="page-link" href="#" aria-label="Previous" id="Previous">
<span aria-hidden="true"><i class="fa fa-chevron-left"></i></span>
</a>
</li>
<li class="page-item">
<a class="page-link" href="#" aria-label="Next" id="Next">
<span aria-hidden="true"><i class="fa fa-chevron-right"></i></span>
</a>
</li>
</ul>
</nav>
Related
I'm using chart.js for showing statistics of reviews and messages of a user, but I'm getting problems with the scripts, now the stats are working but I got this error Cannot find element: #app and I don't know how to manage that.
If I use defer in this script (now I deleted it to see the stats working, but all the rest of the website don't)
<script src="{{ asset('js/app.js') }}"></script>
the stats doesn't work anymore and I get also another error like Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side effects in your templates, such as , as they will not be parsed.
So if I use defer i got errors, if I don't use defer it cannot find #app.
What should I do? Please help me, it's very important!
My app.blade.php file (where the script from before is)
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
{{-- <title>{{ config("app.name", "Bool n Roll") }}</title> --}}
<title>Bool 'n' Roll</title>
<script src="{{ asset('js/app.js') }}"></script>
<link rel="icon" href="{{asset('images/favicon.ico')}}" type="image/x-icon"/>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md shadow-sm bg-nav fixed-nav">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
<img style="height: 50px;" src="{{ asset('images/logorock.png') }}" alt="">
</a>
<button class="navbar-toggler bg-dark" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
#guest
<li class="nav-item login-link rounded ml-2">
<a class="nav-link text-white px-2" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
#if (Route::has('register'))
<li class="nav-item register-link rounded ml-2">
<a class="nav-link title-orange px-2" href="{{ route('register') }}">{{ __('Sei un musicista? Registrati!') }}</a>
</li>
#endif
#else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle title-orange" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ ucfirst(Auth::user()->name) }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/admin">
Dashboard
</a>
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
#csrf
</form>
</div>
</li>
#endguest
</ul>
</div>
</div>
</nav>
<main>
#yield('content')
</main>
<footer class="bg-dark text-white py-5">
<div class="container">
<div class="row text-center">
<div class="col-xs-12 col-md-4 col-lg-4">
<img style="height: 50px;" src="{{ asset('/images/footer-logo.png') }}" alt="">
<h5 class="my-3">Made with <span class="title-pink">♥</span> from Team 4</h5>
</div>
<div class="col-xs-12 col-md-4 col-lg-4">
<h5>Dev Team</h5>
<ul class="list-unstyled">
<li><a class="footer-list title-yellow" href="https://github.com/RobertoZeppilli">Roberto Zeppilli</a></li>
<li><a class="footer-list title-petrol" href="https://github.com/Edomak">Edoardo Maccherini</a></li>
<li><a class="footer-list title-orange" href="https://github.com/fabiopiro">Fabio Piroddi</a></li>
<li><a class="footer-list title-pink" href="https://github.com/michelafranchini">Michela Franchini</a></li>
</ul>
</div>
<div class="col-xs-12 col-md-4 col-lg-4">
<h5 class="my-3">Sei un musicista?</h5>
<ul class="list-unstyled">
<li class="nav-item register-link rounded">
<a class="nav-link title-orange" href="{{ route('register') }}">{{ __('Registrati subito!') }}</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
</div>
#yield('script')
</body>
</html>
My stat view
Here I think I got major problems, maybe the script are not correct? Or there's a better way to place them inside the workflow?
#extends('layouts.app')
#section('content')
<div class="my_container">
<h1 class="stat_title">Le tue statistiche</h1>
#if (count($messages) == 0 && count($reviews) == 0)
<h2 id="empty_page">Non hai statistiche disponibili</h2>
#else
<div class="chart_1">
<h4>Numero di messaggi e recensioni ricevute ogni mese</h4>
<canvas id="myChart"></canvas>
</div>
<div class="chart_1">
<h4>Voti ricevuti ogni mese</h4>
<canvas id="myOtherChart"></canvas>
</div>
#endif
<p class="link_dashboard">Torna alla Dashboard</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js" integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.6/dayjs.min.js" integrity="sha512-bwD3VD/j6ypSSnyjuaURidZksoVx3L1RPvTkleC48SbHCZsemT3VKMD39KknPnH728LLXVMTisESIBOAb5/W0Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>dayjs().format()</script>
<script>
dayjs().format()
var ctx = document.getElementById('myChart');
var ct2 = document.getElementById('myOtherChart');
var commenti = {!! $reviews->toJson() !!};
var messaggi = {!! $messages->toJson() !!};
// console.log(commenti.length);
// console.log(messaggi.length);
var now = dayjs();
if (commenti[0]) {
var primaDataCommento = commenti[0].created_at;
var date1 = dayjs(primaDataCommento);
} else {
var date1 = now;
}
const primaDataMessaggio = messaggi[0].created_at;
const date2 = dayjs(primaDataMessaggio);
var datex;
if (date2 < date1) {
datex = date2;
} else {
datex = date1;
}
var diff = now.diff(datex, 'month');
var diffRece = now.diff(date1, 'month');
var months = [];
var monthsRece = [];
var recensioniMese = [];
var messaggiMese = [];
var voto1 = [];
var voto2 = [];
var voto3 = [];
var voto4 = [];
var voto5 = [];
// prima tabella
var x = 1;
let i = 0;
if (datex.$M == 0) {
diff++;
i++;
x--;
}
for (i; i <= diff; i++) {
var numeroMese = datex.$M + i + x;
months.push(numeroMese + '/2021');
var countRec = 0;
var countMes = 0;
for (let j = 0; j < commenti.length; j++) {
if (numeroMese == dayjs(commenti[j].added_on).$M + 1) {
countRec++;
}
}
for (let j = 0; j < messaggi.length; j++) {
if (numeroMese == dayjs(messaggi[j].added_on).$M + 1) {
countMes++;
}
}
recensioniMese.push(countRec);
messaggiMese.push(countMes);
}
// seconda tabella
x = 1;
i = 0;
if (date1.$M == 0) {
diffRece++;
i++;
x--;
}
for (i; i <= diff; i++) {
var numeroMeseRece = date1.$M + i + x;
monthsRece.push(numeroMeseRece + '/2021');
var countRece1 = 0;
var countRece2 = 0;
var countRece3 = 0;
var countRece4 = 0;
var countRece5 = 0;
for (let j = 0; j < commenti.length; j++) {
if (numeroMeseRece == dayjs(commenti[j].created_at).$M + 1) {
switch (commenti[j].vote) {
case 1:
countRece1++;
break;
case 2:
countRece2++;
break;
case 3:
countRece3++;
break;
case 4:
countRece4++;
break;
case 5:
countRece5++;
break;
default:
break;
}
}
}
voto1.push(countRece1);
voto2.push(countRece2);
voto3.push(countRece3);
voto4.push(countRece4);
voto5.push(countRece5);
}
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: months,
datasets: [
{
label: 'Numero di recensioni',
data: recensioniMese,
backgroundColor: [
'#0000ff8c',
],
borderColor: [
'#0000ff',
],
borderWidth: 1
},
{
label: 'Numero di messaggi ricevuti',
data: messaggiMese,
backgroundColor: [
'#ff00c88c',
],
borderColor: [
'#ff00c8',
],
borderWidth: 1
},
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
var myChart = new Chart(ct2, {
type: 'bar',
data: {
labels: monthsRece,
datasets: [
{
label: 'Recensioni con voto 1',
data: voto1,
backgroundColor: [
'#ff00008c',
],
borderColor: [
'red',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 2',
data: voto2,
backgroundColor: [
'#ffa6008c',
],
borderColor: [
'orange',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 3',
data: voto3,
backgroundColor: [
'#ffff008c',
],
borderColor: [
'yellow',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 4',
data: voto4,
backgroundColor: [
'#b7dd298c',
],
borderColor: [
'#b7dd29',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 5',
data: voto5,
backgroundColor: [
'#57e32c8c',
],
borderColor: [
'#57e32c',
],
borderWidth: 1
},
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
</script>
#endsection
The app.js file
Maybe the problem is here? I was trying to wrap the vue instance inside an addEventListener('load') or something to load the instance later, but it didn't work.
require('./bootstrap');
window.Vue = require('vue');
import router from './router';
var dayjs = require('dayjs')
// dayjs().format()
import Vue from 'vue';
import VueCarousel from 'vue-carousel';
Vue.use(VueCarousel);
// import Vue from "vue";
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
router,
dayjs,
});
The StatController
Everything is ok here, I'll leave it here just to show you the complete workflow of getting the statistics of reviews and messages of a user
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Musician;
use App\Message;
use App\Review;
use Illuminate\Support\Facades\Auth;
class StatController extends Controller
{
public function showStats(){
// prendo i dati del dottore registrato
$musician = Musician::where('user_id', Auth::id())->first();
// accedo alle tabelle dei messaggi e recensioni per prenderne i dati
$messages = Message::where('musician_id', $musician->id)->get();
$reviews = Review::where('musician_id', $musician->id)->get();
return view('admin.musicians.stats', compact('musician', 'messages', 'reviews'));
}
}
Update you app.blade.php. Remove this <script src="{{ asset('js/app.js') }}"></script> from header and put in body after footer.
...
<script src="{{ asset('js/app.js') }}"></script>
#yield('script')
</body>
</html>
Then use #stack('script') to load other script after app.js, update your My Stat View
#extends('layouts.app')
#section('content')
<div class="my_container">
<h1 class="stat_title">Le tue statistiche</h1>
#if (count($messages) == 0 && count($reviews) == 0)
<h2 id="empty_page">Non hai statistiche disponibili</h2>
#else
<div class="chart_1">
<h4>Numero di messaggi e recensioni ricevute ogni mese</h4>
<canvas id="myChart"></canvas>
</div>
<div class="chart_1">
<h4>Voti ricevuti ogni mese</h4>
<canvas id="myOtherChart"></canvas>
</div>
#endif
<p class="link_dashboard">Torna alla Dashboard</p>
</div>
#endsection
#push('script')
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js" integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.6/dayjs.min.js" integrity="sha512-bwD3VD/j6ypSSnyjuaURidZksoVx3L1RPvTkleC48SbHCZsemT3VKMD39KknPnH728LLXVMTisESIBOAb5/W0Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>dayjs().format()</script>
<script>
dayjs().format()
var ctx = document.getElementById('myChart');
var ct2 = document.getElementById('myOtherChart');
var commenti = {!! $reviews->toJson() !!};
var messaggi = {!! $messages->toJson() !!};
// console.log(commenti.length);
// console.log(messaggi.length);
var now = dayjs();
if (commenti[0]) {
var primaDataCommento = commenti[0].created_at;
var date1 = dayjs(primaDataCommento);
} else {
var date1 = now;
}
const primaDataMessaggio = messaggi[0].created_at;
const date2 = dayjs(primaDataMessaggio);
var datex;
if (date2 < date1) {
datex = date2;
} else {
datex = date1;
}
var diff = now.diff(datex, 'month');
var diffRece = now.diff(date1, 'month');
var months = [];
var monthsRece = [];
var recensioniMese = [];
var messaggiMese = [];
var voto1 = [];
var voto2 = [];
var voto3 = [];
var voto4 = [];
var voto5 = [];
// prima tabella
var x = 1;
let i = 0;
if (datex.$M == 0) {
diff++;
i++;
x--;
}
for (i; i <= diff; i++) {
var numeroMese = datex.$M + i + x;
months.push(numeroMese + '/2021');
var countRec = 0;
var countMes = 0;
for (let j = 0; j < commenti.length; j++) {
if (numeroMese == dayjs(commenti[j].added_on).$M + 1) {
countRec++;
}
}
for (let j = 0; j < messaggi.length; j++) {
if (numeroMese == dayjs(messaggi[j].added_on).$M + 1) {
countMes++;
}
}
recensioniMese.push(countRec);
messaggiMese.push(countMes);
}
// seconda tabella
x = 1;
i = 0;
if (date1.$M == 0) {
diffRece++;
i++;
x--;
}
for (i; i <= diff; i++) {
var numeroMeseRece = date1.$M + i + x;
monthsRece.push(numeroMeseRece + '/2021');
var countRece1 = 0;
var countRece2 = 0;
var countRece3 = 0;
var countRece4 = 0;
var countRece5 = 0;
for (let j = 0; j < commenti.length; j++) {
if (numeroMeseRece == dayjs(commenti[j].created_at).$M + 1) {
switch (commenti[j].vote) {
case 1:
countRece1++;
break;
case 2:
countRece2++;
break;
case 3:
countRece3++;
break;
case 4:
countRece4++;
break;
case 5:
countRece5++;
break;
default:
break;
}
}
}
voto1.push(countRece1);
voto2.push(countRece2);
voto3.push(countRece3);
voto4.push(countRece4);
voto5.push(countRece5);
}
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: months,
datasets: [
{
label: 'Numero di recensioni',
data: recensioniMese,
backgroundColor: [
'#0000ff8c',
],
borderColor: [
'#0000ff',
],
borderWidth: 1
},
{
label: 'Numero di messaggi ricevuti',
data: messaggiMese,
backgroundColor: [
'#ff00c88c',
],
borderColor: [
'#ff00c8',
],
borderWidth: 1
},
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
var myChart = new Chart(ct2, {
type: 'bar',
data: {
labels: monthsRece,
datasets: [
{
label: 'Recensioni con voto 1',
data: voto1,
backgroundColor: [
'#ff00008c',
],
borderColor: [
'red',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 2',
data: voto2,
backgroundColor: [
'#ffa6008c',
],
borderColor: [
'orange',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 3',
data: voto3,
backgroundColor: [
'#ffff008c',
],
borderColor: [
'yellow',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 4',
data: voto4,
backgroundColor: [
'#b7dd298c',
],
borderColor: [
'#b7dd29',
],
borderWidth: 1
},
{
label: 'Recensioni con voto 5',
data: voto5,
backgroundColor: [
'#57e32c8c',
],
borderColor: [
'#57e32c',
],
borderWidth: 1
},
]
},
options: {
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
</script>
#endpush
I have a list of articles (105) that i paginated with 10 articles per page. All seems fine on the first page and i am able to go to the next pages with the correct content, but when i click an article on page 2 and onward it is grabbing the index of the very first article in the array.
<div class="news-article-list">
<ul>
<li v-for="(article, index) in allArticles" :key="index">
<a #click="showArticle(index)">
<img :src="article.featureImg" v-if="article.featureImg" alt="Article Feature Image" />
<h2 class="news-title">{{ article.title }}</h2>
<p class="news-date">{{ article.date }}</p>
<p class="short-desc">{{ article.shortDesc }}...</p>
</a>
<a class="read-more" #click="showArticle(index)">Read More</a>
</li>
</ul>
</div>
<ul class="pagination">
<li class="page-item">
<button type="button" class="page-link" v-show="page != 1" #click="page--"><</button>
</li>
<li id="page-numbers">
<button type="button" class="page-link" v-for="pageNumber in pages" #click="page = pageNumber">{{pageNumber}}</button>
</li>
<li class="page-item">
<button type="button" class="page-link" v-show="page < pages.length" #click="page++">></button>
</li>
</ul>
the showArticle function:
showArticle: function showArticle(selected) {
this.selectedArticle = selected;
window.location = this.filteredArticles[this.selectedArticle].url;
}
to explain my array a little more, once the page is "created" i put it in a new array called filteredArticles as i have functions that are in place for filtering based on category, which is why you see the window.location is equal to this.filteredArticles.
My Pagination js:
data: function() {
return {
filteredArticles: [],
timer: null,
page: 1,
currentPage: 1,
perPage: 10,
pages: [],
articles: [
{
title: 'title here',
date: 'date here',
shortDesc: 'description here',
url: 'url to article - had to put each article into a separate file',
category: 'category',
featureImg: 'Image for article'
},
{}
]
},
computed: {
allArticles() {
return this.paginate(this.filteredArticles);
}
},
setPages() {
let numberOfPages = Math.ceil(this.filteredArticles.length / this.perPage);
for (let index = 1; index <= numberOfPages; index++) {
this.pages.push(index);
}
},
paginate(filteredArticles) {
let page = this.page;
let perPage = this.perPage;
let from = (page * perPage) - perPage;
let to = (page * perPage);
return filteredArticles.slice(from, to);
},
watch: {
filteredArticles() {
this.setPages();
}
}
I know that I may have done this in a round about way, so any suggestions would be greatly appreciated, but overall I just need to be able to select any of the articles and it find the correct index and direct you to the correct article no matter what page you are on.
I tried to clean up and simplify your code. I removed the "round-about-ness" that you mentioned and renamed the variables to make more sense (at least to me).
Also, if you need to change the location anyway, so we're not in a single page app, why not use the anchor tag as intended with an href attribute, with the added bonus of accessibility?
You won't see any change when clickin an article in this demo, because I set the URLs simply to hashes ( #1, #2, etc.), but you'll see the resulting URL chaning with each article in the bottom left corner of your browser.
const app = {
data: function() {
return {
timer: null,
currentPage: 1,
perPage: 2,
pages: [],
articles: [{
title: 'Title 1',
date: 'date article 1',
shortDesc: 'description article 1',
url: '/#1',
category: 'category',
featureImg: 'Image for article'
},
{
title: 'Title 2',
date: 'date article 2',
shortDesc: 'description article 2',
url: '#2',
category: 'category',
featureImg: 'Image for article'
},
{
title: 'Title 3',
date: 'date article 3',
shortDesc: 'description article 3',
url: '#3',
category: 'category',
featureImg: 'Image for article'
},
{
title: 'Title 4',
date: 'date article 4',
shortDesc: 'description article 4',
url: '#4',
category: 'category',
featureImg: 'Image for article'
},
{
title: 'Title 5',
date: 'date here',
shortDesc: 'description here',
url: '#5',
category: 'category',
featureImg: 'Image for article'
}
]
}
},
computed: {
pagedArticles() {
let page = this.currentPage;
let perPage = this.perPage;
let from = (page * perPage) - perPage;
let to = (page * perPage);
return this.articles.slice(from, to);
}
}
};
Vue.createApp(app).mount('#app');
nav li {
display: inline;
}
.news-article-list li>a {
display: block;
text-decoration: none;
color: inherit;
}
<script src="https://unpkg.com/vue#3.0.11/dist/vue.global.prod.js"></script>
<div id="app">
<nav>
<ul>
<li v-for="p in Math.ceil( articles.length / perPage )"><button :disabled="currentPage === p" #click="currentPage = p">{{ p }}</buttpn></li>
</ul>
</nav>
<div class="news-article-list">
<ul>
<li v-for="(article, index) in pagedArticles" :key="index">
<a :href="article.url">
<img :src="article.featureImg" v-if="article.featureImg" alt="Article Feature Image" />
<h2 class="news-title">{{ article.title }}</h2>
<p class="news-date">{{ article.date }}</p>
<p class="short-desc">{{ article.shortDesc }}...</p>
<span class="read-more">Read More</span>
</a>
</li>
</ul>
</div>
</div>
You are mixing indexes of two arrays: allArticles and filteredArticles. Thy have different content and indexes. To get the correct index of an element you can use findIndex:
showArticle(selected) {
let index = this.filteredArticles.findIndex(el => el.id === this.allArticles[selected].id)
this.selectedArticle = index;
window.location = this.filteredArticles[index].url;
}
I try to add shopping cart,but I do not know how to do it. When count = 0,- is hidden.And when count > 0,- is show.When i try to click +, automatically increase 1, click - automatically reduced by 1. But can not be displayed.jsfiddle
Look at the Javascript file:
const goods = [{
id: "1",
goods_name: "水立方",
goods_price: "30.00",
goods_num: "15",
count:"0"
}, {
id: "2",
goods_name: "农夫山泉",
goods_price: "28.00",
goods_num: "10",
count:"0"
}]
var app = new Vue({
el: "#app",
data: {
list: goods,
},
methods: {
addCart(item,event) {
if (!this.item.count) {
Vue.set(this.item, 'count', 1);
} else {
this.item.count++;
}
},
lessCart(event) {
this.item.count--;
}
}
})
HTML file:
<div id="app">
<ul>
<li v-for="item in list">
<p>{{item.goods_name}}</p>
<p>{{item.goods_price}}</p>
<a v-show="item.count > 0" #click.stop.prevent="lessCart(item,$event)">-</a>
<input v-show="item.count > 0" v-model="item.count">
<a #click.stop.prevent="addCart(item,$event)">+</a>
</li>
</ul>
</div>
You are mutating the same state each time and not the state from the list.
You should simply do:
const goods = [{
id: "1",
goods_name: "水立方",
goods_price: "30.00",
goods_num: "15",
count:"0"
}, {
id: "2",
goods_name: "农夫山泉",
goods_price: "28.00",
goods_num: "10",
count:"0"
}]
var app = new Vue({
el: "#app",
data: {
list: goods,
},
methods: {
addCart(item) {
item.count++;
},
lessCart(item) {
item.count--;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in list">
<p>{{item.goods_name}}</p>
<p>{{item.goods_price}}</p>
<a v-show="item.count > 0" #click.stop.prevent="lessCart(item)">-</a>
<input v-show="item.count > 0" v-model="item.count">
<a #click.stop.prevent="addCart(item)">+</a>
</li>
</ul>
</div>
Note that you do not need the event argument in your method.
i listed category from json data.i have listed number of sub category under category but i want to list only 3 sub category under category.if i click view more option i want to list corresponding sub category depends on category in modal popup.
i have returned created div depends on parentid zero
$scope.cat = categories.filter(function(category) {
return category && category.parentid === 0
});
i have updated my code in plunker.
http://plnkr.co/edit/Vh1NzYf0qjUkIygLUEJk?p=preview
You can do it by simlpe filter:
<div ng-repeat="childItem in content | filter: item.id | limitTo: 3">
Demo 1 plunker
It also will get rid of using ng-if="childItem.parentid === item.id"
Example:
<div ng-repeat="item in cat">
{{item.name}}
<div ng-repeat="childItem in content | filter: item.id | limitTo: 3">
<div style="margin-left: 20px;" >
{{childItem.name}}
</div>
</div>
</div>
If you want to handle view more, you can write:
<div ng-repeat="childItem in content | filter: item.id | limitTo: limit">
and:
$scope.limit = 3;
$scope.viewMore = function(){
$scope.limit = 100;
}
Demo 2 plunker
[EDIT]
if you want to update view more per sub-category, you need bind limit to your data:
<body ng-controller="MainCtrl">
<div ng-repeat="item in cat">
{{item.name}}
<div ng-repeat="childItem in content | filter: item.id | limitTo: item.limit">
<div style="margin-left: 20px;" >
{{childItem.name}}
</div>
</div>
<a href="" ng-click="viewMore(item)"
ng-if="item.limit == 3">view more</a>
</div>
</body>
and:
$scope.viewMore = function(item){
item.limit = 100;
}
Demo 3 plunker
Update
If you want a show more functionality refer the below Plunkr.
Plunkr
This will do the job. I have added a custom filter that takes the parent.Id as an argument and check the child's parent Id (which was done before by the ng-if). Then I use angular's limit to: 3 filter to limit the results to only 3 items.
Plunkr
Code:
$scope.searchMe = function(statusId) {
return function(user) {
return user.parentid === statusId;
}
}
and the ng-repeat should look like
<div ng-repeat="item in cat">
{{item.name}}
<div ng-repeat="childItem in content | filter: searchMe(item.id) | limitTo: 3">
<div style="margin-left: 20px;">
{{childItem.name}}
</div>
</div>
<a ng-click="open_modalpopup()">view more</a>
</div>
References:
Limit To
passing arguements to angularJS filters
UPDATE -
As per your latest requirement -
if i click view more i want to list all corresponding sub category
depends on category
I update the plnkr to show all categories in a popup once user clicked on View More button.
Updated Plnkr - http://plnkr.co/edit/OUvzqWdfZuQnZpbXWSRW?p=preview
As per your requirement I believe you need to show/hide sub categories on the basis of button click available under specific category.
I re arranged your data and rather than saving it into multiple objects, I am using a singular object newcat to store and manage the UI.
Working Plnkr -
http://plnkr.co/edit/F6MlkMWOJ2b7isRAM1u6?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var data = [{
id: 1,
name: 'mobile',
parentid: 0
}, {
id: 2,
name: 'samsung',
parentid: 1
}, {
id: 3,
name: 'moto',
parentid: 1
}, {
id: 4,
name: 'redmi',
parentid: 1
}, {
id: 5,
name: 'honor',
parentid: 1
}, {
id: 6,
name: 'nokia',
parentid: 1
},
{
id: 7,
name: 'tv',
parentid: 0
}, {
id: 8,
name: 'tv1',
parentid: 7
}, {
id: 9,
name: 'tv2',
parentid: 7
}, {
id: 10,
name: 'tv3',
parentid: 7
}, {
id: 11,
name: 'tv4',
parentid: 7
}, {
id: 12,
name: 'tv5',
parentid: 7
}];
var categories = data;
$scope.title = 'Show Hide Subcategories';
$scope.cat = categories.filter(function(category) {
return category && category.parentid === 0
});
$scope.newcat = angular.extend($scope.cat, {});
angular.forEach($scope.cat, function(cat, key){
var tmpIndex = 0;
var tmpdata = categories.filter(function(category) {
if(cat.id === category.parentid) {
category.indexVal = tmpIndex;
category.isShow = tmpIndex < 3 ? true : false;
tmpIndex++;
return true;
}
})
$scope.newcat[key]['subCat'] = tmpdata;
$scope.newcat[key]['moreclicked'] = false;
})
$scope.showMore = function(index) {
if(!$scope.newcat[index]['moreclicked']) {
angular.forEach($scope.newcat[index].subCat, function(subcat, key) {
subcat.isShow = true;
})
$scope.newcat[index]['moreclicked'] = true;
}
else {
angular.forEach($scope.newcat[index].subCat, function(subcat, key) {
if(key > 2)
subcat.isShow = false;
})
$scope.newcat[index]['moreclicked'] = false;
}
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h3 ng-bind="title"></h3>
<div ng-repeat="cat in newcat">
<b>{{cat.name}}</b>
<div ng-repeat="subcat in cat.subCat">
<div style="margin-left: 20px;" ng-if="subcat.isShow">
{{subcat.name}}
</div>
</div>
<button ng-click="showMore($index)" ng-bind="!cat.moreclicked ? 'View More': 'View Less'"></button>
</div>
</body>
</html>
Now, I have tow buttons. The first button named "array1", the other button named 'array2'. I have an array called "newArray." I have an array named "array1". I have an array named "array2".I have an array called "unselectedArray."
When I click the array1 button, I want to show the item in array1, but the item is not in "newArray1". When I click the array2 button, I want to show the item in array2, but the item is not in "newArray1" This show array is "unselectedArray."
When I click the item in the "unselectedArray," the item is added in 'newArrray';
I use two hours to solve it, but I haven't written the right code.
This is my code:
<style>
.bigDiv {
width: 500px; height: 100%;
margin: 60px auto; background-color: red;
}
li {
float: left;
width: 50px; height: 50px;
}
.selected,.buttonArea,.unselected {
height: 100px;
}
</style>
<div class="bigDiv">
<div class="selected">
<ul>
<li ng-repeat="item in newArray">
{{item.text}}
</li>
</ul>
</div>
<div class="buttonArea">
<button ng-click="showArrayFun('array1')">array1</button>
<button ng-click="showArrayFun('array2')">array2</button>
</div>
<div class="unselected">
<ul>
<li ng-click="addToNewArrayFun($index)" ng-repeat="item in unselectedArray">
{{item.text}}
</li>
</ul>
</div>
</div>
angular.module('myApp', []).controller('con', function ($scope) {
$scope.array1 = [
{
id: 11,
text: 'one'
},
{
id: 12,
text: 'two'
},
];
$scope.array2 = [
{
id: 21,
text: 'winter'
},
{
id: 22,
text: 'spring'
},
];
$scope.newArray = [
{
id: 12,
text: 'two'
}
];
$scope.unselectedArray = [];
$scope.addToNewArrayFun = function (index) {
$scope.newArray.push($scope.unselectedArray[index]);
};
$scope.showArrayFun = function (arrayName) {
if (arrayName == 'array1') {
$scope.unselectedArray = $scope.array1.filter(function (item) {
console.log(($scope.newArray.indexOf(item) == -1));
return ( ($scope.newArray.indexOf(item) == -1) == true );
});
} else if (arrayName == 'array2') {
$scope.unselectedArray = $scope.array2.filter(function (item) {
console.log(($scope.newArray.indexOf(item) == -1));
return ( ($scope.newArray.indexOf(item) == -1) == true );
});
}
}
}
);
Why my code not work? Who can correct my code?
Please write the code which is using $filter.
Who can create AngularJS custom filters to realize it.
// Code goes here
angular.module('myApp', []).controller('con', function ($scope) {
$scope.array1 = [
{
id: 11,
text: 'one'
},
{
id: 12,
text: 'two'
},
];
$scope.array2 = [
{
id: 21,
text: 'winter'
},
{
id: 22,
text: 'spring'
},
];
$scope.newArray = [
{
id: 12,
text: 'two'
}
];
$scope.unselectedArray = [];
$scope.addToNewArrayFun = function (index) {
$scope.newArray.push($scope.unselectedArray[index]);
$scope.unselectedArray.splice(index, 1);
};
$scope.showArrayFun = function (arrayName) {
if (arrayName == 'array1') {
$scope.unselectedArray = $scope.array1.filter(function (item) {
return ( ($scope.newArray.indexOf(item) == -1));
});
} else if (arrayName == 'array2') {
$scope.unselectedArray = $scope.array2.filter(function (item) {
return ( ($scope.newArray.indexOf(item) == -1));
});
}
};
})
/* Styles go here */
.bigDiv {
width: 500px; height: 100%;
margin: 60px auto;
background-color: red;
}
li {
float: left;
width: 50px; height: 50px;
}
.selected,.buttonArea,.unselected {
height: 100px;
}
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body ng-controller="con">
<div class="bigDiv">
<div class="selected">
<ul>
<li ng-repeat="item in newArray">
{{item.text}}
</li>
</ul>
</div>
<div class="buttonArea">
<button ng-click="showArrayFun('array1')">array1</button>
<button ng-click="showArrayFun('array2')">array2</button>
</div>
<div class="unselected">
<ul>
<li ng-click="addToNewArrayFun($index)" ng-repeat="item in unselectedArray">
{{item.text}}
</li>
</ul>
</div>
</div>
</body>
</html>
<div class="bigDiv">
<div class="selected">
<ul>
<li ng-click=" deleteItemFun($index)" ng-repeat="item in newArray track by $index ">
{{item.text}}
</li>
</ul>
</div>
<div class="buttonArea">
<button ng-click="showArrayFun('array1')">array1</button>
<button ng-click="showArrayFun('array2')">array2</button>
</div>
<div class="unselected">
<ul>
<li ng-click="addToNewArrayFun($index)" ng-repeat="item in unselectedArray | fiArray : newArray ">
{{item.text}}
</li>
</ul>
</div>
</div>
angular.module('myApp', []).filter('fiArray', function () {
return function (array, aimArray) {
var tempArray = array;
if (tempArray.length == 0)
return [];
for (var i = 0; i < aimArray.length; i++) {
for (var j = 0; j < tempArray.length; j++) {
if (tempArray[j].id === aimArray[i].id) {
tempArray.splice(j, 1);
j--;
break;
}
}
}
return tempArray;
}
})
.controller('con', ['$scope', 'fiArrayFilter', function ($scope, fiArrayFilter) {
$scope.newArray = [
{
id: 12,
text: 'two'
}
];
$scope.array1 = [
{
id: 11,
text: 'one'
},
{
id: 12,
text: 'two'
},
];
$scope.array2 = [
{
id: 21,
text: 'winter'
},
{
id: 22,
text: 'spring'
},
];
$scope.unselectedArray = [];
$scope.addToNewArrayFun = function (index) {
$scope.newArray.push($scope.unselectedArray[index]);
};
$scope.deleteItemFun = function (index) {
$scope.newArray.splice(index, 1)
}
$scope.showArrayFun = function (arrayName) {
var copyArr = [];
if (arrayName == 'array1') {
copyArr = $scope.array1.concat();
}
else if (arrayName == 'array2') {
copyArr = $scope.array2.concat();
}
$scope.unselectedArray = copyArr;
}
}])
;