woocommerce quantity field does not work properly - javascript

I am creating a shopping cart page and the quantity part, of all inputs only one of the inputs works and it's value changes
where am i doing wrong??
$('.minus').attr('id', 'minus');
$('.plus').attr('id', 'plus');
const minus = document.getElementById('minus')
const plus = document.getElementById('plus')
plus.addEventListener("click", () => {
var count = document.querySelector('[title="Qty"]').value;
count++;
document.querySelector('[title="Qty"]').value = count;
});
minus.addEventListener("click", () => {
var count = document.querySelector('[title="Qty"]').value;
if(count >1){
count--;
document.querySelector('[title="Qty"]').value = count;
}
});
<div class="padding-td">
<button class="btn border text-danger minus"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash" viewBox="0 0 16 16">
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
</svg>
</button>
<input type="number" title="Qty" value="<?php echo $cart_item["quantity"]?>" min="1" class="form-control w-25 d-inline-block input">
<button class="btn border text-danger plus"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus" viewBox="0 0 16 16">
<path d="M8 4a.5.5 0 0 1 .5.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 8 4z"/>
</svg>
</button>
</div>

Related

How can I make this React code shorter? I feel like I'm repeating myself

Hi I know there is a way to make this code shorter. I'm repeating myself and it's practically the same. It's supposed to be the profile page where I show my picture, and social media:
const Profile = () => {
return (
<div className="profile">
<div className="img-profile">
<img src="https://avatars.githubusercontent.com/u/65257680?v=4" alt="" class="img-fluid"></img>
</div>
<div className="flexbox-perfil">
<a href="https://www.linkedin.com/in/paulasierra7/" className="me-3">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" className="bi bi-linkedin" viewBox="0 0 16 16">
<path d="M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854V1.146zm4.943 12.248V6.169H2.542v7.225h2.401zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248-.822 0-1.359.54-1.359 1.248 0 .694.521 1.248 1.327 1.248h.016zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016a5.54 5.54 0 0 1 .016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225h2.4z"/>
</svg>
</a>
<a href="https://github.com/paulasierra7/proyecto_react" className="me-3">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" className="bi bi-github" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
</svg>
</a>
<a href="https://www.instagram.com/paulasierra7/">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" className="bi bi-instagram" viewBox="0 0 16 16">
<path d="M8 0C5.829 0 5.556.01 4.703.048 3.85.088 3.269.222 2.76.42a3.917 3.917 0 0 0-1.417.923A3.927 3.927 0 0 0 .42 2.76C.222 3.268.087 3.85.048 4.7.01 5.555 0 5.827 0 8.001c0 2.172.01 2.444.048 3.297.04.852.174 1.433.372 1.942.205.526.478.972.923 1.417.444.445.89.719 1.416.923.51.198 1.09.333 1.942.372C5.555 15.99 5.827 16 8 16s2.444-.01 3.298-.048c.851-.04 1.434-.174 1.943-.372a3.916 3.916 0 0 0 1.416-.923c.445-.445.718-.891.923-1.417.197-.509.332-1.09.372-1.942C15.99 10.445 16 10.173 16 8s-.01-2.445-.048-3.299c-.04-.851-.175-1.433-.372-1.941a3.926 3.926 0 0 0-.923-1.417A3.911 3.911 0 0 0 13.24.42c-.51-.198-1.092-.333-1.943-.372C10.443.01 10.172 0 7.998 0h.003zm-.717 1.442h.718c2.136 0 2.389.007 3.232.046.78.035 1.204.166 1.486.275.373.145.64.319.92.599.28.28.453.546.598.92.11.281.24.705.275 1.485.039.843.047 1.096.047 3.231s-.008 2.389-.047 3.232c-.035.78-.166 1.203-.275 1.485a2.47 2.47 0 0 1-.599.919c-.28.28-.546.453-.92.598-.28.11-.704.24-1.485.276-.843.038-1.096.047-3.232.047s-2.39-.009-3.233-.047c-.78-.036-1.203-.166-1.485-.276a2.478 2.478 0 0 1-.92-.598 2.48 2.48 0 0 1-.6-.92c-.109-.281-.24-.705-.275-1.485-.038-.843-.046-1.096-.046-3.233 0-2.136.008-2.388.046-3.231.036-.78.166-1.204.276-1.486.145-.373.319-.64.599-.92.28-.28.546-.453.92-.598.282-.11.705-.24 1.485-.276.738-.034 1.024-.044 2.515-.045v.002zm4.988 1.328a.96.96 0 1 0 0 1.92.96.96 0 0 0 0-1.92zm-4.27 1.122a4.109 4.109 0 1 0 0 8.217 4.109 4.109 0 0 0 0-8.217zm0 1.441a2.667 2.667 0 1 1 0 5.334 2.667 2.667 0 0 1 0-5.334z"/>
</svg>
</a>
</div>
</div>
)
}
export default Profile
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Thanks!!
You can make a component that has an anchor element on top of an svg, since you have repeated this multiple times. Make a component like this:
const ClickableSvg = ({link, svg}) => {
return (
<>
<a href={link.url}>{link.text}</a>
{svg}
</>)
}
Then you could do something like this:
const Profile = () => {
const data = [...] //this contains objects with a link and svg.
return (
<div className="profile">
<div className="img-profile">
<img src="https://avatars.githubusercontent.com/u/65257680?v=4" alt="" class="img-fluid"></img>
</div>
<div className="flexbox-perfil">
{data.map((d)=> <ClickableSvg link={d.link} svg={d.svg} />)}
</div>
</div>
)
}
export default Profile
Where data in the code above is an array of objects that contain a link and svg property.

SortableJS Next and Previous Buttons don't call OnEnd function

I use the SortableJS library (SortableJS/Sortable) to reorder pictures. I placed buttons: Next and Previous on each pictures to facilitate movement in desktop mode.
The buttons work well but the problem is that the SortableJS: OnEnd function (which manages the processing of the indexes: oldIndex and newIndex) is not executed.
How can I make my buttons work so that sortableJS can get the new indexes to organize the photos?
Here is my code
<div class="pictures">
<div class="picture-item">
<img src="...mypicture.jpg...">
<div class="btn-nav">
<button type="button" class="sort-prev">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="arrow-left-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-4.5-.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5z"/>
</svg>
</button>
<button type="button" class="sort-next">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="arrow-right-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H4.5z"/>
</svg>
</button>
</div>
</div>
...
</div>
// Array populated from dropzoneJS upload
var pictures = [{filename:test.jpg, position:0},{filename:test2.jpg, position:1}, ...]
var sortable = new Sortable(document.getElementById('pictures'), {
onEnd:function(evt)
{
// Function work with drag and drop not button click !
console.log(pictures);
let oldIndex = evt.oldIndex,
newIndex = evt.newIndex;
pictures.splice(newIndex, 0, pictures.splice(oldIndex, 1)[0]);
pictures.forEach((picture, index) => picture.position = index);
updateHiddenField(pictures);
}
});
$(document).on('click', '.sort-prev', function(){
var current = $(this).closest('.picture-item');
current.prev().before(current);
});
$(document).on('click', '.sort-next', function(){
var current = $(this).closest('.picture-item');
current.next().after(current);
});

Data not showing from web api to React in front-end

I'm trying to fetch data from webapi to display in react js tables, everything seems to work fine only text is not being displayed in these table the look empty[!
What might be the problem here, because I can't figure it out for days.
Image of Table
this is the error Im getting in console
This is my Department.js file
import React,{Component} from 'react';
import { Table } from 'react-bootstrap';
import { ModalBody, ModalTitle } from 'react-bootstrap';
import { variables } from './variables';
export class Department extends Component{
constructor(props){
super(props);
this.state={
departments:[],
modalTitle:"",
DepartmentName:"",
DepartmentId:0,
DepartmentIdFilter:"",
DepartmentNameFilter:"",
departmentsWithoutFilter:[]
}
}
FilterFn(){
var DepartmentIdFilter=this.state.DepartmentIdFilter;
var DepartmentNameFilter = this.state.DepartmentNameFilter;
var filteredData=this.state.departmentsWithoutFilter.filter(
function(el){
return el.DepartmentId.toString().toLowerCase().includes(
DepartmentIdFilter.toString().trim().toLowerCase()
)&&
el.DepartmentName.toString().toLowerCase().includes(
DepartmentNameFilter.toString().trim().toLowerCase()
)
}
);
this.setState({departments:filteredData});
}
sortResult(prop,asc){
var sortedData=this.state.departmentsWithoutFilter.sort(function(a,b){
if(asc){
return (a[prop]>b[prop])?1:((a[prop]<b[prop])?-1:0);
}
else{
return (b[prop]>a[prop])?1:((b[prop]<a[prop])?-1:0);
}
});
this.setState({departments:sortedData});
}
changeDepartmentIdFilter = (e)=>{
this.state.DepartmentIdFilter=e.target.value;
this.FilterFn();
}
changeDepartmentNameFilter = (e)=>{
this.state.DepartmentNameFilter=e.target.value;
this.FilterFn();
}
refreshList(){
fetch(variables.API_URL+'departments')
.then(response=>response.json())
.then(data=>{
this.setState({departments:data,departmentsWithoutFilter:data});
});
}
componentDidMount(){
this.refreshList();
}
changeDepartmentName =(e)=>{
this.setState({DepartmentName:e.target.value});
}
addClick(){
this.setState({
modalTitle:"Add Department",
DepartmentId:0,
DepartmentName:""
});
}
editClick(dep){
this.setState({
modalTitle:"Edit Department",
DepartmentId:dep.DepartmentId,
DepartmentName:dep.DepartmentName
});
}
createClick(){
fetch(variables.API_URL+'departments',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
DepartmentName:this.state.DepartmentName
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
updateClick(){
fetch(variables.API_URL+'departments',{
method:'PUT',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
},
body:JSON.stringify({
DepartmentId:this.state.DepartmentId,
DepartmentName:this.state.DepartmentName
})
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
deleteClick(id){
if(window.confirm('Are you sure?')){
fetch(variables.API_URL+'departments/'+ id,{
mode:'no-cors',
method:'DELETE',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then(res=>res.json())
.then((result)=>{
alert(result);
this.refreshList();
},(error)=>{
alert('Failed');
})
}
}
render(){
const {
departments,
modalTitle,
DepartmentId,
DepartmentName
}=this.state;
return(
<div>
<button type="button"
className="btn btn-primary m-2 float-end"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
onClick={()=>this.addClick()}>
Add Department
</button>
<table className="table table-striped">
<thead>
<tr key={Department.id}>
<th>
<div className="d-flex flex-row">
<input className="form-control m-2"
onChange={this.changeDepartmentIdFilter}
placeholder="Filter"/>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentId',true)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-down-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.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5a.5.5 0 0 1 1 0z"/>
</svg>
</button>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentId',false)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-up-square-fill" viewBox="0 0 16 16">
<path d="M2 16a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2zm6.5-4.5V5.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 5.707V11.5a.5.5 0 0 0 1 0z"/>
</svg>
</button>
</div>
DepartmentId
</th>
<th>
<div className="d-flex flex-row">
<input className="form-control m-2"
onChange={this.changeDepartmentNameFilter}
placeholder="Filter"/>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentName',true)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-down-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.5v5.793l2.146-2.147a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-3-3a.5.5 0 1 1 .708-.708L7.5 10.293V4.5a.5.5 0 0 1 1 0z"/>
</svg>
</button>
<button type="button" className="btn btn-light"
onClick={()=>this.sortResult('DepartmentName',false)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-arrow-up-square-fill" viewBox="0 0 16 16">
<path d="M2 16a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2zm6.5-4.5V5.707l2.146 2.147a.5.5 0 0 0 .708-.708l-3-3a.5.5 0 0 0-.708 0l-3 3a.5.5 0 1 0 .708.708L7.5 5.707V11.5a.5.5 0 0 0 1 0z"/>
</svg>
</button>
</div>
DepartmentName
</th>
<th>
Options
</th>
</tr>
</thead>
<tbody>
{departments.map(dep=>
<tr key={dep.DepartmentId}>
<td>{dep.DepartmentId}</td>
<td>{dep.DepartmentName}</td>
<td>
<button type="button"
className="btn btn-light mr-1"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
onClick={()=>this.editClick(dep)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-pencil-square" viewBox="0 0 16 16">
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
<path fillRule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
</svg>
</button>
<button type="button"
className="btn btn-light mr-1"
onClick={()=>this.deleteClick(dep.DepartmentId)}>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="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>
</button>
</td>
</tr>
)}
</tbody>
</table>
<div className="modal fade" id="exampleModal" tabIndex="-1" aria-hidden="true">
<div className="modal-dialog modal-lg modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{modalTitle}</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"
></button>
</div>
<div className="modal-body">
<div className="input-group mb-3">
<span className="input-group-text">DepartmentName</span>
<input type="text" className="form-control"
value={DepartmentName}
onChange={this.changeDepartmentName}/>
</div>
{DepartmentId===0?
<button type="button"
className="btn btn-primary float-start"
onClick={()=>this.createClick()}
>Create</button>
:null}
{DepartmentId!==0?
<button type="button"
className="btn btn-primary float-start"
onClick={()=>this.updateClick()}
>Update</button>
:null}
</div>
</div>
</div>
</div>
</div>
)
}
}```
This is my Program.cs
using Microsoft.EntityFrameworkCore;
using WebApp.Data;
var myAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
//Enable CORS
builder.Services.AddCors(options =>
{
options.AddPolicy(name: myAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors(myAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
What might be the problem here, because I can't figure it out for days.
Does anyone had the same issue?
It looks like I have done something wrong in react js file

Multiple Audio Players on one page, only first player responds to click

I took the audio player code from this article, made a few style changes, and am now attempting to display multiple such players on one page. Currently, only the first player responds to clicks.
I used row and column elements to display full-page rows with 3 players per row, each player having its own icon image and audio source file. My trouble is now in establishing the index-searching procedure so that the JS can play audio_X when button_X is clicked.
I've tried other solutions on StackOverflow to no avail, so I've removed all the changes I tried and am starting again from square one.
const playerButton = document.querySelector('.player-button'),
audio = document.querySelector('audio'),
playIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</svg>
`,
pauseIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
`;
function toggleAudio() {
if (audio.paused) {
audio.play();
playerButton.innerHTML = pauseIcon;
// document.getElementById("1").style.opacity = "1";
} else {
audio.pause();
playerButton.innerHTML = playIcon;
// document.getElementById("1").style.opacity = "0";
}
}
playerButton.addEventListener('click', toggleAudio);
function audioEnded() {
playerButton.innerHTML = playIcon;
}
audio.onended = audioEnded;
const timeline = document.querySelector('.timeline');
function changeTimelinePosition() {
const percentagePosition = (100 * audio.currentTime) / audio.duration;
timeline.style.backgroundSize = `${percentagePosition}% 100%`;
timeline.value = percentagePosition;
}
audio.ontimeupdate = changeTimelinePosition;
function changeSeek() {
const time = (timeline.value * audio.duration) / 100;
audio.currentTime = time;
}
timeline.addEventListener('change', changeSeek);
const soundButton = document.querySelector('.sound-button'),
soundIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
</svg>`,
muteIcon = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>`;
function toggleSound() {
audio.muted = !audio.muted;
soundButton.innerHTML = audio.muted ? muteIcon : soundIcon;
}
soundButton.addEventListener('click', toggleSound);
<div class="audio-player left">
<div class="icon-container">
<img src="coverart1.jpg" style="width: 100%" alt="">
<!--<svg xmlns="http://www.w3.org/2000/svg" class="audio-icon" viewBox="0 0 20 20" fill="currentColor">
<path d="blahblahblahpath" />
</svg>-->
<audio src="audio/1.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="blahblahblahpath" />
</svg>
</button>
<input type="range" class="timeline" max="100" value="0">
<button class="sound-button">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
<path fill-rule="evenodd" d="blahblahblahpath" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
With this structure, I'm not quite sure how to index/search for specific players (beyond knowing that i should probably use queryselectALL and add for loops to some JS functions).
Any fixes? Currently the first player works perfectly, but no other player responds to clicks. Something with the event listener perhaps?
beyond knowing that i should probably use queryselectALL and add for loops to some JS functions
That's the point: you'll need to assign event listeners to each player instance.
let audioPlayers = document.querySelectorAll(".audio-player");
if (audioPlayers.length) {
audioPlayers.forEach(function(audioPlayer, i) {
let audio = audioPlayer.querySelector("audio");
let playerButton = audioPlayer.querySelector(".player-button");
playerButton.addEventListener("click", function(e) {
let current = e.currentTarget;
let audio = current.closest(".audio-player").querySelector("audio");
let btnSvg = current.querySelector(".useBtn");
if (!audio.paused) {
btnSvg.setAttribute("href", "#icon-play");
audio.pause();
} else {
btnSvg.setAttribute("href", "#icon-pause");
audio.play();
}
});
let timeline = audioPlayer.querySelector('.timeline');
timeline.addEventListener('change', function(e) {
let time = (timeline.value * audio.duration) / 100;
audio.currentTime = time;
});
audio.addEventListener('ended', function(e) {
console.log('audio finished');
timeline.value = 0;
});
audio.addEventListener('timeupdate', function(e) {
let percentagePosition = (100 * audio.currentTime) / audio.duration;
timeline.value = percentagePosition;
});
});
}
svg {
display: block;
width: 1em;
}
.player-button {
display: inline-block;
height: 1em;
background: none;
padding: 0;
border: none;
font-size: 1.2em;
position: relative;
bottom: -0.15em;
}
<div class="audio-player left">
<div class="icon-container">
<audio preload="metadata" src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg viewBox="0 0 20 20" fill="#3D3132">
<use class="useBtn" href="#icon-play" />
</svg>
</button>
<input type="range" class="timeline" min="0" max="100" step="1" value="0">
</div>
</div>
<div class="audio-player left">
<div class="icon-container">
<audio preload="metadata" src="https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3"></audio>
</div>
<div class="controls">
<button class="player-button">
<svg viewBox="0 0 20 20" fill="#3D3132">
<use class="useBtn" href="#icon-play" />
</svg>
</button>
<input type="range" class="timeline" min="0" max="100" step="1" value="0">
</div>
</div>
<svg class="plyrBtns" style="display:none" aria-hidden="true">
<symbol class="icon icon-play" id="icon-play" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</symbol>
<symbol class="icon icon-pause" id="icon-pause" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</symbol>
</svg>

Add tooltip via JavaScript in Bootstrap 5

How do add a tooltip in Bootstrap v5 via Javascript? I'm tying to add a tooltip and popover to the same element and it seems the best route is to enable both them via JS.
The tooltip added via html works as expected:
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.bundle.min.js"></script>
<span class="input-group-text mb-3" id="basic-addon2" title="If you want us">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
</span>
Next I tried to add the tooltip via JS:
var options =
{
title : "If you want us",
};
var responseTeamMemberSpanElm = document.getElementById("basic-addon2");
var tooltipResponseTeamMember = new bootstrap.Tooltip(responseTeamMemberSpanElm,options );
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.bundle.min.js"></script>
<span class="input-group-text mb-3" id="basic-addon2" >
<!-- info icon with circle around: from https://icons.getbootstrap.com/icons/info-circle/ -->
<svg "basic-addon2-svg" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
</svg>
</span>
The look of the tooltip looks different. Also, I can put my cursor on the grey background, the tooltip works as expected but when I hover over the circle "i", the tooltip stops working. After I hover over the circle "i", I see the tooltip get moved to the bottom of the screen and the tooltip doesn't work even if I hover elsewhere and come back to the background.
All the older answers I found are using the JQuery version of bootstrap.
Is this a bug or am I doing something wrong?
If you define css propertry pointer-events: none; in all child of tooltip element then its working fine but this may be create a problems on click, hover, focus and other events listener.
So re-initialize tooltip method when hide tooltip by hide.bs.tooltip method in Bootstrap-v5.
Source: https://getbootstrap.com/docs/5.0/components/tooltips/#events
Try below snippet.
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
this.addEventListener('hide.bs.tooltip', function () {
new bootstrap.Tooltip(tooltipTriggerEl)
})
return new bootstrap.Tooltip(tooltipTriggerEl)
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12">
<span class="input-group-text border position-relative" id="basic-addon2" data-bs-toggle="tooltip" data-bs-placement="top" title="If you want us">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle"
viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path
d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
</svg>
</span>
</div>
<div class="col-sm-12 my-3">
<span class="input-group-text border position-relative" id="basic-addon3" data-bs-toggle="tooltip" data-bs-placement="top" title="If you want us">
<input type="text" class="form-control me-2" placeholder="First Name">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle"
viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path
d="M8.93 6.588l-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
</svg>
</span>
</div>
</div>
</div>

Categories

Resources