Dropdown select not working with single option in Svelte - javascript

I have a dropdown menu in my Svelte application that displays a list of players. I want to be able to search for a player in this list and have the dropdown menu show only the players that match the search query. However, when there is only one matching player in the list, I am unable to select (update) that player from the dropdown menu; but the dropdown menu displays one player. How can I fix this issue?
Select
<select class="form-select" bind:value={player_id} id="player">
{#each players as player}
{#if !tournament.players.includes(player._id) && player.name
.toLowerCase()
.includes(searchTerm.toLowerCase())}
<option value={player._id}>{player.name}</option>
{/if}
{/each}
</select>
Search bar
<input class="rounded line"
type="text"
bind:value={searchTerm}
placeholder="Search for a player"
/>
Update button
<button class="btn btn-primary line"
on:click={addPlayerToTournament}>Update
</button>
UPDATED Function addPlayertoTournament
function addPlayerToTournament() {
tournament.players.push(player_id);
tournament.players = tournament.players;
axios
.put(
"http://localhost:3001/api/tournaments/" + tournament_id,
tournament
)
.then((response) => {
getTournament();
});
}
I have tried using the includes function to check if the player's name is included in the search term, and then using an if statement to only show players that meet this condition in the dropdown menu.
I would appreciate any help or suggestions on how to resolve this problem.

I wanted to thank user #Corrl for all of their help and effort in providing a working solution. I am now able to move forward with my project and I am very grateful for their contributions. I have attached the solution that worked for me in the end, let me know if you have any questions.
Code Block
<script>
let searchTerm = "";
let selectablePlayers = [];
$: calculateSelectablePlayers(searchTerm, tournament)
function calculateSelectablePlayers(searchTerm, tournament) {
console.log('calculate - only runs if searchTerm or tournament changes')
if(searchTerm || tournament.players.length > 0) {
selectablePlayers = players.filter(player => {
const notYetInTournament = !tournament.players.includes(player._id)
const searchTermInName = player.name.toLowerCase().includes(searchTerm.toLowerCase())
return notYetInTournament && searchTermInName
})
if(searchTerm) player_id = selectablePlayers[0]?._id ?? ''
} else {
selectablePlayers = players
}
}
function addPlayerToTournament() {
tournament.players = [...tournament.players, player_id];
player_id = "";
console.log(tournament.players);
axios
.put(
"http://localhost:3001/api/tournaments/" + tournament_id,
tournament
)
.then((response) => {
getTournament();
});
}
</script>
<body>
<div>
<h3>Add Players</h3>
<!-- Add an input element for the search bar -->
<div
class="input-button-container mb-2"
style="display: flex; align-items: center;"
>
<input
class="rounded line"
type="text"
bind:value={searchTerm}
placeholder=" Search for a player"
/>
<button
class="btn btn-primary line"
on:click={addPlayerToTournament} disabled={player_id === ''}>Update</button
>
</div>
<select class="form-select" bind:value={player_id} id="player">
<option value="" disabled>please select player</option>
{#each selectablePlayers as player, i}
<option value={player._id}>{player.name}</option>
{/each}
</select>
</div>
</body>

Related

Why is this computed() supposed to filter a listof items if anything is writen in a text input not working?

I have this super simple vue3 App, it works kinda like a to-do app, you add an item, and it pushes into an Array which is displayed in Screen.
I set a <input/ type="text" with a v-model="" and made a computed which works over that array.
The logic is very simple, it has a .filter and a conditional with a return for the match case and the return of the original Array if the input is empty.
<template>
<div class="container">
<form #submit.prevent="addItem(item)">
<div class="form__first-row">
<label for="item">
<input type="text" v-model="item" id="item" placeholder="New Item" required>
</label>
{{ item }}
<button :disabled="!item.length" type="submit">Add Item</button>
</div>
</form>
<div class="filter-container">
<label for="filter-items">
<input type="text" id="filter-items" placeholder="Filter Items" required class="filter-input" v-model="filterText">
</label>
</div>
{{ filterText }}
<h2>Items List</h2>
<div class="list-container">
<div class="unpackedlist-container">
<b>
<p>Unpacked</p>
</b>
<ul>
<li v-for="fitem in filteredvalues" :key="fitem">
<button #click="deleteItem(item)">Delete item</button>
{{ fitem }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const item = ref('');
const packedItemsArray = ref([]);
function addItem (item) {
unpackedItemsArray.value.push(item);
};
const filterText = ref('')
const filteredvalues = computed(() => {
if (!filterText.value.length) {
return unpackedItemsArray.value
} else {
unpackedItemsArray.value.filter( val => val == filterText.value)
}
})
const deleteItem = () => {
return unpackedItemsArray.value.filter((val) => val != it )
}
</script>
The weird thing that I observed is that a console.log() of filterText.value inside the computed returns me an undefined, is that the problem? Async issue?
Any suggestion is highly appreciated! thanks in advence!
You forgot a return statement on line:
unpackedItemsArray.value.filter( val => val == filterText.value)
You should change it to:
return unpackedItemsArray.value.filter( val => val == filterText.value)
From the code I'm seeing here, i don't think the variable unpackedItemsArray is defined. That could be the p

How to make a click function in javascript loop through all records instead of just the first record

I have a feeling this problem I've having trouble with is pretty simple but I am new to all this and don't know all the ins and outs of html, javascript, etc. yet. The javascript functions is what's really difficult to learn for me. Anyways, I have an item cart where the users add whatever products they want to order. I'm trying to implement a function where when the user clicks the "Proceed To Checkout" button it checks to make sure whatever qty they are ordering does not exceed the amount we have in stock. If it does then display an alert message. I have a function working perfectly at the moment, but it is only checking the first record and not looping through anything. Any thoughts or insight on what I can do would be greatly appreciated. Here is my code:
#foreach (var item in (List<Item>)Session["cart"])
{
<tr>
<td>
#item.Pr.Product_Code
</td>
<td>
#item.Pr.Description<br />
<span class="text-left" id="errmsg"></span>
</td>
<td>
<img src="~/Images/#item.Pr.ImageUrl" width="100" height="80" />
</td>
<td>
<input type="text" value="#item.Qty" id="quantity" name="quantity" class="amtOrdered" /><br />
<input type="text" value="#item.Pr.Qty_Available" id="qty-avbl" name="qty-avbl" class="amt-avbl" hidden />
</td>
<td class="btn-sctn">
<button class="button">
<i class="fa solid fa-trash-o"></i>
#Html.ActionLink("Remove", "Delete", "ItemCart", new { id = item.Pr.ProductID },
new { onclick = "return confirm ('Are you sure you want to delete this item?');", #class = "remove" })
</button>
</td>
<td></td>
</tr>
}
</table>
<div></div>
<hr />
<p class="place-order">
<input type="submit" class="checkout" value="Proceed To Checkout" id="checkQty" />
</p>
<p class="keep-shop">
#Html.ActionLink("Continue Shopping", "ProductCatalog", "Products", "", new { #class = "shopping-link" })
</p>
}#*End of form*#
}#*End of if session*#
and my function I have for this is:
<script type="text/javascript">
$(document).ready(function () {
$("#checkQty").click(function (event) {
// Get the value of the input field with id
let qty = document.getElementById("quantity").value;
let avbl = document.getElementById("qty-avbl").value;
let text;
if (qty > avbl) {
event.preventDefault();
text = "There is not enough stock to order this amount";
document.getElementById("errmsg").innerHTML = text;
return false;
}
else {
text = "";
}
});
});
</script>
Try this, I hope it will solve your problem based on what you described.
<script type="text/javascript">
$(document).ready(function () {
$("#checkQty").click(function (event) {
// Get the value of the input field with id
let qtys = document.querySelectorAll('input[name="quantity"]');
let avbls = document.querySelectorAll('input[name="qty-avbl"]');
let text;
// assumming the quantity and available quantity inputs will be adjacent and equal in number
for(let i=0; i < qtys.length; i++){
let qty = qtys[i].value;
let avbl = avbls[i].value;
if (qty > avbl) {
event.preventDefault();
text = "There is not enough stock to order this amount";
document.getElementById("errmsg").innerHTML = text;
return false;
}
else {
text = "";
}
}
});
});
Here you can use for-of or foreach loop as well to iterate over all the inputs.

Is there any way to keep data in form before executing submit

so I have this form
<div class="container">
<form class="form">
<div class="rangeOfChanges">
<label for="range">Range of changes</label>
<input type="text" step="1" id="range" class="range" name="range" pattern="/(\d+-\d+|\d+)/g"/>
</div>
<div class="changeManyDevices">
<div class="changeManyDevicesDesc">
deviceType
</div>
<select name="device" id="device">
<option value="a"></option>
<option value="b"></option>
<option value="c"></option>
<option value="d"></option>
<option value="e"></option>
</select>
</div>
<div class="changeManyWiresType">
<div class="changeManyWiresTypeDesc">
CableDim
</div>
<select name="cable" id="cable">
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
</select>
</div>
<div class="changeManyWiresLength">
<div class="changeWiresLengthDesc">
CableLen
<input type="text" id="anotherInput" />
</div>
<div class="updateManySegmentsData">
<button type="submit" class="submitChanges">Submit</button>
</div>
</form>
</div>
and now via javascript ( without using jQuery ) I would like to handle my form.
My goal is to detect which input and/or select field has changed, and based on input.range apply changes to my array. So I have to have input.range filled and check in which other field changes were made, and if any apply those changes to array when submit button is clicked. I have tried doing that, my solution only works to apply changes to all attributes, not only for those who were changed.
function processData(e) {
if (e.preventDefault) {
e.preventDefault();
}
const input = document.getElementById(`range`).value;
const arrayOfInputRanges = input.replace(/\s/g, "").split(`,`);
const regex = /(\d+-\d+|\d+)/g;
const checkIfRegExp = regex.test(input);
const deviceSelect = document.getElementById(`changeManyDevices`);
const wireSelect = document.getElementById(`changeManyCables`);
const wireInput = document.getElementById(`manyCablesInputChange`).value;
const deviceSelectValue = deviceSelect.options[deviceSelect.selectedIndex].value;
const wireSelectValue = wireSelect.options[wireSelect.selectedIndex].value;
if (!checkIfRegExp) {
alert(`wrong input`);
return false;
} else if (checkIfRegExp) {
arrayOfInputRanges.forEach((element) => {
if (element.indexOf(`-`) > -1) {
//splitting array and sorting data.
const splitRange = element.split(`-`).sort();
for (let i = splitRange[0]; i <= splitRange[splitRange.length - 1]; i++) {
systemData.bus[i].deviceName = deviceSelectValue;
systemData.bus[i].cableType = wireSelectValue;
systemData.bus[i].cableLen_m = wireInput;
}
} else if (element.indexOf(`-`) === -1) {
console.log(element);
}
// parseInt(element);
// console.log(element);
});
}
return false;
}
function submitChanges() {
const submitFormButton = document.querySelector(`.changesForm`);
submitFormButton.addEventListener('submit', processData);
}
I know that in my solution I just take whatever value is holded in both select elements, same with both inputs. Maybe the solution is to just clear form inputs and selects every time user submits form so he has to put those values once again, and if he does not provide those just keep whatever value is in array?

Incrementing the name attribute of cloned inputs in jquery

I have a specific section of a form(a select box and three checkboxes) that needs to be duplicated upon request. I have the clone of the div working as well as the incrementing of that specific div, but I am having issues incrementing the checboxes itself to make it unique.
Here is my HTML:
<div class="orgboxdupe" style="border: 1px solid lightgrey; padding-left:20px;padding-right:20px;padding-bottom:20px;margin-top:10px; width: 600px;">
<h3>Add user to an organization</h3>
<select id="orggroupadd" class="user_groupadd" name="user_orggroupadd[]">
<option value="none">Select an organization</option>
<option value="152">Test4</option>
<option value="156">test9</option>
</select>
<br><br>Organization Admin (can view uploaded files): <input type="checkbox" name="orgadmincheckbox2"><br><br>c3 Access: <input type="checkbox" name="c3checkbox2"> c4 Access: <input type="checkbox" name="c4checkbox2">
</div>
On button click it creates a new orgboxdupe box with an incrementing ID but for some reason it increments the number on the first div checkboxes and not on the subsequent cloned checkboxes:
Here is my JS
//Portalorgs - add Users
//Vars
let $addnewgroupbutton = jQuery( "#addnewgroup" );
let $mainelement = jQuery("#orguserbox");
let $dupebox = jQuery(".orgboxdupe");
let $selectboxid = jQuery("#orggroupadd");
let $checkboxes = jQuery("input[type='checkbox']");
let $cloneindex = 1;
//Duplicating add organizations box for users - po-addusers.php
$addnewgroupbutton.click(function() {
$cloneindex++;
$dupebox.clone().appendTo($mainelement).attr("id","user_orggroupadd" + $cloneindex).find(':checked').attr('checked', false);
$checkboxes.each(function(){
jQuery(this).attr("name",jQuery(this).attr("name") + $cloneindex);
});
console.log($cloneindex);
});
Thanks for any help that can be provided.
As noted by #Taplar $checkboxes references the original checkboxes. So they are the ones being updated each time there's a click.
You need to reference the checkboxes in the just copied clone; you can use chaining like so:
....
.end().find(':checkbox').attr('name', function() {
return this.name + $cloneindex;
});
//Portalorgs - add Users
//Vars
let $addnewgroupbutton = jQuery( "#addnewgroup" );
let $mainelement = jQuery("#orguserbox");
let $dupebox = jQuery(".orgboxdupe");
let $selectboxid = jQuery("#orggroupadd");
let $checkboxes = jQuery("input[type='checkbox']");
let $cloneindex = 1;
//Duplicating add organizations box for users - po-addusers.php
$addnewgroupbutton.click(function() {
$cloneindex++;
$dupebox.clone().appendTo($mainelement).attr("id","user_orggroupadd" + $cloneindex).find(':checked').attr('checked', false)
//operate on the close via method chaining
.end().find(':checkbox').attr('name', function() {
return this.name + $cloneindex;
});
/*$checkboxes.each(function(){
jQuery(this).attr("name",jQuery(this).attr("name") + $cloneindex);
});*/
//console.log($cloneindex);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="addnewgroup">Add New Group</button>
<div id="orguserbox">
<div class="orgboxdupe" style="border: 1px solid lightgrey; padding-left:20px;padding-right:20px;padding-bottom:20px;margin-top:10px; width: 600px;">
<h3>Add user to an organization</h3>
<select id="orggroupadd" class="user_groupadd" name="user_orggroupadd[]">
<option value="none">Select an organization</option>
<option value="152">Test4</option>
<option value="156">test9</option>
</select>
<br><br>Organization Admin (can view uploaded files): <input type="checkbox" name="orgadmincheckbox2"><br><br>c3 Access: <input type="checkbox" name="c3checkbox2">
</div>
</div>

Make a NG-Options value select in same function as populating list

I am having some difficulties with selecting a value from an array in the same function that I populate the select using ng-options. I am trying to dynamically load a select list full of options and at the same time there is a default value from the last time the user chose something that I want to already be selected. when console.logging I can see that this works and is added to machineProfile.input but the select does not reflect what the ng-model has as a current value. I did confirm that they are both the same. I have some code below.
$scope.getMachineProfile = function(object) {
var count = 0;
var keepGoing = true;
$scope.machineProfile.machineName = object.Name;
$scope.machineInputs = object.Hardware;
/*angular.forEach(object.Hardware, function(inputs, key) {
console.log($scope.machineInputs);
});*/
//var foundMachine = 0;
angular.forEach($scope.machineProfiles, function(machine, key) {
if (keepGoing) {
if (machine.remoteAddr === object.Address) {
keepGoing = false;
/*$timeout(function(){
}, 500);*/
/*console.log($scope.machineProfiles[count].input);
console.log($scope.machineProfile.input);*/
$scope.machineProfile.input = $scope.machineProfiles[count].input;
$scope.machineProfile.workType = $scope.machineProfiles[count].workType;
$scope.machineProfile.workPeriod = $scope.machineProfiles[count].workPeriod;
$scope.machineProfile.counterRate = $scope.machineProfiles[count].counterRate;
$scope.machineProfile.timerRate = $scope.machineProfiles[count].timerRate;
console.log($scope.machineProfile);
//console.log('Awesome select: ' + count);
//console.log($scope.machineProfiles[count].input);
}
++count;
}
});
HTML
<ul class="nav sidebar-menu">
<li ng-repeat="machine in machineObj" class="">
<a ng-click="getMachineProfile(machine)">
<span class="fa fa-cogs"></span>
<span class="sidebar-title">{{machine.Name}}</span>
</a>
</li>
</ul>
Below is once a item is selected from the code above:
<div class="col-sm-4">
<div class="form-group">
<label for="chooseInput" class="control-label">Choose Input</label>
<!-- <select name="chooseInput" class="form-control" ng-model="machineProfile.input">
<option ng-selected="machine.input === machineProfile.input" ng-repeat="machine in machineInputs" value="machine.input">
{{machine.input === machineProfile.input}}
</option>
</select> -->
<select name="chooseInput" class="form-control" ng-model="input" ng-change="awesome(machineProfile.input)" ng-options="machine.input for machine in machineInputs track by machine.input"></select>
<!-- <input disabled="true" name="machineName" type="text" class="form-control" placeholder="Machine Name"> -->
</div>
</div>
Any help is appreciated as this is driving me nuts. The $scope object machineProfile.input is updated but nothing appears on screen.
Looks like your ng-model is not correct. Try this.
<select name="chooseInput" class="form-control" ng-model="machineProfile.input" ng-change="awesome(machineProfile.input)" ng-options="machine.input for machine in machineInputs track by machine.input"></select>

Categories

Resources