I want to make this code fit the DRY principle, I see that I repeat myself, but there must be a way to shorten this code into something less WET. The goal is to make a function that plays a sound when hovering over a card, it works, but as of now the code is WET.
<header id="play_1">
<audio>
<source src="/voices/sound1"></source>
</audio>
</header>
<header id="play_2">
<audio>
<source src="/voices/sound2"></source>
</audio>
</header>
<header id="play_3">
<audio>
<source src="/voices/sound3"></source>
</audio>
</header>
window.onload=function(){
var playHover = document.getElementById('play_1'),
audios = document.querySelectorAll('audio');
console.log(audios);
playHover.addEventListener('mouseover', function() {
[].forEach.call(audios, function(audio) {
audio.play();
});
}, false);
var playHover2 = document.getElementById('play_2'),
audios = document.querySelectorAll('audio');
console.log(audios);
playHover2.addEventListener('mouseover', function() {
[].forEach.call(audios, function(audio) {
audio.play();
});
}, false);
var playHover3 = document.getElementById('play_3'),
audios = document.querySelectorAll('audio');
console.log(audios);
playHover3.addEventListener('mouseover', function() {
[].forEach.call(audios, function(audio) {
audio.play();
});
}, false);
}
I tried making a for loop to put in the id's number, but I failed to make it work I inspired the for loop mostly from someone else having a similar dry problem here
window.onload=function(){
for ( var i = 1; i < 4; i ) window.onload();
var playHover = document.getElementById('play_' i),
audios = document.querySelectorAll('audio');
console.log(audios);
playHover.addEventListener('mouseover', function() {
[].forEach.call(audios, function(audio) {
audio.play();
});
}, false);
}
CodePudding user response:
Skip declaring it as a variable:
for (let i = 1; i < 3; i ) {
document.getElementById('play_ ' i),
audios = document.querySelectorAll('audio').addEventListener('mouseover', function() {
[].forEach.call(document.querySelectorAll('audio'), function(audio) {
audio.play();
});
}, false)
}
CodePudding user response:
Unfortunately, because I don't have any obvious access to an audio-streaming service (that allows their content to be streamed freely) I can't offer you much of a demo.
However the I'd suggest the following revisions to your code, based on the following observations:
- the DOM of each element you're working with has the same structure as all the others,
- you're effectively doing the same thing in each instance,
- it's not necessary to bind an event-handler using the
id
property, and - variables can be instantiated inside of functions as they're needed.
With that in mind I suggest the following JavaScript (explanatory comments are in the code):
// here we're using an alternative EventTarget.addEventListener() to bind the
// event-handling once the window, and contents, have loaded and are ready:
// the empty parentheses are used because we're not passing any arguments to
// the enclosed function; using EventTarget.addEventListener() makes the
// Event Object available automatically, but we don't need to use that
// in this instance:
window.addEventListener('DOMContentLoaded', () => {
// defining the named function to be bound as the event-handler; in this
// function we pass in a reference to the Event Object passed by
// EventTarget.addEventListener():
const playAudio = (evt) => {
// from the Event Object we retrieve the <header> element to which
// the function was bound, and triggered:
let currentHeader = evt.currentTarget,
// from the <header> we use Element.querySelector() to find
// the first (if any) <audio> element descendant:
currentAudio = currentHeader.querySelector('audio'),
// finding all <audio> elements in the document (since the way
// I read your code it seemed like you were playing all <audio>
// elements, but I imagine I was wrong:
allAudios = document.querySelectorAll('audio');
// if you want to play just the <audio> element from the <header>
// that your user is hovering over:
currentAudio.play();
// if, instead, you do want to play all <audios> then we can
// iterate over the NodeList of <audio> elements using
// NodeList.prototype.forEach():
allAudios.forEach(
// passing in a reference the current <audio> element, and
// calling its play() method:
(audioElement) => audioElement.play()
);
};
// using document.querySelectorAll() to retrieve all <header> elements:
document.querySelectorAll('header')
// using NodeList.prototype.forEach() to iterate over that NodeList:
.forEach(
// passing a reference to the current <header> of the NodeList to
// the Arrow function; and within the function binding the
// playAudio() function (note the deliberate lack of parentheses)
// as the event-handler for the 'mouseover' event:
(headerElement) => headerElement.addEventListener('mouseover', playAudio))
});
<header id="play_1">
<audio>
<source src="/voices/sound1">
</audio>
</header>
<header id="play_2">
<audio>
<source src="/voices/sound2">
</audio>
</header>
<header id="play_3">
<audio>
<source src="/voices/sound3">
</audio>
</header>
References: