How to add HTML form fields based on JSON response data - javascript

I have a HTML form for products which contains initially a fields group (for the product components) of 2 rows and can add rows using a button with an onClick event to a js function addRow(). the code is:
<?php
$arrayNumber = 0;
for($x = 1; $x < 3; $x++) { ?>
<tr id="editRow<?php echo $x; ?>" class="<?php echo $arrayNumber; ?>">
<td style="padding-left:20px;padding-right: 20px;">
<div class="form-group">
<select class="form-control" name="editRawName[]" id="editRawName<?php echo $x; ?>" onchange="getRawData(<?php echo $x; ?>)">
<option value="">~~SELECT~~</option>
<?php
$rawSql = "SELECT * FROM raw_material WHERE status = 1";
$rawData = $connect->query($rawSql);
while($row = $rawData->fetch_array()) {
echo "<option value='".$row['raw_id']."' id='changeRaw".$row['raw_id']."'>".$row['raw_name']."</option>";
} // /while
?>
</select>
</div>
</td>
<td style="padding-left:20px;">
<div class="form-group">
<input type="number" name="editQuantity[]" id="editQuantity<?php echo $x; ?>" autocomplete="off" class="form-control" min="1"/>
</div>
</td>
<td>
<button class="btn btn-default removeRawRowBtn" type="button" id="removeRawRowBtn" onclick="removeRawRow(<?php echo $x; ?>)"><i class="glyphicon glyphicon-trash"></i></button>
</td>
</tr>
<?php
$arrayNumber++;
} // /for?>
Now, to edit a product I use a js function editProduct() to fetch the selected product data and return it as a JSON response to fill the product form fields. The editProduct function code part to grab and fill product fields is:
function editProduct(productId = null) {
if(productId) {
$("#productId").remove();
$(".text-danger").remove();
$(".form-group").removeClass('has-error').removeClass('has-success');
$('.div-loading').removeClass('div-hide');
$('.div-result').addClass('div-hide');
$.ajax({
url: 'action.php',
type: 'post',
data: {productId: productId},
dataType: 'json',
success:function(response) {
$('.div-loading').addClass('div-hide');
$('.div-result').removeClass('div-hide');
$(".editProductFooter").append('<input type="hidden" name="productId" id="productId" value="'+response.product_id+'" />');
// product name
$("#editProductName").val(response.product_name);
// category name
$("#editCategoryName").val(response.categories_id);
// quantity
$("#editProductQuantity").val(response.quantity);
// product unit
$("#editProductUnit").val(response.product_unit);
// sales margin
$("#editSalesMargin").val(response.sales_margin);
// status
$("#editProductStatus").val(response.status);
// Get the product components count
var totalComponents = response.total_components;
// Loop for every component
// Set the fields id that will contains the data
// Fill the fields with data
for (var x = 0; x<totalComponents; x++){
var idrawn = "#editRawName"+x.toString();
var idrawq = "#editQuantity"+x.toString();
var resri = "raw_id_"+x.toString();
var resqu = "rp_quantity_"+x.toString();
$(idrawn).val(response[resri]);
$(idrawq).val(response[resqu]);
}
The problem is: In case of a product with a total components of more than 2, I need to add rows to be filled with the components data.
First, I tried to launch the addRow() function before the last for loop in the editProduct function like this (didn't work):
if (totalComponents > 2) {
var adro = totalComponents - 2;
for (var y=0; y<adro; y++)
{ addRow(); }
}
Then, I tried to simulate the click of the Add Component button that launch the addRow function using the solution posted here: How to simulate a click with JavaScript? and change the above code like this:
if (totalComponents > 2) {
var adro = totalComponents - 2;
for (var y=0; y<adro; y++)
{ eventFire(document.getElementById('addRowBtn'), 'click'); }
}
but still no luck.
The code of addRow function is:
function addRow() {
$("#addRowBtn").button("loading");
var tableLength = $("#rawTable tbody tr").length;
var tableRow;
var arrayNumber;
var count;
if(tableLength > 0) {
tableRow = $("#rawTable tbody tr:last").attr('id');
arrayNumber = $("#rawTable tbody tr:last").attr('class');
count = tableRow.substring(3);
count = Number(count) + 1;
arrayNumber = Number(arrayNumber) + 1;
} else {
// no table row
count = 1;
arrayNumber = 0;
}
$.ajax({
url: 'action1.php',
type: 'post',
dataType: 'json',
success:function(response) {
$("#addRowBtn").button("reset");
var tr = '<tr id="row'+count+'" class="'+arrayNumber+'">'+
'<td style="padding-left:20px;padding-right: 20px;">'+
'<div class="form-group">'+
'<select class="form-control" name="rawName[]" id="rawName'+count+'" onchange="getRawData('+count+')" >'+
'<option value="">~~SELECT~~</option>';
$.each(response, function(index, value) {
tr += '<option value="'+value[0]+'">'+value[1]+'</option>';
});
tr += '</select>'+
'</div>'+
'</td>'+
'<td style="padding-left:20px;">'+
'<div class="form-group">'+
'<input type="number" name="quantity[]" id="quantity'+count+'" autocomplete="off" class="form-control" min="1" />'+
'</div>'+
'</td>'+
'<td>'+
'<button class="btn btn-default removeRawRowBtn" type="button" onclick="removeRawRow('+count+')"><i class="glyphicon glyphicon-trash"></i></button>'+
'</td>'+
'</tr>';
if(tableLength > 0) {
$("#rawTable tbody tr:last").after(tr);
$("#totalComponents").remove();
var comp = '<input type="hidden" name="totalComponents" id="totalComponents" value="'+count+'" />';
} else {
$("#rawTable tbody").append(tr);
$("#totalComponents").remove();
var comp = '<input type="hidden" name="totalComponents" id="totalComponents" value="'+tableLength+'" />';
}
$("#rawTable").after(comp);
}
});}
I was wandering if there is a way to get the result that I need.

Related

Onchange function for dropdown in jquery ajax

I have a script with two dropdowns that it is dependent on. The third dropdown is a price, readOnly, which is dependent on subcategory. I have given onChange but there are some problems. I could not render the price value. I am new to ajax and really need some help. I got this example and changed it to fit my needs. I need to just take price from the onClick of subcategory.
Here is my code:
<script>
$(document).ready(function(){
var count = 0;
$(document).on('click', '.add', function(){
count++;
var html = '';
html += '<tr>';
html += '<td> </td>';
html += '<input type="hidden" name="item_name[]" class="form-control item_name" />';
html += '<td><select name="item_category[]" class="form-control item_category" data-sub_category_id="'+count+'"><option value="">Select Service Type</option><?php echo fill_select_box($connect, "0"); ?></select></td>';
html += '<td><select name="item_sub_category[]" class="form-control item_sub_category" id="item_sub_category'+count+'"><option value="">Select Service Name</option></select></td>';
html += '<td><input type="text" name="item_sub_category_price[]" class="form-control item_sub_category_price" /></td>';
html +='<td><input type="text" name="nosessions[]" class="form-control nosessions" /></td>';
html += '<td><button type="button" name="remove" class="btn btn-danger btn-xs remove"><span class="glyphicon glyphicon-minus"></span>Remove Service</button></td>';
$('tbody').append(html);
});
$(document).on('click', '.remove', function(){
$(this).closest('tr').remove();
});
$(document).on('change', '.item_category', function(){
var category_id = $(this).find(':selected').data('foo');
var sub_category_id = $(this).data('sub_category_id');
// var sub_category_price = $(this).data('sub_category_price');
$.ajax({
url:"fill_sub_category.php",
method:"POST",
data:{category_id:category_id},
success:function(data){
var html = '<option value="">Select Sub Category</option>';
html += data;
$('#item_sub_category'+sub_category_id).html(html);
}
})
});
$(document).on('change', '.sub_category_id', function(){
alert( this.value );
});
$('#insert_form').on('submit', function(event){
event.preventDefault();
var error = '';
$('.item_category').each(function(){
var count = 1;
if($(this).val() == ''){
error += '<p>Select Item Category at '+count+' row</p>';
return false;
}
count = count + 1;
});
$('.item_sub_category').each(function(){
var count = 1;
if($(this).val() == ''){
error += '<p>Select Item Sub category '+count+' Row</p> ';
return false;
}
count = count + 1;
});
$('.item_sub_category_price').each(function(){
var count = 1;
if($(this).val() == ''){
error += '<p>Select Item price '+count+' Row</p> ';
return false;
}
count = count + 1;
});
$('.nosessions').each(function(){
var count = 1;
if($(this).val() == ''){
error += '<p>Select no of sessions '+count+' Row</p> ';
return false;
}
count = count + 1;
});
$('.packname').each(function(){
if($(this).val() == ''){
error += '<p>Select no of packname '+count+' Row</p> ';
return false;
}
});
var form_data = $(this).serialize();
if(error == ''){
$.ajax({
url:"insert.php",
method:"POST",
data:form_data,
success:function(data){
if(data == 'ok'){
$('#item_table').find('tr:gt(0)').remove();
$('#error').html('<div class="alert alert-success">Item Details Saved</div>');
}
}
});
}; else{
$('#error').html('<div class="alert alert-danger">'+error+'</div>');
}
});
});
</script>
<script>
$(document).ready(function(){
var count = 0;
$(document).on('click', '.add', function(){
count++;
var html = '';
html += '<tr>';
html += '<td> </td>';
html += '<input type="hidden" name="item_name[]" id="item_name'+count+'" class="form-control item_name" />';
html += '<td><select name="item_category[]" id="item_category'+count+'" onchange="getsubCategory('+count+')" class="form-control item_category" data-sub_category_id="'+count+'"><option value="">Select Service Type</option><?php echo fill_select_box($connect, "0"); ?></select></td>';
html += '<td><select name="item_sub_category[]" id="item_sub_category'+count+'" class="form-control item_sub_category" id="item_sub_category'+count+'"><option value="">Select Service Name</option></select></td>';
html += '<td><input type="text" name="item_sub_category_price[]" id="item_sub_category_price'+count+'" class="form-control item_sub_category_price" /></td>';
html +='<td><input type="text" name="nosessions[]" id="nosessions'+count+'" class="form-control nosessions" /></td>';
html += '<td><button type="button" name="remove" class="btn btn-danger btn-xs remove"><span class="glyphicon glyphicon-minus"></span>Remove Service</button></td>';
$('tbody').append(html);
});
$(document).on('click', '.remove', function(){
$(this).closest('tr').remove();
});
});
function getsubCategory(id){
var itemCategory="item_category"+id;
var subcategory_id = "item_sub_category"+id;
var category_id= $("#"+itemCategory).val();
$.ajax({
url:"fill_sub_category.php",
method:"POST",
data:{category_id:category_id},
success:function(data){
var html = '<option value="">Select Sub Category</option>';
html += data;
$('#'+subcategory_id).html(html);
}
})
}
</script>
You can do the same for others
I assume that you need to get price of the sub-category using AJAX,
$(document).on('change', '.sub_category_id', function(){
var sub_category_id = $(this).val();
$.ajax({
url:"get_sub_category_price.php",
method:"POST",
data:{sub_category_id : sub_category_id},
success:function(data){
$('#item_sub_category'+sub_category_id).parent().next().find('. item_sub_category_price').val(data);
}
});
});
get_sub_category_price.php file should get the subcategory id and echo the price.

I can't save specific selected value. it saved all data from database

i am inserting multiple data. what happen is when i select a project from drop down list. it save all data from selection. please check the image below first
function sample($con){
$select = "SELECT * FROM project_tbl";
$select_result = mysqli_query($con,$select);
if (mysqli_num_rows($select_result)> 0) {
while ($row = mysqli_fetch_assoc($select_result)) {
echo "<option value=".$row['project_name'].">" .$row['project_name']."</option>";
}
}
}
*html codes (i used drop down list to populate data from database)
<td class="pro">
<select class="pro">
<option value=""><?php sample($con); ?></option>
</select>
</td>
*ajax codes (adding, saving and removing)
$(document).ready(function(){
var count = 1;
$('#add').click(function(){
count = count + 1;
var html_code = "<tr id='row"+count+"'>";
html_code += "<td class='pro'><select class='pro'><option value=''><?php sample($con); ?></option></select></td>";
html_code += "<td contenteditable='true' class='desc'></td>";
html_code += "<td contenteditable='true' class='comp'></td>";
html_code += "<td contenteditable='true' class='entry'></td>";
html_code += "<td contenteditable='true' class='remarks'></td>";
html_code += "<td><button type='button' name='remove' data-row='row"+count+"' class='btn btn-outline-danger btn-xs remove' title='remove'><i class='fa fa-times' aria-hidden='true'></i></button></td>";
html_code += "</tr>";
$('#crud_table').append(html_code);
});
$(document).on('click', '.remove', function(){
var delete_row = $(this).data("row");
$('#' + delete_row).remove();
});
$('#save').click(function(){
var desc = [];
var pro = [];
var comp = [];
var entry = [];
var remarks = [];
$('.desc').each(function(){
desc.push($(this).text());
});
$('.pro').each(function(){
pro.push($(this).text());
});
$('.comp').each(function(){
comp.push($(this).text());
});
$('.entry').each(function(){
entry.push($(this).text());
});
$('.remarks').each(function(){
remarks.push($(this).text());
});
$.ajax({
url:"insert_inspection.php",
method:"POST",
data:{desc:desc, pro:pro, comp:comp, entry:entry, remarks:remarks},
success:function(data){
alert(data);
$("td[contentEditable='true']").text("");
$('select').prop('selectedIndex',0);
for(var i=2; i<= count; i++){
$('tr#'+i+'').remove();
}
}
});
});
});
Here is what happen when I save.
database
I am new in PHP.
insert_inspection.php
<?php
$con = mysqli_connect("localhost", "root", "", "pms");
if (isset($_POST["desc"])){
$desc = $_POST["desc"];
$pro = $_POST["pro"];
$comp = $_POST["comp"];
$entry = $_POST["entry"];
$remarks = $_POST["remarks"];
$query = '';
for($count = 0; $count<count($desc); $count++){
$desc_clean = mysqli_real_escape_string($con, $desc[$count]);
$pro_clean = mysqli_real_escape_string($con, $pro[$count]);
$comp_clean = mysqli_real_escape_string($con, $comp[$count]);
$entry_clean = mysqli_real_escape_string($con, $entry[$count]);
$remarks_clean = mysqli_real_escape_string($con, $remarks[$count]);
if($desc_clean != '' && $pro_clean != '' && $comp_clean != '' && $entry_clean != '' && $remarks_clean != ''){
$query .= 'INSERT INTO `inspection_tbl`(`description`, `project_name`, `completion`, `entry`, `remarks`) VALUES("'.$desc_clean.'", "'.$pro_clean.'", "'.$comp_clean.'", "'.$entry_clean.'", "'.$remarks_clean.'");
';
}
}
if($query != ''){
if(mysqli_multi_query($con, $query)){
echo 'Item Data Inserted';
}else{
echo 'Error';
}
}else{
echo 'All Fields are Required';
}
}
?>
it is saved as such because your select element only has one option value
modify it from:
<td class="pro"> <select class="pro"> <option value=""><?php sample($con); ?></option> </select> </td>
to:
<td class="pro">
<select class="pro">
<option value=""></option>
<?php sample($con); ?>
</select>
</td>
and modify your select element handler to push only your selected item
something like this:
$('.pro').each(function(){
if($(this).prop("selected")) {
pro.push($(this).text());
}
});
or modify this part to something like:
$(".pro > option:selected").each(function(){
pro.push($(this).text());
});

change checkbox label after select

I have some checkboxes (101) which labels should change based on a select input. The JS I have only runs for one, which is logical. Though I'm not very familiar with jquery functions, I don't know how to proceed for all the 101 checkboxes.
the inputs :
<?php
for ($i = 1; $i < 102; $i++): //adjust this number to whatever number of checkboxes you want
echo '<div class="each_checkboxes">';
// $j = sprintf('%04u', $i);
echo '<label id="contact" for="checkbox"></label>';
echo '<input type="checkbox" name="tape[]" id="checkbox" value=""/>';
echo '</div>';
endfor;
?>
the select :
<select id="method" name="server" class="custom-dropdown__select custom-dropdown__select--white" required>
<option value="0" default>Choose server</option>
<option value="server1">server 1</option>
<option value="server2">server 2</option>
</select>
the js :
$(document).ready(function () {
$('#method').change(function () {
var method = $('option:selected').val();
if (method == "server1") {
$('#contact').text("MA" + i);
} else if (method == "server2") {
$('#contact').text("SAS" + i);
}
});
});
You need to use class instead of id, because id should be unique for each element. Try like following.
PHP:
<?php
for ($i = 1; $i < 102; $i++):
echo '<div class="each_checkboxes">';
echo '<label class="contact" for="checkbox'.$i.'"></label>';
echo '<input type="checkbox" name="tape[]" id="checkbox'.$i.'" value=""/>';
echo '</div>';
endfor;
?>
jQuery:
$(document).ready(function () {
$('#method').change(function () {
var method = $('option:selected').val(),
text = "";
if (method == "server1") {
text = "MA";
} else if (method == "server2") {
text = "SAS";
}
$('.contact').each(function (i) {
var value = text + (++i);
$(this).text(value);
$('#' + $(this).attr('for')).val(value);
});
});
});
You are referencing to id attribute in your jQuery selector which will only look for first match in your dom You need to assign a class to your label and reference to that when changing you label text then this will work.
<?php
for ($i = 1; $i < 102; $i++): //adjust this number to whatever number of checkboxes you want
echo '<div class="each_checkboxes">';
// $j = sprintf('%04u', $i);
echo '<label id="contact" class="contact" for="checkbox"></label>';
echo '<input type="checkbox" name="tape[]" id="checkbox" value=""/>';
echo '</div>';
endfor;
?>
and in jQuery just use class selector like this;
$(document).ready(function () {
$('#method').change(
function () {
var method = $('option:selected').val();
if (method == "server1") {
$('.contact').text("MA" + i);
} else if (method == "server2") {
$('.contact').text("SAS" + i);
}
});
});
That's it.
Use label class instead of id
<?php
for ($i = 1; $i < 102; $i++): //adjust this number to whatever number of checkboxes you want
echo '<div class="each_checkboxes">';
// $j = sprintf('%04u', $i);
echo '<label class="contact" for="checkbox"></label>';
echo '<input type="checkbox" name="tape[]" id="checkbox" value=""/>';
echo '</div>';
endfor;
?>
js code is
$(document).ready(function () {
$('#method').change(
function () {
var method = $('option:selected',this).val();
if (method == "server1") {
$('.each_checkboxes label.contact').html("MA" + i);
} else if (method == "server2") {
$('.each_checkboxes label.contact').html("SAS" + i);
}
});
});
Use "class" for your checkbox's label instead of "id". Basically, "id" of an element should be unique. But class, more than one elements can have the same class.
So, the label should be like this:
<label class="contact" for="checkbox"></label>
Then your onchange method should be like this:
$('#method').change(
function () {
var method = $('option:selected').val();
if (method == "server1") {
$('.contact').text("MA" + i);
} else if (method == "server2") {
$('.contact').text("SAS" + i);
}
});

Cloned elements' events corresponding to all elements in the form

I successfully cloned my table rows, which has values retrieved from database. However I have few issues with it.I used class for all the elements as clone will duplicate IDs.No the problem raises because it unable to target each element uniquely. WHat's the way to do make each element / row unique here?
How the functions work:
When first select box selected, item for that selected id would appear in the next column.Followed by price textbox and quantity textbox. WHen both are filled up, last textbox for total amount would automatically appear.
Issues with the cloning are:
* WHen select box selected from the first/original row, all cloned items are updated with the value.Same goes for amount textbox and vise-versa.
My script:
<script>
var harga;
var qty;
$("input[name^=harga]").on("keyup", function () {
alert($(this).attr("id"));
console.log($(this).val());
harga = $(this).val();
});
$(".qty").on("keyup", function () {
console.log($(this).val());
qty = $(this).val();
var amount = harga * qty;
$(".amount").val(amount);
});
$(document).ready(function () {
$(".sub_item").hide();
$('.gr').change(function () {
var gr_id = $(this).find('option:selected').val();
console.log(gr_id);
var agency_id = '<?php echo $_SESSION['
agency_id
'];?>';
/*show branch for selected department starts*/
var data;
$.ajax({
type: "POST",
dataType: "json",
url: s_path + "get-item.php?group=" + gr_id + "&agency=" + agency_id, //Relative or absolute path to response.php file
data: data,
success: function (data) {
$(".sub_item").show();
$(".it_id").empty();
for (i = 0; i < data.length; i++) {
$(".it_id").append("<option value='" + data[i].item_id + "'>" + data[i].item_name + "</option>");
}
if (data.length == "") {
$(".it_id").append("<option>No items found</option>");
}
console.log(data);
}});//end success
/*show branch ends*/
});
});
$("#more_items").on("click", function () {
alert("Hi");
$(".clone_this").clone(true, true).insertBefore("#last_e");
});
$(function () {
$("#hide1").hide();
$("#hide2").hide();
$("#hide3").hide();
$('#faktor').change(function () {
var val = $(this).val();
//alert($(this).val());
if ($.trim(val) == 1) {
$("#hide1").show();
} else {
$("#hide1").hide();
}
});
$('#insurance').change(function () {
$("#hide2").show();
var val = $(this).val();
//alert($(this).val());
if ($.trim(val) == 1) {
$("#hide2").show();
} else {
$("#hide2").hide();
}
});
$('#bon').change(function () {
$("#hide3").show();
var val = $(this).val();
//alert($(this).val());
if ($.trim(val) == 1) {
$("#hide3").show();
} else {
$("#hide3").hide();
}
});
});
</script>
Form
<form action="#" method="POST" id="submit_item">
<input type="text" name="contract_id" value="" id="contract_id2"/>
<table>
<tr>
<th>Group Item</th>
<th>Nama Item</th>
<th>Harga</th>
<th>Kuantiti</th>
<th>Amount</th>
</tr>
<tr class="clone_this">
<td>
<select name='group' style="width:80px;" class="gr">
<option>Choose group</option>
<?php
$group = $agency->show_all_group();
foreach ($group as $k => $v) {
$i = 0;
$i++;
?>
<option value="<?php echo $v['group_id'] ?>"><?php echo $v['group_name'] ?></option>
<?php
}
?>
</select>
</td>
<td class="sub_item">
<select name='item' style="width:100px;" class="it_id">
</select>
</td>
<td><input type="text" name="harga_<?php echo $i; ?>[]" id="<?php echo $i; ?>" value="" class="harga"/></td>
<td>
<input type='text' size='2' value="" name='qty[]' class='qty'/>
</td>
<td><input type="text" name="amount[]" class="amount" value=""/></td>
</tr>
<tr id="last_e">
<td colspan="3"><input type="submit" name="submit" value="Next" id="item_s"/></td>
<td><input type="button" value="Add more items" id="more_items"/></td>
</tr>
</table>
</form>
You need find the relative elements to update so
$(document).ready(function () {
$('#submit_item').on('keyup', '.qty, .harga', function () {
var $tr= $(this).closest('tr');
$tr.find('.amount').val($tr.find('.harga').val() * $tr.find('.qty').val() || 0)
})
$(".sub_item").hide();
$('#submit_item').on('change', '.gr', function () {
var $this = $(this),
$tr = $this.closest('tr'),
gr_id = $this.find('option:selected').val(),
$subitem = $tr.find('.sub_item'),
$it_id = $tr.find('.it_id');
var agency_id = '<?php echo $_SESSION['agency_id'];?>';
/*show branch for selected department starts*/
var data;
$.ajax({
type: "POST",
dataType: "json",
url: s_path+"get-item.php?group="+gr_id+"&agency="+agency_id, //Relative or absolute path to response.php file
data: data,
success: function (data) {
$subitem.show();
$it_id.empty();
for (i = 0; i < data.length; i++) {
$it_id.append("<option value='" + data[i].item_id + "'>" + data[i].item_name + "</option>");
}
if (data.length == "") {
$it_id.append("<option>No items found</option>");
}
console.log(data);
}
}); //end success
/*show branch ends*/
});
});
Demo: Fiddle

javascript only executing on first row of table

I've got a table row that is repeating 15 times. Then on one of the fields it executes JS. The problem is it's only executing the JS on the first row of the table. What am I doing wrong?
PHP Table script:
for ($x = 1; $x <= 15; $x++) {
echo '<tr>';
echo '<td><input size="6" id="qty" name="qty' . $x . '" type="text"/></td>';
echo '<td><input onfocus="calcTotal()" type="text" name="tot' . $x . '" id="tot" size="6" readonly/></td>';
echo '</tr>';
}
The JS:
function calcTotal() {
var myqty = document.getElementById('qty').value;
var myrate = <?php echo json_encode($therate); ?>;
myResult = myqty * myrate;
var elem = document.getElementById("tot");
elem.value = myResult;
}
Because you are repeating the INPUT, whose ID is qty. You can't repeat DOM IDs, otherwise you run into problems like this.

Categories

Resources