Forked from neisdev/alpinejs-3-bootstrap-repeater.markdown
Created
January 12, 2024 02:51
-
-
Save bran921007/ab8ff9d28be4ea9aecbc084af904f56d to your computer and use it in GitHub Desktop.
Alpinejs 3 - Bootstrap repeater
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="container" x-data x-cloak> | |
<h1 class="h2 d-print-none mt-4 mb-2">Alpinejs 3 - Bootstrap 5 repeater</h1> | |
<p class="d-print-none mb-4">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sequi corrupti accusantium numquam similique maxime earum quos alias voluptatibus eius porro. Voluptates culpa nam illum reprehenderit maiores modi eaque est in.</p> | |
<h2 class="d-none d-print-block text-center mb-4">My awesome table</h2> | |
<div x-data="repeater"> | |
<template x-for="(row, index) in rows" :key="index"> | |
<div class="position-relative d-print-none"> | |
<div class="row g-1 mb-3"> | |
<div class="col-12 col-md-5 col-lg-6 col-xl-7"> | |
<div class="form-floating"> | |
<input id="lavoroInput" x-model="row.description" type="text" class="form-control" placeholder="Description" /> | |
<label for="lavoroInput">DESCRIPTION</label> | |
</div> | |
</div> | |
<div class="col-5 col-md-3 col-lg-2 col-xl-2"> | |
<div class="form-floating"> | |
<input x-model="row.unit_price" type="number" class="form-control" placeholder="Unit price" /> | |
<label for="totaleInput">UNIT PRICE</label> | |
</div> | |
</div> | |
<div class="col-3 col-md-2 col-xl-1"> | |
<div class="form-floating"> | |
<input x-model="row.qty" type="number" min="1" class="form-control" /> | |
<label for="totaleInput">QTY</label> | |
</div> | |
</div> | |
<div class="col-4 col-md-2 col-xl-2"> | |
<div class="form-floating"> | |
<input readonly id="amountInput" x-model="row.amount" :value="row.amount = (row.qty * row.unit_price) > 0 ? (row.qty * row.unit_price).toFixed(2) : null" type="text" class="form-control" placeholder="Amount" /> | |
<label for="amountInput">AMOUNT <span x-text="currency_symbol"></span></label> | |
</div> | |
</div> | |
</div> | |
<div class="position-absolute top-0 start-100 translate-middle me-1 mt-1" x-show="rows.length > 1" x-data="{hover: false}"> | |
<div class="p-1 text-secondary border rounded-circle" :class="hover ? 'border-danger bg-danger text-white' : 'bg-white'" style="cursor:pointer" @click="del(index)" @mouseenter="hover = true" @mouseleave="hover = false"> | |
<div style="line-height:6px" class="text-center"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16"> | |
<path d="M1.293 1.293a1 1 0 0 1 1.414 0L8 6.586l5.293-5.293a1 1 0 1 1 1.414 1.414L9.414 8l5.293 5.293a1 1 0 0 1-1.414 1.414L8 9.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L6.586 8 1.293 2.707a1 1 0 0 1 0-1.414z" /> | |
</svg> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
<div class="d-print-none"> | |
<div class="d-flex justify-content-between d-print-none"> | |
<button class="btn btn-sm btn-outline-success lh-1" type="button" @click="add()"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square-fill" viewBox="0 0 16 16"> | |
<path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z" /> | |
</svg> | |
ADD ITEM | |
</button> | |
<button type="button" class="btn btn-sm btn-outline-danger lh-1" @click="reset()"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16"> | |
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z" /> | |
</svg> | |
RESET | |
</button> | |
</div> | |
<hr> | |
<div class="text-end"> | |
<div class="row g-1 lh-lg"> | |
<div class="col-6 col-sm-8 col-md-10">SUBTOTAL:</div> | |
<div class="col-6 col-sm-4 col-md-2 text-start"> | |
<span x-text="subtotal()"></span><span x-text="currency_symbol"></span> | |
</div> | |
</div> | |
<div class="row g-1 lh-lg"> | |
<div class="col-6 col-sm-8 col-md-10">TAX:</div> | |
<div class="col-6 col-sm-4 col-md-2"> | |
<div class="input-group input-group-sm"> | |
<input type="text" x-model="tax" class="form-control"> | |
<span class="input-group-text">%</span> | |
</div> | |
</div> | |
</div> | |
<div class="row g-1 lh-lg"> | |
<div class="col-6 col-sm-8 col-md-10">TOTAL:</div> | |
<div class="col-6 col-sm-4 col-md-2 text-start"> | |
<strong x-text="total()"></strong><span x-text="currency_symbol"></span> | |
<p class="small">Tax amount: <span x-text="taxAmount()"></span><span x-text="currency_symbol"></span></p> | |
</div> | |
</div> | |
</div> | |
<div class="text-center"> | |
<button class="btn btn-outline-info btn-sm my-2" @click="print()"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-printer-fill" viewBox="0 0 16 16"> | |
<path d="M5 1a2 2 0 0 0-2 2v1h10V3a2 2 0 0 0-2-2H5zm6 8H5a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1z"></path> | |
<path d="M0 7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-1v-2a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v2H2a2 2 0 0 1-2-2V7zm2.5 1a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1z"></path> | |
</svg> PRINT TABLE</button> | |
</div> | |
<hr class="mb-4"> | |
</div> | |
<div class="d-print-block d-none"> | |
<table class="table table-striped"> | |
<thead> | |
<tr> | |
<th scope="col">#</th> | |
<th scope="col">Description</th> | |
<th scope="col">Unit price</th> | |
<th scope="col">Qty</th> | |
<th scope="col">Amount</th> | |
</tr> | |
</thead> | |
<tbody> | |
<template x-for="(row, index) in rows" :key="index"> | |
<tr> | |
<th scope="row" x-text="index+1">1</th> | |
<td x-text="row.description"></td> | |
<td> | |
<span x-text="row.unit_price"></span> | |
<span x-text="currency_symbol"></span> | |
</td> | |
<td x-text="row.qty"></td> | |
<td> | |
<span x-text="row.amount"></span> | |
<span x-text="currency_symbol"></span> | |
</td> | |
</tr> | |
</template> | |
</tbody> | |
</table> | |
<table class="table table-borderless table-sm"> | |
<tbody> | |
<tr class=""> | |
<td style="width:70%" class="text-end">SUBTOTAL:</td> | |
<td colspan="2"><span x-text="subtotal()"></span><span x-text="currency_symbol"></span></td> | |
</tr> | |
<tr class=""> | |
<td class="text-end">TAX:</td> | |
<td > | |
<span x-text="tax"></span>% | |
<p class="small mb-0">Tax amount: <span x-text="taxAmount()"></span><span x-text="currency_symbol"></span></p> | |
</td> | |
</tr> | |
<tr class=""> | |
<td class="text-end">TOTAL:</td> | |
<td> | |
<span x-text="total()"></span><span x-text="currency_symbol"></span> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
<div class="d-print-none"> | |
<button class="btn btn-outline-warning btn-sm my-2" @click="rows = [...window.demo_data]">LOAD DEMO DATA</button> | |
<div x-data="{open:false}"> | |
<div class="card mt-6 small text-secondary" style="border: 1px dotted #aaa"> | |
<div class="card-body p-1"> | |
<div class="text-center cursor-pointer lh-1" style="cursor: pointer;" @click="open = ! open"> | |
SHOW ROWS JSON | |
<template x-if="open"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16"> | |
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z" /> | |
</svg> | |
</template> | |
<template x-if="!open"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16"> | |
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z" /> | |
</svg> | |
</template> | |
</div> | |
<div x-show="open"> | |
<pre x-text="JSON.stringify(rows, null, 2)"></pre> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script defer src="https://unpkg.com/@alpinejs/[email protected]/dist/cdn.min.js"></script> | |
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var demo_data = [ | |
{ | |
"description": "Logo design", | |
"qty": 1, | |
"unit_price": "1200", | |
"amount": 0, | |
}, | |
{ | |
"description": "Landing page", | |
"qty": 1, | |
"unit_price": "400", | |
"amount": 0, | |
}, | |
{ | |
"description": "Social media manager", | |
"qty": "12", | |
"unit_price": "180", | |
"amount": 0, | |
} | |
]; | |
document.addEventListener('alpine:init', () => { | |
Alpine.data('repeater', () => ({ | |
// Data | |
rowBase: { | |
description: null, | |
qty: 1, | |
unit_price: null, | |
amount: 0, | |
}, | |
currency_symbol: '€', | |
tax: 22, | |
rows: [], | |
// Calculations | |
subtotal() { | |
const subt = this.rows.reduce((prev, cur) => { | |
return Number(prev) + Number(cur.amount); | |
}, 0); | |
return subt.toFixed(2); | |
}, | |
taxAmount() { | |
const subt = this.subtotal(); | |
return ((subt * this.tax) / 100).toFixed(2); | |
}, | |
total() { | |
const subt = Number(this.subtotal()); | |
return (subt + ( (subt * this.tax) / 100)).toFixed(2); | |
}, | |
// Actions | |
add() { | |
// const row = JSON.stringify(this.rowBase); | |
// this.rows.push(JSON.parse(row)); | |
this.rows.push({...this.rowBase}); | |
}, | |
del(index) { | |
this.rows.splice(index, 1); | |
}, | |
reset() { | |
this.rows = []; | |
this.add(); | |
}, | |
print() { | |
window.print(); | |
}, | |
init() { | |
this.add(); | |
} | |
})) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.0/js/bootstrap.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[x-cloak] { | |
display: none !important; | |
} | |
body { | |
font-family: "IBM Plex Sans", sans-serif; | |
} | |
@media print { | |
@page { | |
margin-top: 0; | |
margin-bottom: 0; | |
} | |
body { | |
margin-top: 50px; | |
margin-bottom: 50px; | |
font-size-adjust: 0.46; | |
} | |
.container { | |
max-width: 100% !important; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment