Why js text to speech not taking more charachters? - javascript

Here i am using js text to speech with SpeechSynthesis and its working fine with limited amount of words/sentences, but the time i add all my blog paragraph which is more then 2-3k words its not working, its converting till some part and automatically being stop. So how can i add unlimited no of words or total page content converted to speech.
NOTE: I tried js speak() also, which worked fine but i want a pause/stop option so i used this. So if there any other working way then please suggest.
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"],[name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');
msg.text = document.querySelector('[name="text"]').value;
function populateVoices() {
voices = this.getVoices();
voicesDropdown.innerHTML = voices.map(voice => `<option value="${voice.name}">${voice.name}(${voice.lang})</option>`).join('');
}
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
function toggle(startOver = true) { //true is for it will not stop if language changes
speechSynthesis.cancel();
if (startOver) {
speechSynthesis.speak(msg);
}
}
function setOption() {
// console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}
speechSynthesis.addEventListener('voiceschanged', populateVoices);
voicesDropdown.addEventListener('change', setVoice);
options.forEach(option => option.addEventListener('change', setOption));
speakButton.addEventListener('click', toggle);
<div class="voiceinator">
<select name="voice" id="voices">
<option value="">Select a voice</option>
</select>
<label for="rate">Rate:</label>
<input type="range" name="rate" min="0" max="3" value="1" step="0.1">
<label for="pitch">Pitch:</label>
<input type="range" name="pitch" min="0" max="2" value="1" step="0.1">
<textarea name="text"></textarea>
<button id="stop">Stop!</button>
<button id="speak">Speak</button>
</div>

It's a known bug. The workaround is to issue a resume every 14 seconds.
You can add this immediately after the line speechSynthesis.speak(msg):
let r = setInterval(() => {
console.log(speechSynthesis.speaking);
if (!speechSynthesis.speaking) {
clearInterval(r);
} else {
speechSynthesis.resume();
}
}, 14000);

Related

How can I add an value to an input type

How can I add an value to an input type.
I'm currently working on a converter for meter to kilometer, to mile, ...
I've created different input types in my HTML Code and took the value of them in JS, which worked completely fine, and I prevented the page from reloading after I click submit. Now I want to reassign the new, calculated value (kilometer.value = meter / 1000), but this doesn't work.
It works completely fine, when I'm putting an console.log after the variable meter and the first variable kilometer. It logs the correct number - the reassignment just doesn't work.
JavaScript:
const calculateMeter = () => {
let meter = document.getElementById("meter").value;
let kilometer = document.getElementById("kilometer").value;
kilometer.value = meter / 1000;
}
HTML:
<form id="calculator" onsubmit="calculateMeter(); return false">
<label for="kilometer">Kilometer:</label>
<input type="number" id="kilometer"><br>
<label for="meter">Meter:</label>
<input type="number" id="meter"><br>
value of <input> is always a string, but in case of numerical input types, like type="number", or type="range", you can get the number directly using valueAsNumber:
const calculateMeter = () => {
let kilometer = document.getElementById("kilometer").valueAsNumber;
document.getElementById("meter").value = kilometer * 1000;
}
const calculateKilometer = () => {
let meter = document.getElementById("meter").valueAsNumber;
document.getElementById("kilometer").value = meter / 1000;
}
<label for="kilometer">Kilometer:</label>
<input type="number" id="kilometer" oninput="calculateMeter()"><br>
<label for="meter">Meter:</label>
<input type="number" id="meter" oninput="calculateKilometer()"><br>
Did you mean something like, that?
let meterInp = document.getElementById("meter");
let kilometerInp = document.getElementById("kilometer");
meterInp.addEventListener("change", ()=>{
kilometerInp.value = (+meterInp.value)/1000;
});
kilometerInp.addEventListener("change", ()=>{
meterInp.value = (+kilometerInp.value)*1000;
});
<form id="calculator" onsubmit="calculateMeter(); return false">
<label for="kilometer">Kilometer:</label>
<input type="number" id="kilometer" step="0.00001"><br>
<label for="meter">Meter:</label>
<input type="number" step="0.01" id="meter"><br>
</form>
The (+) converts string to number.
for e.g. (+meterInp.value)/1000
You should convert meter to intiger
const calculateMeter = () => {
let meter = document.getElementById("meter").value;
let kilometer = document.getElementById("kilometer").value;
kilometer.value = Number(meter) / 1000;
}

How to automatically select checkboxes if user input in "wall_amount" exceeds 3

I would like my program to automatically select all checkboxes (Specifically "Side 1, Side 2, Side 3 and Side 4") if the wall_amount input is above 3. How would this be done?
I have tried this on javascript lines 10-12. Thanks
HTML
<label for="wall_amount">Number of Walls</label>
<input type="number" value="1" min="1" max="4" step="1" id="wall_amount" name="wall_amount"></input>
<div>
Please choose where you want the walls placed
<label for="wall_side1">Side 1</label>
<input type="checkbox" id="wall_side1" name="wall_side1"></input>
<div style="display: inlineblock;">
<label for="wall_side2">Side 2</label>
<input type="checkbox" id="wall_side2" name="wall_side2"></input>
<img class="img2" src="images/reference.png" alt="Bouncy Castle">
<label for="wall_side3">Side 3</label>
<input type="checkbox" id="wall_side3" name="wall_side3"></input>
</div>
<label for="wall_side4">Side 4</label>
<input type="checkbox" id="wall_side4" name="wall_side4"></input>
</div>
Javascript
var base_length = Number(document.getElementById("base_length").value);
var base_width = Number(document.getElementById("base_width").value);
var walltype = Number(document.getElementById("walltype").value);
var checkbox_side1 = document.getElementById("wall_side1");
var checkbox_side2 = document.getElementById("wall_side2");
var checkbox_side3 = document.getElementById("wall_side3");
var checkbox_side4 = document.getElementById("wall_side4");
var wall_amount = Number(document.getElementById("wall_amount").value);
$("input:checkbox").click(function() {
let max = $("#wall_amount").val();
var bol = $("input:checkbox:checked").length >= max;
$("input:checkbox").not(":checked").attr("disabled", bol);
});
$("wall_amount").on('keyup', function () {
$('checkbox_side1').prop('checked', +$(this).val() > 3);
});
You can use the function setAttribute to check checkboxes. For example, this code (based on your example) will check your element with the id wall_side1.
checkbox_side1.setAttribute("checked", true)
Anyway, try adding this to your code as a function. Then add a conditional statement that runs the function every time your variable exceeds a certain amount.
I am still relatively new at answering questions so I hope this helps!
const checkboxes = [
"wall_side1",
"wall_side2",
"wall_side3",
"wall_side4"
].map((id) => document.getElementById(id));
const amountInput = document.getElementById("wall_amount");
amountInput.addEventListener("change", (event) => {
const value = parseInt(event.target.value || 0);
if (value === 4) {
checkboxes.forEach(
checkbox => {
checkbox.disabled = true;
checkbox.checked = true;
}
);
} else {
checkboxes.forEach(
checkbox => {
checkbox.disabled = false;
}
);
}
});

How to properly track keys with DOM

I'm doing a web calculator, I need to track when when the user type a number key, but this calculator also has two input type="number" to define the range that the numbers will be generated.
let from = document.querySelector("#from")
let to = document.querySelector("#to")
let regex = /[\d]/
from.addEventListener("focus", () => {
console.log('focus')
});
document.onkeypress = function(evt) {
if (evt.key.match(regex)) {
alert(evt.key);
} else if (evt.key == 'Enter') {
alert(evt.key)
};
};
<div class="range">
<span>Range: from </span>
<input type="number" id="from" value="0">
<span>to</span>
<input type="number" id="to" value="100">
</div>
How I can stop tracking the keys only when the user is typing on the input field?
the solution is to check if document.activeElement is equals to the element that you want to check.
document.onkeypress = function(evt) {
if (from === document.activeElement) {
console.log("jaisokdjhaslkdhjsa")
} else {
if (evt.key.match(regex)) {
alert(evt.key);
} else if (evt.key == 'Enter') {
alert(evt.key)
};
}
};

Elements not showing up in array after pushing

I want to add books to a library. After entering info to input and submitting the books array stay empty. I'll post pictures so you can understand better. Also sorry for messy code. I'll clean up after getting it to work.
console.log after adding a book
const books = [];
const submitBook = () => {
const bookName = document.querySelector('#title').value;
const bookAuthor = document.querySelector('#author').value;
const bookYear = document.querySelector('#year').value;
// let book = new Book(bookName.value, bookAuthor.value, bookYear.value);
books.push({
'name':bookName,
'author':bookAuthor,
'year':bookYear
});
alert("Book added.");
}
<label for="title">Title:</label><br>
<input type="text" id="title" name="title" required><br>
<label for="author">Author:</label><br>
<input type="text" id="author" name="author" required><br>
<label for="year">Year:</label><br>
<input type="number" id="year" name="year" required><br>
<button onclick="submitBook()">Add book</button>
Your code seems to work. I've taken the liberty to simplify you code somewhat. It is generally not a good idea to use inline event handling (onclick=... within html), so moved the handler to the code section. Also added a button to show added books.
let books = [];
let to = null;
const clearAfter = (delay = 2) => setTimeout(() => console.clear(), delay * 1000);
const format = obj => JSON.stringify(obj).split("},{").join("},\n{");
const submitBook = () => {
let book = {};
document.querySelectorAll("input")
.forEach(inp => book[inp.name] = inp.value);
books.push(book);
console.clear();
// console.log here to see the result immediately,
// otherwise there may not be any result yet
console.log(`Added:\n${format(book)}`);
}
document.addEventListener("click", evt => {
if (evt.target.id === "addbook") {
submitBook();
} else if (evt.target.id === "showbooks") {
console.clear();
console.log(`${books.length || "No"} added books\n${
books.length < 1 ? "-" : format(books)}`);
}
// remove the log (to make buttons visible again in the SO-run window)
clearTimeout(to);
to = clearAfter();
});
<label for="title">Title:</label><br>
<input type="text" id="title" name="title" required><br>
<label for="author">Author:</label><br>
<input type="text" id="author" name="author" required><br>
<label for="year">Year:</label><br>
<input type="number" id="year" name="year" required><br>
<p>
<button id="addbook">Add book</button>
<button id="showbooks">Show books added</button>
</p>

How to create an event handler for a range slider?

I'm trying to get a range slider to work but I can't.
How do I add an event handler so when the user chooses a value my code reads that value. Right now its value is always 1.
I would like to do this using pure Javascript.
HTML:
<div id="slider">
<input class="bar" type="range" id="rangeinput" min="1" max="25" value="1" onchange="rangevalue.value=value"/>
<span class="highlight"></span>
<output id="rangevalue">1</output>
</div>
JAVASCRIPT:
var rangeInput = document.getElementById("rangeinput").value;
var buttonInput = document.getElementById("btn");
if (buttonInput.addEventListener) {
buttonInput.addEventListener("click", testtest, false);
}
else if (buttonInput.attachEvent) {
buttonInput.attachEvent('onclick', testtest);
}
function testtest(e) {
if (rangeInput > 0 && rangeInput < 5) {
alert("First");
} else {
alert("Second");
}
}
JSFIDDLE
Single Read
The problem is that you're only reading the value once (at startup), instead of reading it every time the event occurs:
// this stores the value at startup (which is why you're always getting 1)
var rangeInput = document.getElementById("rangeinput").value;
You should be reading the value in the handler instead:
function testtest(e) {
// read the value from the slider:
var value = document.getElementById("rangeinput").value;
// now compare:
if (value > 0 && value < 5) {
alert("First");
} else {
alert("Second");
}
}
Or to rewrite your code:
var rangeInput = document.getElementById("rangeinput");
var buttonInput = document.getElementById("btn");
if (buttonInput.addEventListener) {
buttonInput.addEventListener("click", testtest, false);
}
else if (buttonInput.attachEvent) {
buttonInput.attachEvent('onclick', testtest);
}
function testtest(e) {
var value = rangeInput.value;
if (value > 0 && value < 5) {
alert("First");
} else {
alert("Second");
}
}
Updating rangevalue
It also looks like you want to update the output element with the value of the range. What you're currently doing is referring to the element by id:
onchange="rangevalue.value=value"
However, as far as I know, this isn't standard behavior; you can't refer to elements by their id alone; you have to retrieve the element and then set the value via the DOM.
Might I suggest that you add a change listener via javascript:
rangeInput.addEventListener("change", function() {
document.getElementById("rangevalue").textContent = rangeInput.value;
}, false);
Of course, you'll have to update the code to use addEventListener or attachEvent depending on the browsers that you want to support; this is where JQuery really becomes helpful.
Use the mouseup event for that.
var rangeInput = document.getElementById("rangeinput");
rangeInput.addEventListener('mouseup', function() {
if (this.value > 0 && this.value < 5) {
alert("First");
} else{
alert("Second");
}
});
DEMO: http://jsfiddle.net/ZnYjY/1
You can also use the FORMs oninput method:
<form oninput="result.value=parseInt(a.value)+parseInt(b.value)">
<input type="range" name="b" value="50" />100 +
<input type="number" name="a" value="10" /> =
<output name="result"></output>
</form>
This has an advantage over onclick/onmouseup because it handles the case where the slider is moved using the keyboard (tab to the input and use the arrow keys)
Use the oninput event.
HTML Codes:
<div id="slider">
<input class="bar" type="range" id="range-input" min="1" max="25" value="1"/>
<span class="highlight"></span>
<output id="range-value">1</output>
</div>
<button id="btn" type="submit">Submit</button>
Javascript scripts
(function() {
var rangeInput = document.getElementById("range-input")
var rangeValue = document.getElementById("range-value")
var button = document.getElementById("btn")
// Show alert message when button clicked
button.onclick = testTest
function testTest() {
let value = rangeInput.value
if(value > 0 && value < 5) {
alert("first")
return true
}
alert("second")
return false
}
// Print the range value to the output
rangeInput.oninput = rangeOutput
function rangeOutput() {
rangeValue.innerText = rangeInput.value
}
})()
Demo
UPDATE 2021
Another option is to use the input event handler i.e. eventTarget.addEventListener("input", alert("Hello World"), though this event handler is the same with oninput, the difference having we can use addEventListener
<script type="text/javascript">
function range()
{
//the simplest way i found
var p = document.getElementById('weight');
var res = document.getElementById('rangeval');
res.innerHTML=p.value+ " Lbs";
}
</script>
<label for="weight">Your weight in lbs:</label>
<input name="weight" type="range" id="weight" max="500" min="0" value="75" onChange="range()" onKeyUp="range()">
<span id="rangeval"></span>

Categories