There is an object with keys whose values are text, and this text should appear in the placeholder of the search page on the site. The first key is written one letter at a time until the whole word is created, and then, one letter at a time, it is completely deleted, and the second key is written in the same way in placeholder. The dialing speed does not matter.
I am enclosing my work. Now the problem is that all the keys are written, but they must take turns, deleting the previous one by letter.
let types={
phrase1:"Words",
phrase2:"has been",
phrase3:"deleted",
};
function writer() {
let curr = 0;
let text = Object.values(types)
let elem = document.getElementsByClassName('topnav');
elem.textContent += text.charAt(curr);
curr++
if (curr < text.length )
window.setInterval(writer,60);
}
writer();
<div class="topnav">
<input type="text" placeholder=" ">
</div>
Solution
call setTimeout() because it will call the method once whereas setIntervall() will call it repetitive what doesn't make sense here because you will call it in your next function call again.
use recursion to get the next word of your array
Defined three cases here
current letter < wordsArray.length apply method on the same element of the array
When 1 is false and value < wordsArray apply method on the next array element writer(value+1)
1 and 2 are false then print out the content of the array as string
let types = {
phrase1: "Words",
phrase2: "has been",
phrase3: "deleted",
};
var curr = 0;
function writer(value) {
let inp = document.getElementById("text");
let wordArray = Object.values(types)
let sentence = wordArray[value];
inp.placeholder = sentence.charAt(curr);
curr++;
if (curr < sentence.length){
window.setTimeout(function() {
writer(value);
}, 500);
}else if(value < wordArray.length-1){
window.setTimeout(function() {
curr = 0;
inp.placeholder = " ";
writer(value+1);
}, 500)
}else {
inp.placeholder = wordArray.join().replaceAll(",", " ");
}
}
writer(0);
<div class="topnav">
<input id="text" type="text" placeholder=" ">
</div>
I've made a demo, from the very little you could piece together from your question. You really didn't specify anything... BUT I would like to add that the types variable should be an Array and not an Object which makes it much easier to work with. Nonetheless, I did work with your provided code:
const types = {
phrase1:"Words",
phrase2:"has been",
phrase3:"deleted",
}
const inputElm = document.querySelector('.topnav > input')
function iteratePlaceholder(place = 1) {
inputElm.placeholder = types[`phrase${place||1}`];
// call this function again only if "place" is less than the length of keys (3)
(place < Object.keys(types).length) && setTimeout(iteratePlaceholder, 500, ++place)
}
iteratePlaceholder()
<div class="topnav">
<input type="text" placeholder=" ">
</div>
Related
I am trying to update my html using regex and javascript. I can capture the group I intend, however nothing on the dom is changing the way I would expect.
I want to discover all currency mentions of AUD, I have a regex that is capturing that. I then need to change how it is displayed.
I used the .replace function, however it does not seem to change anything. It only seems to change it in the console.log.
10AUD
Help us all
<p> 20THB</p>
<p> There is 100USD, here</p>
<p>More random sentances that should not be evalued even with 500 numbers in it</p>
<p>Here I can write a bunch like I had 300THB in my pocket and a spare 50AUD note aswell</p>
Here is the js portion.
regAUD = RegExp(/([0-9]+(AUD))/gi);
function checker() {
str = document.getElementsByTagName('p');
//str = str.innerText;
for (i = 0; i < str.length; i++) {
str[i].id = String(i+"para");
console.log(str[i].innerText);
inner = str[i].innerText;
//Now make an if statement to if we go further
//res = isCurrency(inner); //This passes correctly
res = 1;
if(res === 1){
if(regAUD.test(inner)){
inner = inner.replace(regAUD, '<b>$1</b>');
console.log(inner);
console.log("Done?");
}
}
}
}
I assume I am using the function incorrectly. It does show up in the console but not in the elements expected. It doesn't change anything, ie I expect it to currently make 10AUD and 500AUD bold but it does not do this. Is there a better method to achieve this change in the DOM or have I used this function incorrectly?
You forget to affect your new HTML string to the concerned elements' own HTML.
Also, you could have a shorter function.
Here's one with two parameters:
selector to execute the highlight on wanted elements.
currency to highlight the wanted currency.
// Highlights "AUD" mentions winthin all <p> elements.
highlightCurrencyFromElement('p', 'aud');
function highlightCurrencyFromElement(selector, currency) {
const elements = document.querySelectorAll(selector),
pattern = new RegExp(`(\\d+\\s*${currency})`, 'gi');
for (let i = 0; i < elements.length; i++) {
elements[i].innerHTML = elements[i].innerHTML.replace(pattern, '<b>$1</b>');
}
}
<div>
<p>5</p>
<p>21 AUD</p>
</div>
<div>
<p>50AUD</p>
<p>50 €</p>
<p>87 USD</p>
<span>20 AUD (in span, so no highlighted)</span>
<div>
You have to set the paragraph innerHTML porperty after replacing regxmatch to replace in DOM.
regAUD = RegExp(/([0-9]+(AUD))/gi);
function checker() {
str = document.getElementsByTagName('p');
//str = str.innerText;
for (i = 0; i < str.length; i++) {
str[i].id = String(i+"para");
console.log(str[i].innerText);
inner = str[i].innerText;
//Now make an if statement to if we go further
//res = isCurrency(inner); //This passes correctly
res = 1;
if(res === 1){
if(regAUD.test(inner)){
inner = inner.replace(regAUD, '<b>$1</b>');
str[i].innerHTML= inner;
console.log(inner);
console.log("Done?");
}
}
}
}
I have a hopefully pretty easy problem. I'm trying to create a JS function on my app where there's a number in HTML and every time it is clicked, another number is subtracted from it and the result displays.
(So far this much works.)
Then the action should be repeatable so the number keeps getting smaller.
(This part doesn't work yet.)
Finally, there's a reset button that, when clicked, resets the original number to a random number.
(The random number is found correctly, but when you click to subtract it subtracts from the original number, not from the randomly-chosen replacement number.)
Here's a partially-working JSFiddle
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
var n = n - s;
document.getElementById("countdownNumber").onclick = function updateNumber(){
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
var n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>
Can anyone (1) double check what I've done to make sure I'm not doing things in a stupid way and (2) help me figure out how to get the repeatable action functioning?
The issue is you are calculating value of n only once, it should be calculated on every click thus change you countdown click function to:
document.getElementById("countdownNumber").onclick = function updateNumber(){
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
n = n - s;
this.innerHTML = n;
}
Here is a working demo:
https://jsfiddle.net/m3q8fn2x/
If you are still struggling with this ,then consider the fact that when you declare a variable inside an event function its starting value is always the same , when the event is triggered. So consider this fact and declare variables outside the event function's scope.
const togglerBtn = document.getElementById("togglerBtn");
let temp = false;
togglerBtn.addEventListener("click", () => {
// alert();
if (!temp) {
togglerDiv.style.transform = "translateY(48px)";
return (temp = true);
} else if (temp) {
togglerDiv.style.transform = "translateY(-500px)";
return (temp = false);
}
});
Here is your working code:
You need to put the n = n - s part into the update number function so its called each time you click.
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
document.getElementById("countdownNumber").onclick = function updateNumber() {
n = n - s;
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>
I have a small input field where this code gets activated everytime a key is pressed inside it. But it now only prints "found something" when the name exacly matches what you type in the input field.
How can change a part that when I type something like "b" it already removes the matches where there is no "b" in the name is and print every possible matches that still have a "b".
My small code to find the match.
Info is my json big array where I can loop through all the names with info[i].name
var textInput = $findperson.find('input').val();
console.log(textInput);
for (i = 1; i < info.length; i++) {
if (textInput === info[i].name) {
console.log('found something');
}
}
Set Flag if found any match and print them, otherwise print found nothing,
for gi g mean search globally and i mean ignore case sothat A will match a and vise verse.
var textInput = $findperson.find('input').val();
console.log(textInput);
found = false
for (i = 1; i < info.length; i++) {
if (info[i].name.match(new RegExp(textInput,"gi")) ) {
console.log(info[i].name);
found = true
}
}
if(!found){
console.log("found nothing")
}
I would use regex like this:
var textInput = $findperson.find('input').val();
var regex = new Regexp(".*("+textInput+").*","i");
var filtered = info.filter(function (current) {
return current.name.match(regex);
});
console.log(filtered);
Just use indexOf to search for one String within another:
if(info[i].name.indexOf(textInput) != -1) {
indexOf will return -1 if String isn't found within the other.
You can try searching for some letters in one of the results 'balloon', 'ball', 'apple' in the example below:
var results = ['balloon', 'ball', 'apple'];
function filterResults() {
var input = document.getElementById('input').value;
var resultsFiltered = results.filter(function(a) {
return a.indexOf(input) != -1;
});
var result = ''; resultsFiltered.map(function(a) {
result += a + '<br/>';
}); document.getElementById('result').innerHTML = result;
}
<input id='input' onkeyup='filterResults();'/>
<div id='result'></div>
I'm making a webapp that will search cards based on parameters given.
The problem lies on the fact that the cards have different types. For instance one card may have something like "income": 4, while another behaves completely different and has an attribute "cost" : 5. All i meant is that my JSON has 5 types of different objects, that although they share many similarities, they have certain distinctions.
So let's say that my user searches for a card based on the Title. All of them has this attribute, so it's fairly easy to make an condition like this.
if ((item.name.toLowerCase().indexOf(cardParams.searchTitle.toLowerCase()) > -1) && (cardParams.searchTitle != null ) && (cardParams
.searchTitle.length > 0)){
But what if my user wants to search the text in the body too? All of them the have one too, so this leads to another condition with starts making things awkward.
Furthermore, let's way that my user triggers my worst case scenario and asks for two attributes that no card has them at the same time along with the ones above. One would say that i should work on my form to make them mutually exclusive, but programmatically this is beyond me.
What i've decided to go for is to search for each attribute seperately and save the results all into an array. If i have as many duplicates of an card as many valid attributes (not null or empty), then i would keep them.
This is really really clumsy and not optimal. I'm sure there are very simple solutions that i can't think of.
How can i proceed such a problem? Is creating tons of conditions the only way to go? What should i do?
Edit: Thanks for the downvotes. It's like i ask for fun.
If you want to search across an object inside javascript, you can just loop over the properties, and access those for which the object.hasOwnProperty(propertyName) returns true
As an example, you see here a bunch of cards, with different properties, the search will however iterate over all of the properties of each card and will select a card that matches and then search for the next matching card.
At the end it will either show the results, or simply say there are no results found ;)
var cards = [{
title: 'Card 1',
prop1: 'Test of card1',
description: 'Description of card1',
customCard1: 'Custom property'
}, {
title: 'Card 2',
description: 'Description of card2',
customCard2: 'Custom property card2'
}];
function searchCards() {
var txt = document.getElementById('searchBox').value.toLowerCase(),
i, len, card, prop, matches = [],
val;
for (i = 0, len = cards.length; i < len; i++) {
card = cards[i];
for (prop in card) {
if (card.hasOwnProperty(prop)) {
val = card[prop];
if (typeof val !== 'undefined' && val.toLowerCase && val.toLowerCase().indexOf(txt) >= 0) {
// this card matches
matches.push(card);
break;
}
}
}
}
showMatches(matches);
}
function showMatches(matches) {
var elem = document.getElementById('result'),
i, len, content = '';
if (typeof matches === 'undefined' || !matches.length) {
elem.innerHTML = '<i>No results found</i>';
return;
}
for (i = 0, len = matches.length; i < len; i++) {
content += '<div><b>title:</b>' + matches[i].title + '</div>';
}
elem.innerHTML = content;
}
<input type="text" id="searchBox" />
<button type="button" onclick="javascript:searchCards()">Search</button>
<div id="result"></div>
Update based on the comments
If you have multiple input fields, you could give them an extra class to recognise them, and then let jQuery return you all the matching elements based on your selector (in my case, .search), and get the values that were given by the user, then you can simply check if your card has a defined value for it, and if this defined value is really part of the card itself
I reused some code from the first snippet, didn't want to spend to much extra time on it ;)
var cards = [{
title: 'Card 1',
prop1: 'Test of card1',
description: 'Description of card1',
customCard1: 'Custom property'
}, {
title: 'Card 2',
description: 'Description of card2',
customCard2: 'Custom property card2'
}];
function getSearchParameters() {
var properties = [];
$('.search').each(function() {
if (this.value) {
properties.push(this.value);
}
});
return properties;
}
function search() {
var properties = getSearchParameters(), i, len, card, matches = [], p, plen, prop, match;
for (i = 0, len = cards.length; i < len; i++) {
card = cards[i];
match = true;
for (p = 0, plen = properties.length; p < plen; p++) {
prop = properties[p];
if (typeof card[prop] === 'undefined' || !card.hasOwnProperty(prop) ) {
// didn't find a property, this doesn't match
match = false;
break;
}
}
if (match) {
matches.push(card);
}
}
showMatches(matches);
}
function showMatches(matches) {
var elem = document.getElementById('result'),
i, len, content = '';
if (typeof matches === 'undefined' || !matches.length) {
elem.innerHTML = '<i>No results found</i>';
return;
}
for (i = 0, len = matches.length; i < len; i++) {
content += '<div><b>title:</b>' + matches[i].title + '</div>';
}
elem.innerHTML = content;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<input type="text" class="search" />
<button type="button" onclick="search()">Search for matching properties</button>
<div id="result">
</div>
I'm trying to delete an item from an array and add it to another array. The array states consists of a list of 50 states. User needs to enter the name of a state and the state must get deleted from states array and get added to the array correctState. Here is my code
function searchString()
{
var total = 50;
var string = document.getElementById("txtState").value;
var element = document.getElementById("status");
for (i=0; i < states.length; i++)
{
if(states[i].toUpperCase() == string.toUpperCase())
{
count = count + 1;
//element.innerHTML = "CORRECT!!!"
addElem = states.splice(i,1);
correctState.push(addElem);
/*for (j=0; j < correctState.length; j++)
{
if(correctState[j].toUpperCase() == string.toUpperCase())
{
element.innerHTML = "Already Submitted. Try another State";
}
}*/
}
document.getElementById("score").innerHTML = count +"/"+ total;
document.write(states);
document.write(correctState);
}
}
Enter State : <input type="text" name="txtState" id="txtState"><span id="timer"></span><br /><span id="status"></span>
<button type="button" name="btnPlay" id="btnPlay" accesskey="s" onClick="searchString()"><u>S</u>ubmit</button>
I'm not able to achieve what I need. I'm new to javascript and need help.
Re these lines:
addElem = states.splice(i,1);
correctState.push(addElem);
splice doesn't return the element that you remove, it returns an array of those elements. So your code is pushing array instances onto correctState. I'd do this:
correctState.push(states[i]); // First push the matching state onto `correctStates`
states.splice(i,1); // ...then remove it
Alternately, you could do it in the order you showed, you just have to get the removed element out of the array you get back
addElem = states.splice(i,1);
correctState.push(addElem[0]);
// Here -----------------^^^
but again, I'd do it by pushing first, then removing.
Separately, I'd use the debugger built into your browser to single-step through that code and watch it run. I suspect you'll find that you want to move some things around, and you almost certainly want to stop looping once you've found that string matches something in the array.
My guess is that it's the fact that you're modifying your states array while you are still enumerating.
So say you're states array is [AR, LA, CT] and the user entered LA. So your for loop goes like this
i = 0 (length is 3 so i < 3)
string not found
i = 1 (length is 3 so i < 3)
string found, remove it from states
i = 2 (length is 2 so i < 2 fails and there's no final loop)
What you probably want is just something like this
function moveAllInstancesBetweenArrays(val, source, destination) {
var indexOfVal = source.map(function(s) { return s.toUpperCase() })
.indexOf(val.toUpperCase());
if(indexOfVal == -1)
return;
source.splice(indexOfVal, 1);
destination.push(val);
moveAllInstancesBetweenArrays(val, source, destination); //continue until all matching are moved
}
moveAllInstancesBetweenArrays(yourSearchVal, states, correctStates);