I want to pass the values from my JQuery to the AlpineJS (Component) so that I can execute the modal. I want to implement a multiple selection delete function (bulk delete). Here's my code.
This is my recycle.php file where jquery, alpine and some php are included.
<div x-data="{
modalDeleteBulk: false,
password:'',
userId: 0,
seletedUserIds: [],
openModalDeleteBulk(){
this.password = '';
this.modalDeleteBulk = true;
},
handleModalDeleteBulk(id){
this.seletedUserIds = id;
this.openModalDeleteBulk();
},
handleDeleteBulk(){
if(this.password === ''){
this.errors.push('Password input is empty!');
return;
}
postData('api/<?php if($_GET['view'] == 'users'){echo("users.php");} elseif($_GET['view'] == 'survey'){echo("surveys.php");} elseif($_GET['accounts']){echo("users.php");}?>?action=deleteThesePerm', {
password:this.password,
recycle_id:this.seletedUserIds,
}).then((data) => {
if(data.status === 201){
alert('Deleted successfully');
} else {
alert('There is an error. It is either you put an invalid password or internal error.');
}
});
this.modalDeleteBulk = false;
}
}">
the modal inside it
<section x-show="modalDeleteBulk" x-cloak>
<div class="h-full w-full bg-gray-600 top-0 left-0 right-0 bg-opacity-75 absolute flex flex-row justify-center items-center z-50">
<div class="bg-white rounded shadow">
<div class="border-b p-3 flex justify-between items-center bg-green-600 text-white font-semibold">
<h4>Confirmation</h4>
<svg xmlns="http://www.w3.org/2000/svg" #click="modalDelete = false" class="h-6 w-6 cursor-pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
<div class="p-3 max-full">
<form action="">
<div class="text-xs text-red-400" x-show="errors.length > 0">
<template x-for="error in errors">
<li x-text="error"></li>
</template>
</div>
<div class="flex flex-col gap-y-2 mb-3" x-show="userId === 0">
<label for="">Enter admin password to confirm.</label>
<input type="password" x-model="password" class="bg-gray-50 outline-none border px-3 py-2 rounded w-96 hover:border-2 hover:border-blue-300 hover:bg-white">
</div>
<div class="flex justify-end">
<button type="button" #click="handleDeleteBulk()" class="bg-red-600 text-white py-2 px-5 rounded flex items-center gap-x-1 hover:bg-red-400">
<span>Delete</span>
</button>
</div>
</form>
</div>
</div>
</div>
</section>
This is my table where I can select multiple checkboxes.
<table id="table_id" class="display nowrap" style="width:100%"><button type="button" id="delete-selected" class="bg-red-500 text-sm text-white px-2 py-1 rounded hover:bg-red-400 flex items-center gap-x-1" disabled>Delete Selected</button>
<br>
<thead>
<tr>
<th>Select All<br><input type="checkbox" id="select-all"></th>
<th>Last Name</th>
<th>First Name</th>
<th>Username</th>
<th>Role</th>
</tr>
</thead>
<tbody id="table-body">
<?php foreach ($users as $user) : ?>
<tr>
<td><input type="checkbox" class="select-user" data-user-id="<?= $user['id'] ?>"></td>
<td><?= $user['lastname'] ?></td>
<td><?= $user['firstname'] ?></td>
<td><?= $user['username'] ?></td>
<td><?= getRole($user['role_id']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
my JQuery, i want to call the handleModalDeleteBulk() here (e.g. handleModalDeleteBuld(selectedUserIds);
$('#select-all').click(function() {
$('.select-user').prop('checked', this.checked);
$('#delete-selected').prop('disabled', !this.checked);
});
// Handle the selected users checkbox
$('.select-user').click(function() {
var allChecked = $('.select-user:checked').length === $('.select-user').length;
$('#select-all').prop('checked', allChecked);
$('#delete-selected').prop('disabled', !allChecked);
});
// Handle the delete selected button
$('#delete-selected').click(function() {
var selectedUserIds = [];
$('.select-user:checked').each(function() {
selectedUserIds.push($(this).data('user-id'));
});
if (selectedUserIds.length > 0) {
// the code will be here
}
});
It's been hours thinking about how can I achieve this. Thank you in advance for the response.
Remove jQuery completely and use Alpine.js data model for each part of your code, it will be much cleaner and easier to understand. Here I provide a minimal Alpine.js example that fulfill the same purpose as your jQuery code.
First we have a new userIds array that holds all user IDs. We can have multiple x-init directives, so we put one to each checkbox via x-init="userIds.push(1)" (or with PHP: x-init="userIds.push(<?= $user['id'] ?>)") to fill the array. We will use this array to check some disabled conditions on the buttons.
Next we have an x-model="selectedUserIds" directive on each checkbox, so when an user clicks on a checkbox its value will be automatically added/removed to selectedUserIds array.
The rest is just some utility buttons with :disabled logic. The bulk delete modal will now work since we have already filled the seletedUserIds array.
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs#3.x.x/dist/cdn.min.js"></script>
<div x-data="{
modalDeleteBulk: false,
userIds: [],
selectedUserIds: [],
}">
<div x-text="`All userIDs: ${userIds}`"></div>
<div x-text="`Selected userIDs: ${selectedUserIds}`"></div>
<div x-text="`Is modal opened? ${modalDeleteBulk}`"></div>
<div>
<button #click="selectedUserIds = userIds" :disabled="selectedUserIds.length == userIds.length">Select all</button>
<button #click="selectedUserIds = []" :disabled="selectedUserIds.length == 0">Deselect all</button>
<button #click="modalDeleteBulk = true" :disabled="selectedUserIds.length == 0">Delete selected</button>
</div>
<table>
<tr>
<td><input type="checkbox" x-model="selectedUserIds" value="1" x-init="userIds.push(1)"> User #1</td>
</tr>
<tr>
<td><input type="checkbox" x-model="selectedUserIds" value="2" x-init="userIds.push(2)"> User #2</td>
</tr>
<tr>
<td><input type="checkbox" x-model="selectedUserIds" value="3" x-init="userIds.push(3)"> User #3</td>
</tr>
</table>
</div>
Related
I write down a function which is bulk deletion on table. There is a table with checkbox on every rows, if some one select checkboxs then click on delete button its shows a confirmation modal, if it is close them modal then no action occurs.
In my case when I checked the boxes modal shows correct selected data, and if I then unchecked their is no problem, problem occurs when third time checked it populate previous unchecked data in modal. means checked -> unchecked -> checked.
let newTableData = "";
$('.btn-delete-employees-table-danger').hide();
let modalValue = null;
let selectedID = null;
let selectedRow = ""
let counter = 0;
console.log($('.btndelete'));
$(document).on('click', '.btndelete', function(e) {
$('.btn-delete-employees-table-danger').show();
if ($(this).prop("checked") == true || this.checked) {
counter = counter + 1;
var id = $(this).closest('tr').data('id');
selectedRow = $(`.roww[data-id=${id}]`);
selectedID = $(this).closest('tr').attr('id');
$(this).closest('tr').addClass('deleteselectedrow')
if($(this).closest('tr').addClass('deleteselectedrow')) {
$('.counter-of-selected-emp-modal').html(`${counter} employees will be deleted`)
newTableData += `
<div class="card mt-3" id="emp-${selectedID}">
<div class="d-flex justify-content-between modal-row">
<div>
<h4>${selectedRow[0].cells[1].innerText}</h4>
<p class="light-small-grey-text">ID</p>
</div>
<div>
<h4>${selectedRow[0].cells[2].innerText}</h4>
<p class="light-small-grey-text">Emp Name</p>
</div>
<div>
<h4>${selectedRow[0].cells[3].innerText}</h4>
<p class="light-small-grey-text">Emp DOB</p>
</div>
<div>
<h4>${selectedRow[0].cells[4].innerText}</h4>
<p class="light-small-grey-text">Emp CNIC</p>
</div>
</div>
</div>
`
console.log(newTableData);
}
$('.data-in-modal').html(newTableData);
} else {
counter = counter - 1;
$('.counter-of-selected-emp-modal').html(`${counter} employees will be deleted`)
selectedID = $(this).closest('tr').attr('id');
console.log($(selectedRow[0].cells[0].childNodes[1].checked))
console.log($("#emp-"+selectedID));
$(this).prop('checked', false);
$("#emp-"+selectedID).remove();
$("#emp-"+selectedID).empty();
$(this).prop("checked") == false;
$("#emp-"+selectedID).addClass('d-none')
console.log($('.data-in-modal'));
console.log(newTableData);
}
if(counter == 0 ) {
$('.btn-delete-employees-table-danger').hide();
$('.data-in-modal').html("");
newTableData = '';
}
});
function getandsetdate() {
var date = new Date().toISOString('yyyy-mm-dd').split('T')[0];
var element = document.getElementById('date')
element.value = date
return date
}
// show confirmation modal
$('.shown-modal').on('click', function (e) {
var policy_date_elem = $('input[name="emp_policy_end"]')
policy_date_elem.val(getandsetdate())
policy_date_elem.css('border', '1px #ced4da solid')
$('#showsDependentModal').modal('show');
})
$('#btnDelteYes').click(function () {
$('.deleteselectedrow').remove();
console.log($('.deleteselectedrow'))
console.log($('.deleteselectedrow').prevObject[0]);
$('.btn-delete-employees-table-danger').hide();
newTableData = ""
$('#showsDependentModal').modal('hide');
});
$('.no-btn').click(function () {
$('tr').removeClass('deleteselectedrow')
$('#showsDependentModal').modal('hide');
})
<table class="table table-bordered sortable empy-table" id="table">
<thead class="">
<tr>
<th>
Select
</th>
<!-- <th>check</th> -->
<th>Emp ID</th>
<th>Employee Name</th>
<th>DOB</th>
<th>CNIC</th>
<th class="noExport">Details</th>
</tr>
</thead>
<tbody id="search-table" class="employees_body">
<!-- {% for employee in employees %}
<tr id="{{ employee.id }}" data-id="{{ forloop.counter }}" class="roww">
<td>
<input class="btndelete" type="checkbox" name="employee_id" value="{{ employee.id }}" />
</td>
<td>
{{employee.id}}
</td>
<td>
{{employee.first_name}} {{employee.last_name}}
</td>
<td>
{{employee.date_of_birth}}
</td>
<td>
{{employee.cnic}}
</td>
<td class="noExport">
<a class="text-dark" href="{% url 'smartbenefits:employee_profile' employee.id %}">
<button class="button-detail"><span class="fa fa-info-circle"></span></button>
</a>
</td>
</tr>
{% endfor %} -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal hide fade" id="showsDependentModal" tabindex="-1" aria-labelledby="showssDependentModal" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content modal-secondary">
<div class="px-4 pt-5 w-100">
<div class="d-flex justify-content-between w-100">
<div class="">
<h4>Please confirm if you want to delete the below employees?</h4>
<p class="counter-of-selected-emp-modal"></p>
</div>
<i class="fa fa-window-close dependent-close-icons-modal no-btn" id="modal-dismiss" data-bs-dismiss="modal" aria-label="Close"></i>
</div>
</div>
<div class="modal-body">
<div class="data-in-modal ">
</div>
<div class="policy-end w-25 mt-3">
<!-- <input type="text" name="emp_policy_end" readonly vaule="" /> -->
<label class="date-detail" for="emp_policy_end">Policy End Date. <span
class="fa fa-info-circle"></span></label>
<span class="hover-message">Policy End date will be same as the current date. For further queries,
contact our ops team</span>
<input id="date" type="date" name="emp_policy_end" readonly />
</div>
</div>
<div class="modal-footer">
<button class="button-secondary active" id="btnDelteYes">Confirm</button>
</div>
</div>
</div>
</div>
When a click event occurs on a table, I want to pass the values of the relevant row into the modal. I wrote a code like this, but the values of the top row are always passed into the modal. What I want to do is to show the values in the row I clicked in the modal. How can I provide this?
my table codes here:
<table class="table align-middle" id="customerTable">
<thead class="table-light">
<tr>
<th class="sort" data-sort="name">Name Surname</th>
<th class="sort" data-sort="company_name">Phone Number</th>
<th class="sort" data-sort="leads_score">Note</th>
<th class="sort" data-sort="phone">Status</th>
<th class="sort" data-sort="location">Personal Name</th>
<th class="sort" data-sort="tags">Data Name</th>
<th class="sort" data-sort="action">Edit</th>
</tr>
</thead>
<tbody class="list form-check-all">
{% for x in model %}
<tr>
<td class="table-namesurname">{{x.name}}</td>
<td class="table-phonenumber">{{x.phonenumber}}</td>
<td class="table-note">{{x.note}}</td>
<td class="table-status">{{x.status}}</td>
<td class="table-callname">{{x.callname}}</td>
<td class="table-dataname">{{x.dataname}}</td>
<td>
<ul class="list-inline hstack gap-2 mb-0">
<li class="list-inline-item" data-bs-toggle="tooltip" data-bs-trigger="hover" data-bs-placement="top" title="Edit">
<a class="edit-item-btn" id="call-button" href="#showModal" data-bs-toggle="modal" data-id="{{x.id}}"><i class="ri-phone-line fs-16"></i></a> <!-- Here is the edit button -->
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
my modal here
<div class="modal fade" id="showModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-light p-3">
<h5 class="modal-title" id="exampleModalLabel"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" id="close-modal"></button>
</div>
<form action="">
<div class="modal-body">
<input type="hidden" id="id-field" />
<div class="row g-3">
<div class="col-lg-12">
<div>
<label for="company_name-field" class="form-label">Name Surname</label>
<input type="text" id="call-name-surname" class="form-control" placeholder="Enter company name" value="" required />
</div>
</div>
<div class="col-lg-12">
<div>
<label for="company_name-field" class="form-label">Phone Number</label>
<input type="email" id="call-phone-number" class="form-control" placeholder="Enter company name" value="" required />
</div>
</div>
<!--end col-->
<div class="col-lg-12">
<div>
<label for="leads_score-field" class="form-label">Note</label>
<input type="text" id="call-note-field" class="form-control" placeholder="Enter lead score" value="" required />
</div>
</div>
<!--end col-->
<div class="col-lg-12">
<div>
<label for="phone-field" class="form-label">Status</label>
<input type="text" id="call-status-field" class="form-control" placeholder="Enter phone no" value="" required />
</div>
</div>
<div class="col-lg-12">
<div>
<label for="phone-field" class="form-label">Personal Name</label>
<input type="text" id="call-persnoel-name" class="form-control" placeholder="Enter phone no" value="" required />
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="hstack gap-2 justify-content-end">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Kapat</button>
<button type="submit" class="btn btn-success" id="add-btn">Kaydet</button>
</div>
</div>
</form>
</div>
</div>
</div>
and the my script codes
<script type="text/javascript">
$(document).ready(function () {
$("#call-button").click(function() {
var nameSurname = $(this).closest('tr').find('.table-namesurname').text();
var phoneNumber = $(this).closest('tr').find('.table-phonenumber').text();
var note = $(this).closest('tr').find('.table-note').text();
var status = $(this).closest('tr').find('.table-status').text();
var callName = $(this).closest('tr').find('.table-callname').text();
var dataName = $(this).closest('tr').find('.table-dataname').text();
$("#call-name-surname").val(nameSurname)
$("#call-phone-number").val(phoneNumber)
$("#call-note-field").val(note)
$("#call-status-field").val(status)
$("call-persnoel-name").val(callName)
});
});
</script>
console output
Gökan 905387532589 <empty string> Aranmadı ece datatest
The problem here is that the values of the clicked element in the table are not coming. Whichever I click, the values of the element at the top of the table are displayed. How can I solve this problem?
HTML id attribute should be unique, adding multiple elements with the same id, when you select, you will only get the first element that has this id, you need to select the rows by class, you have edit-item-btn class for the button.
<script type="text/javascript">
$(document).ready(function () {
$(".edit-item-btn").click(function() {
var nameSurname = $(this).closest('tr').find('.table-namesurname').text();
var phoneNumber = $(this).closest('tr').find('.table-phonenumber').text();
var note = $(this).closest('tr').find('.table-note').text();
var status = $(this).closest('tr').find('.table-status').text();
var callName = $(this).closest('tr').find('.table-callname').text();
var dataName = $(this).closest('tr').find('.table-dataname').text();
$("#call-name-surname").val(nameSurname)
$("#call-phone-number").val(phoneNumber)
$("#call-note-field").val(note)
$("#call-status-field").val(status)
$("call-persnoel-name").val(callName)
});
});
There is this modal in which I have a group of checkboxes being generated by the directive x-for from AlpineJS (v2.8.2), and the .sapId checkbox is the one that needs to be always selected no matter what. I partially got what I wanted here using jQuery: $('.sapId').prop('checked', 'checked').attr('disabled', 'disabled');.
This made the checkbox checked and unclickable, and that is exactly what I want. Problem: Whenever I click another checkbox from the .selectColumns list, the .sapId loses the selected status and I can't select it anymore. Till now I've done some searches and tried to do this using jQuery, but would be nice if there was a way of doing via Alpine or Livewire itself.
Here is the modal:
<div x-data="{
data:columns,
selectedColumns: [],
}"
wire:ignore class="modal fade" id="selectColumnsModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Selecionar Colunas</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<i aria-hidden="true" class="ki ki-close"></i>
</button>
</div>
<p class="mx-10 mt-4">Selecione até 9 colunas para exibir...</p>
<div class="text-center mx-10">
<div class="input-icon">
<input type="text" class="form-control" placeholder="Nome da coluna..." id="searchColumns">
<span>
<i class="flaticon2-search-1 text-muted"></i>
</span>
</div>
</div>
<div class="modal-body">
<div class="mt-6 text-center">
<table id="selectColumnsTable" class="table table-hover gy-5">
<thead>
<th class="text-left">
Coluna
</th>
<th class="text-left">
<i class="la la-eye"></i>
</th>
<thead>
<tbody>
<tr>
<td class="text-left ml-4">
<span x-html="columns[1].title"></span>
</td>
<td class="text-left">
<input x-model="selectedColumns" class="sapId" id="sapId" type="checkbox" :value=columns[1].field>
</td>
</tr>
<template x-for="(column, index) in data" :key="index">
<tr x-show="column.field != 'id' && column.field != 'sap_id' &&column.title != '' && column.title != 'CÓDIGO'">
<td class="text-left ml-4">
<span x-html="column.title"></span>
</td>
<td class="text-left">
<input x-model="selectedColumns" id="selectColumns" class="selectColumns" type="checkbox" :value=column.field>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<div class="modal-footer d-flex justify-content-around">
<button #click="displaySelected(selectedColumns)" type="button" class="btn btn-primary col-5" data-target="click">Exibir selecionadas</button>
<button type="button" class="btn btn-danger col-5" data-dismiss="modal">Cancelar</button>
</div>
</div>
</div>
</div>
And just in case, this is the jQuery I'm using to control the limit of boxes that can be selected:
$(".selectColumns").change(function () {
var displayLimit = 8;
var selected = $('.selectColumns:checked').length;
if (selected > displayLimit) {
$('.selectColumns').not(':checked').attr('disabled', 'disabled');
} else {
$('.selectColumns').not(':checked').removeAttr('disabled');
}
});
All suggestions are welcome, thanks in advance!
<td class="text-left">
<input x-model="selectedColumns" class="sapId" id="sapId" type="checkbox" disabled="disabled" :value=columns[1].field checked>
</td>
<label for="checkbox">checkbox</label>
you can simply include "checked" and "disabled" in the input tag.
Finally I got solution for your problem, you can do something like this to limit the number of checkbox checked using apline:
<input x-model="selectedColumns" type="checkbox" :disabled="selectedColumns.lenght > 8 && !$el.checked">
SelectedColumns.length returns the length off the array and $el is a magic property that can be used to retrieve the current DOM node.
And for the .sapId you can do something like this:
<input x-model="selectedColumns" type="checkbox" checked disabled>
But you have to hardcode the value of .sapId in order to keep it checked that how x-model works. x-model allows you to bind the value of an input element to Alpine data.
In my input form the user needs to be able to input multiple lines of data. I achieve this by making an ajax call to submit the information and then it will clone that row and append it to my table body so the user can enter more data. They can do this as many times as they want. However, I want to be able to disable the previous whenever a new row is created.
This is what I currently have to try to solve this problem. It works for the first two rows, as in when I click add on the first row it creates a new one and the previous items are disabled. However, when I click on add again to create another row, row three, that row is automatically disabled. I'm assuming because it's cloning the first row. If anyone has any ideas on how to fix this is greatly appreciated! Thanks!
$('#tableData').on('click', 'button.addRow', (e) => {
const cloneRow = $('#tableData tbody tr').first();
e.preventDefault();
let data = {
project_id: getPid,
imp_or_ann: $(".imp_or_ann").last().val(),
category: $(".category").last().val(),
cost: $(".cost").last().val(),
hours: $(".hours").last().val()
}
$.ajax({
url: '/costs_hours',
type: 'POST',
data: data
}).then(
cloneRow.clone().appendTo('#tableData tbody').find(".cost, .hours").val(''),
$(".imp_or_ann:not(:last)").attr("disabled", true),
$(".category:not(:last)").attr("disabled", true),
$(".cost:not(:last)").attr("disabled", true),
$(".hours:not(:last)").attr("disabled", true),
)
});
This is the HTML
<div class="row">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Home</li>
<li class="breadcrumb-item active" aria-current="page">Costs and Hours</li>
</ol>
</nav>
<form action='/costs_hours' id="formData" method="POST">
<div class="card border-secondary w-100 text-light" style="background-color: #333f48">
<h5 style="background-color: #bf5700;" class="card-header">Costs & Hours</h5>
<div class="card-body w-100 text-end">
<div id="errors" class="text-start"></div>
<table id="tableData" class="table text-light text-center mt-3">
<thead>
<tr>
<th scope="col">Implementation or Annual</th>
<th scope="col">Category</th>
<th scope="col">Costs</th>
<th scope="col">Hours</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="input-group mb-3">
<div class="input-group mb-3">
<select name="imp_or_ann" class="form-select imp_or_ann"
id="inputGroupSelect01">
<option disabled selected>Choose...</option>
<option>Implementation</option>
<option>Annual</option>
</select>
</div>
</div>
</td>
<td>
<div class="input-group mb-3">
<div class="input-group mb-3">
<select name="category" class="form-select category" id="inputGroupSelect01">
<option disabled selected>Choose...</option>
<option>EMO</option>
<option>Analysts</option>
<option>Maintenance</option>
<option>ETS</option>
<option>BOT</option>
<option>OtherUT</option>
<option>Materials</option>
<option>Non-UT Contract</option>
<option>Contingency</option>
</select>
</div>
</div>
</td>
<td>
<div class="input-group mb-3">
<input name="cost" type="text" class="cost form-control">
</div>
</td>
<td>
<div class="input-group mb-3">
<input name="hours" type="text" class="hours form-control">
</div>
</td>
<td>
<button type="button" style="background-color: #bf5700;"
class="btn btn-warning text-light addRow"><i
class="fas fa-plus-circle"></i> Add
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="row text-center my-3">
<div class="col-11 text-end">
<button disabled id="next" type="button" class='btn btn-success'><a id="link"
class="text-white">Next</a>
</button>
</div>
</div>
</div>
</form>
</div>
The issue is indeed the first row. You are cloning it after inputs within it are disabled
Create a clone() of it when page loads and before anything is disabled within that row. If there are any preset values in first row you can reset them in the cloned version
Then append a clone of that clone as needed and prior to that append disable other inputs
Simplified working version of add and disable:
const $table = $('#tableData'),
$tbody = $table.find('tbody'),
$cloneRow = $tbody.find('tr').first().clone();
$table.on('click', 'button.addRow', (e) => {
e.preventDefault();
$tbody.find(':input').prop('disabled', true);
$tbody.append($cloneRow.clone());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">Home</li>
<li class="breadcrumb-item active" aria-current="page">Costs and Hours</li>
</ol>
</nav>
<form action='/costs_hours' id="formData" method="POST">
<div class="card border-secondary w-100 text-light" style="background-color: #333f48">
<h5 style="background-color: #bf5700;" class="card-header">Costs & Hours</h5>
<div class="card-body w-100 text-end">
<div id="errors" class="text-start"></div>
<table id="tableData" class="table text-light text-center mt-3">
<thead>
<tr>
<th scope="col">Implementation or Annual</th>
<th scope="col">Category</th>
<th scope="col">Costs</th>
<th scope="col">Hours</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="input-group mb-3">
<div class="input-group mb-3">
<select name="imp_or_ann" class="form-select imp_or_ann"
id="inputGroupSelect01">
<option disabled selected>Choose...</option>
<option>Implementation</option>
<option>Annual</option>
</select>
</div>
</div>
</td>
<td>
<div class="input-group mb-3">
<div class="input-group mb-3">
<select name="category" class="form-select category" id="inputGroupSelect01">
<option disabled selected>Choose...</option>
<option>EMO</option>
<option>Analysts</option>
<option>Maintenance</option>
<option>ETS</option>
<option>BOT</option>
<option>OtherUT</option>
<option>Materials</option>
<option>Non-UT Contract</option>
<option>Contingency</option>
</select>
</div>
</div>
</td>
<td>
<div class="input-group mb-3">
<input name="cost" type="text" class="cost form-control">
</div>
</td>
<td>
<div class="input-group mb-3">
<input name="hours" type="text" class="hours form-control">
</div>
</td>
<td>
<button type="button" style="background-color: #bf5700;"
class="btn btn-warning text-light addRow"><i
class="fas fa-plus-circle"></i> Add
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="row text-center my-3">
<div class="col-11 text-end">
<button disabled id="next" type="button" class='btn btn-success'><a id="link"
class="text-white">Next</a>
</button>
</div>
</div>
</div>
</form>
</div>
I wrote a code for a shopping cart. In that for each change in quantity value (either increasing or decreasing) there should be a change in the price. I tried to implement this for a decreasing price with respect to the quantity. I can change the quantity but I am not able to change the price field because the price still gives me the type of object as I console.log. Can anyone point out what I am doing wrong?
Below is the code:
product.html
<tr>
<td class="product-thumbnail">
<img src="images/cloth_1.jpg" alt="Image" class="img-fluid">
</td>
<td class="product-name">
<h2 class="h5 text-black">Top Up T-Shirt</h2>
</td>
<!-- The price -->
<td>$49.00</td>
<td>
<div class="input-group mb-3" style="max-width: 120px;">
<div class="input-group-prepend">
<button class="btn btn-outline-primary js-btn-minus" type="button">−</button>
</div>
<input type="text" class="form-control text-center" value="1" placeholder="" aria-label="Example text with button addon" aria-describedby="button-addon1">
<div class="input-group-append">
<button class="btn btn-outline-primary js-btn-plus" type="button">+</button>
</div>
</div>
</td>
<td>
<div class="price"></div>
</td>
<td>X</td>
</tr>
<tr>
<td class="product-thumbnail">
<img src="images/cloth_2.jpg" alt="Image" class="img-fluid">
</td>
<td class="product-name">
<h2 class="h5 text-black ">Polo Shirt</h2>
</td>
<td>$49.00</td>
<td>
<div class="input-group mb-3" style="max-width: 120px;">
<div class="input-group-prepend">
<button class="btn btn-outline-primary js-btn-minus" type="button">−</button>
</div>
<input type="text" class="form-control text-center" value="1" placeholder="" aria-label="Example text with button addon" aria-describedby="button-addon1">
<div class="input-group-append">
<button class="btn btn-outline-primary js-btn-plus" type="button">+</button>
</div>
</div>
</td>
<td>
<div class="price">8</div>
</td>
<td>X</td>
</tr>
main.js
<script>
$('.js-btn-minus').on('click', function(e)
{
e.preventDefault();
if ( $(this).closest('.input-group').find('.form-control').val() !=0 && $(this).closest('.input-group').find('.form-control').val() >0)
{
$(this).closest('.input-group').find('.form-control').val(parseInt($(this).closest('.input-group').find('.form-control').val()) - 1);
var va = parseInt($(this).closest('.input-group').find('.form-control').val());
va = (parseInt(va));
this.a = va;
console.log(this.a);
var price = $(this).closest('tr').find('.price');
console.log(price.val(parseInt(this.a)));
}
}
</script>
use price.html or price.text instead of price.val and then remember, input get value by .val() but other element get by .html() or .text()
First thing is that your table is not well structured. Second thing is that your requirement is not exactly clear to me.
Thought I assume you want to increase or decrease the price where the class is price.
You are receiving the whole element as you are using val() and it is always going to be the object.
If you could tell the exact issue/requirement, I can help you out.
$('.js-btn-minus').on('click', function(e)
{
e.preventDefault();
var next_val = parseInt($(this).closest('.input-group').find('.form-control').val()) - 1;
if (next_val < 0){
next_val = 0
$(this).closest('.input-group').find('.form-control').val(0)
}
else{
$(this).closest('.input-group').find('.form-control').val(next_val);
var existing_value = $(this).closest('tr').find('.price').html()
if ((existing_value || '') == ''){
$(this).closest('tr').find('.price').html(next_val)
}
else{
$(this).closest('tr').find('.price').html(existing_value - 1)
}
}
// Price updates
//var current_price = parseInt($(this).closest('.input-group').parent().prev('td').html().replace('$', ''))
//var final_price = current_price - next_val;
});
$('.js-btn-plus').on('click', function(e)
{
e.preventDefault();
var next_val = parseInt($(this).closest('.input-group').find('.form-control').val()) + 1;
if (next_val < 0){
next_val=0;
$(this).closest('.input-group').find('.form-control').val(0)
}
else{
$(this).closest('.input-group').find('.form-control').val(next_val);
var existing_value = parseInt($(this).closest('tr').find('.price').html())
if ((existing_value || '') == ''){
$(this).closest('tr').find('.price').html(next_val)
}
else{
$(this).closest('tr').find('.price').html(existing_value + 1)
}
}
// Price updates
//var current_price = parseInt($(this).closest('.input-group').parent().prev('td').html().replace('$', ''))
//var final_price = current_price + 1
//console.log(final_price)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td class="product-thumbnail">
<img src="images/cloth_1.jpg" alt="Image" class="img-fluid">
</td>
<td class="product-name">
<h2 class="h5 text-black">Top Up T-Shirt</h2>
</td>
<!-- The price -->
<td class="current_price">$49.00</td>
<td>
<div class="input-group mb-3" style="max-width: 120px;">
<div class="input-group-prepend">
<button class="btn btn-outline-primary js-btn-minus" type="button">−</button>
</div>
<input type="text" class="form-control text-center" value="1" placeholder="" aria-label="Example text with button addon" aria-describedby="button-addon1">
<div class="input-group-append">
<button class="btn btn-outline-primary js-btn-plus" type="button">+</button>
</div>
</div>
</td>
<td>
<div class="price"></div>
</td>
<td>X</td>
</tr>
<tr>
<td class="product-thumbnail">
<img src="images/cloth_2.jpg" alt="Image" class="img-fluid">
</td>
<td class="product-name">
<h2 class="h5 text-black ">Polo Shirt</h2>
</td>
<td class="current_price">$49.00</td>
<td>
<div class="input-group mb-3" style="max-width: 120px;">
<div class="input-group-prepend">
<button class="btn btn-outline-primary js-btn-minus" type="button">−</button>
</div>
<input type="text" class="form-control text-center" value="1" placeholder="" aria-label="Example text with button addon" aria-describedby="button-addon1">
<div class="input-group-append">
<button class="btn btn-outline-primary js-btn-plus" type="button">+</button>
</div>
</div>
</td>
<td>
<div class="price">8</div>
</td>
<td>X</td>
</tr>
</table>