How to go about parsing text for keywords in jQuery? - javascript

Say I had a famous speech posted on a website. What would be the best way to go about searching for a given keyword, say 'hello' throughout the entire document and save the number of occurrences as an integer? I don't really know where to start on this one. Should I use something like...
var wordcount;
$('#wrapper').each(function(e)
{
$("div:contains('hello')"){ //all content will be in the wrapper div
wordcount++;
});
});
I know that probably isn't right, but hopefully I'm on the right track. Thanks for the help!

The easiest way is to just return the length of a RegExp match:
var count = $("#wrapper div:contains('hello')").html().match(/hello/ig).length;

var numberOfMatches = $('div').text().match(/hello/ig).length;

Well unfortunately, that div:contains is only going to fire once. It is looking for all divs that contain that text. Unless you have every word wrapped in a div tag...
var text = $('#wrapper').text();
var words[] = text.split(' ');
var count = 0;
for(var i=0; i<words.length; i++){ if(words[i].IndexOf("TheWord") >= 0){ count++; } }
This is a non jquery method, but it should work for you.

If you're wanting to do this interactively (i.e., with a dynamic string), then this implementation is idiomatic:
http://jsfiddle.net/entropo/S5uTg/
JS ...
$("#keyword").keyup(function() {
var value = $(this).val(),
re = new RegExp(value, 'ig'),
count = $("#speech").text().match(re).length;
$("#result").text("Occurences: " + count);
});
HTML ...
<div id="search-form">
<legend>Search through this text</legend>
<label for="keyword">Keyword</label>
<input id="keyword" name="keyword" type="search"
placeholder="e.g. - today" required="" autofocus="" />
<div id="result"></div>
</div>

Related

Javascript find and replace function using while loop

I have this simple function to find and replace text in my textarea message. User will be able to type into the textarea and also be able to find and replace words from the text area they just entered. Currently I'm trying to use a while loop to replace multiple same words found in the textarea that the user keyed in. But every time I run it it seems to freeze the entire html page any idea why this is happening?
find and replace are textbox for user to key in the word they want to find and replace the user is able to key in multiple words to replace as well.
function findText() {
let find = document.getElementById('find').value;
let replace = document.getElementById('replace').value;
let message = document.getElementById('message').value;
var lmao = message.indexOf(find);
while (message.indexOf(find) != -1) {
document.getElementById("message").value = message.replace(find, replace);
}
}
Replace while loop with a replaceAll.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll
function findText() {
let find = document.getElementById('find').value;
let replace = document.getElementById('replace').value;
let message = document.getElementById('message').value;
var lmao = message.indexOf(find);
document.getElementById("message").value = message.replaceAll(find, replace);
}
<div>Find <input id="find" value="find" /></div>
<div>Replace <input id="replace" value="replace" /></div>
<div>
<textarea id="message" style="height: 100px">you can find and replace every words just by .replaceAll, example: find 1 find 2 find 3</textarea>
</div>
<div>
<button onclick="findText()">Submit</button>
</div>
Just a addition in other answer you can use g for global search and to replace where you find that word .
Read more about regex and //g here
Also you can let the search case-insensitivity using i along with g like this :
message.replace(/find/g, replace)
This way it will also replace Find finD FIND
And instead of using while you can use if loop
function findText() {
let find = document.getElementById('find').value;
let replace = document.getElementById('replace').value;
let message = document.getElementById('message').value;
var lmao = message.indexOf(find);
if(message.indexOf(find) != -1) {
document.getElementById("message").value = message.replace(/find/g, replace);
}
}
<div>Find <input id="find" value="find" /></div>
<div>Replace <input id="replace" value="replace" /></div>
<div>
<textarea id="message" style="height: 100px">you can find and replace every words just by .replaceAll, example: find 1 find 2 find 3</textarea>
</div>
<div>
<button onclick="findText()">Submit</button>
</div>
The issue is with your while condition. When all input fields are empty your while condition is true. So inside the while condition the input value keeps on updating to empty string again, which makes loop an infinite loop. Thats why your ui is breaking.
Issue Scenario
console.log(("").indexOf("") !== -1);
To fix this, you have to make sure that your find and replace values are not same. Or else, it will be an infinite loop again.
Fixed Solution
function findText() {
let find = document.getElementById('find').value;
let replace = document.getElementById('replace').value;
let message = document.getElementById('message');
while (find !== replace && message.value.indexOf(find) != -1) {
message.value = message.value.replace(find, replace);
}
}
<input type="text" id="find">
<input type="text" id="replace">
<textarea name="" id="message" cols="30" rows="10"></textarea>
<button onclick="findText()">Check</button>

How to automatically change a specific text value with an input value?

What I'm trying to achieve is that when I'm entering an input value, the specific number of a textarea's value would replaced too according to the input value.
F.e: If I would enter into the input value a number 4, textarea's specific value (in this case a number) would be 4 too. If I would delete a value from the input, the value would be deleted from textarea too.
As you can see in the snippet, it works bad. It changes a value just one time. After that, 'text-areas' value isn't changing.
Could someone help me with that? Thank you for your time
$('.text1').keyup(function() {
var recommendationText = $('.textarea');
var specificString = '4';
var str = $('.textarea').val().replace(specificString, $(this).val());
recommendationText.val(str);
specificString = $(this).val();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" class="text1">
<textarea rows="4" class="textarea" cols="50">
This is a textarea of 4 rows.
</textarea>
There are a couple of issues with your code. The first is that the specificString value is being reassigned each time you do a keyup, so you need to set the default outside of the event handler. But also, if you delete the value, it will have no way of finding it and will prepend it to the start.
I'd personally recommend using a template based approach, rather than storing the previous value:
var specificString = '[numRows]';
var recommendationText = $('.textarea').val();
$('.text1').keyup(function() {
var numRows = $(this).val();
if (isNaN(parseFloat(numRows)) || !isFinite(numRows) || numRows.length < 1) {
numRows = 0;
}
var str = recommendationText.replace(specificString, numRows);
$('.textarea').val(str);
}).keyup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" class="text1" value="4">
<textarea rows="4" class="textarea" cols="50">
This is a textarea of [numRows] rows.
</textarea>
This could use a proper templating language like Handlebars or Underscore.js templates, but that is too opinion-based to include in my answer.
Declare and initialize specificString outside of keyup() event.Otherwise your value for specificString will be always 4.
var specificString = '4';
$('.text1').keyup(function() {
var recommendationText = $('.textarea');
var str = $('.textarea').val().replace(specificString, $(this).val());
recommendationText.val(str);
specificString = $(this).val();
});
Well your issue is you replace the string so next time you look for the 4 it is not there. Reason why is you redefine specificString inside of the loop so it is always 4 and not what the user last typed. So if you move it outside it will work ("sort of")
Your design will fail if the user enters in something that matches another word. EG This, it will replace the first occurrence, not the string you want to replace. Or if you delete the string, you will not have any match.
So what can you do? I would use a data attribute with the original and use that. And I would make some sort of "template" so you know what you are replacing and do not replace another part of the string with the replacement when user matches text.
$('.text1').keyup(function() {
var ta = $('.textarea')
var specificString = /\{4\}/;
var entry = $(this).val() || "4";
var str = ta.data("text").replace(specificString, entry);
ta.val(str);
}).trigger("keyup");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" class="text1">
<textarea rows="4" class="textarea" cols="50" data-text="This is a textarea of {4} rows.">
</textarea>
In your way your code would work. Just change your code like this..! There are some logical issues in your code. Initiate the value of specificString outside the keyup() method to get first 4 and then then the value of textbox.
var recommendationText = $('.textarea');
var specificString = recommendationText.val().match(/\d+/);
$('.text1').keyup(function() {
if($(this).val() != '' && $.isNumeric($(this).val())) {
var str = $('.textarea').val().replace(specificString, $(this).val());
recommendationText.val(str);
specificString = $(this).val();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" class="text1">
<textarea rows="4" class="textarea" cols="50">
This is a textarea of 4 rows.
</textarea>
Solution is much easier than you might expect.
Note: The $ in ${inputVal} is not jquery, its part of template literals. Don't get confused there.
document.getElementById('text1').onkeyup = changeTextArea;
function changeTextArea() {
let inputVal = document.getElementById('text1').value;
let text = `This is a textArea of ${inputVal} rows`;
document.getElementById("textarea").value = text;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" id="text1">
<textarea rows="4" id="textarea" cols="50">
This is a textarea of 4 rows.
</textarea>

See what changed inside TextArea with on change listener

I need a textbox, where everytime the text changes, I know what exactly has changed. I'm currently using a JQuery's listener for changes in my input element, and what I do is:
When the text changes
Get the text from the box a1 and compare to what I have in box a2.
If there are changes, log them into output textarea
Here is a Sample https://codepen.io/nikolaevra/pen/eeWWbo
I'm currently using the following diff library https://github.com/kpdecker/jsdiff, and it has O(NM) efficiency, which is a lot.
Is there a way to get the exact change that was made to the textarea using JQuery or anything like that? For example, if I had test in both a1 and a2 and then changed a1 to be testing, I want to see ing as the change that was made.
EDIT:
I tried playing around with the method a little bit and this is one problem that I found. When I run diff = "testing".replace("test",''); => ing just as required, but when I try diff = "testing a potato cannon".replace("testing potato cannon",''); => testing a potato cannon, where I only changed one character. This is a lot of overhead that I wanted to avoid. In that case, I would only want to know where the value has been changed and what it has been changed to. Not the entire tail of the string.
Consider that what you have in string a1 is the constant text and that what you have in string a2 is where you make changes.
let's just say that the value in a1 is "test";
Try this for your JavaScript:
var constValue = $('#a1').val();
$('#a2').change(function() {
var changingValue = $('a2').val(); // say the value entered is "testing"
console.log(changingValue.replace(constValue, ''); // gives you "ing"
}
This will give you the changed/entered (newly) value in string a2 and log it to your console.
The logic you use here is simple:
Read the value from string a2 and use the value in a1 to replace (if exists) in string a2, hence giving you the changed value. You need not use any libraries for this. JavaScript gives you this function called replace.
Do let me know if any more queries.
nikolaevra, have you tried using javascript's replace method? e.g diff = [value of a1].replace([value of a2],'');
You can use this method to achive what you are looking for :
function getDifference(a, b)
{
var i = 0;
var j = 0;
var result = "";
while (j < b.length)
{
if (a[i] != b[j] || i == a.length)
result += b[j];
else
i++;
j++;
}
return result;
}
Then you need to make a method to get the values from your textboxs and use it in your button onclick event, I used javascript, you can use jquery if you want :
function findDiff(){
var b1= document.getElementById("b1").value;//sky is blue
var b2= document.getElementById("b2").value;//sky is red
document.getElementById("result").value=getDifference(b1,b2);//red
}
https://jsfiddle.net/eu2kvfxo/
i hope this code will help you
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
var arr_text1 = new Array();
var arr_text2 = new Array();
var i=0;
var text2nw="";
$('#a2').on('input',function () {
arr_text1 = $("#a1").val().split('');
arr_text2 = $("#a2").val().split('');
if (arr_text1[i] == arr_text2[i]) {
}
else {
$('#output').val($("#a2").val().replace($("#a1").val(), ""));
// $('#output').val(text2nw);
}
if ($("#a2").val() != '') {
i++;
}
else {
i = 0;
$('#output').val('');
}
});
});
</script>
</head>
<body>
<p>This is the original text:</p>
<textarea id="a1" rows="4" cols="50" type="text"></textarea>
<p>Change Text to something else here:</p>
<textarea id="a2" rows="4" cols="50" type="text"></textarea>
<p id="title">This are the changes that you made:</p>
<textarea rows="10" cols="100" id="output" for="title"></textarea>
</body>
</html>

Loop through each child in a div with data-attribute

I have multiple <div>s, based on a <select>, where each one contains multiple <input>s and sometimes a disabled <select> with a fixed value. Now I'm trying to loop through each of the divs and put all inputs and select values into an array and push that array into the "master" array.
However this seems not to work to well.
I feel like I'm already close but yet so far. :(
var dummy = [];
for(var i = 1; i <= toSend.count; i++){
var temp = [];
$("div[data-row="+i+"]").children('input, select').each(function(){
temp.push( $(this).val() );
});
dummy.push(temp);
};
console.log(dummy);
toSend.count is the counting of how many div's with data-row exist.
The HTML looks like this :
<div id="container">
<div data-row="1">
<input type="text"/>
<input type="text"/>
</div>
<div data-row="2">
<input type="text"/>
<input type="text"/>
</div>
</div>
Aaah, nevermind this was my own stupidity! I'm generating the div's via AJAX
and I copy pasted myself an error.
All div's had data-row=1, no wonder it packed all in one array >.<
(Edit: pays to read the code more completely)
Since the toSend variable is just the DIVs with a data-row attribute, no need to loop over toSend to find the DIVs:
var dummy = [];
$("#container div[data-row]").each(function() {
var temp = [];
$(this).children("input, select").each(function() {
temp.push(this.value);
});
dummy.push(temp);
});
After this, you might not even need the toSend variable at all.
Brief code for what you want to achieve.
$("div[data-row="+i+"]")each(function(){
$(this).children('input, select').each(function(){
console.log( $(this).val());
console.log("Child Change");
});
console.log("Div Change");
});
.each function from jquery is not syncrounious, use for instead.
var $tmp;
for(var i = 1; i <= toSend.count; i++)
{
$tmp = $("div[data-row="+i+"]").children('input, select');
for(var ii = 1,len = $tmp.length; ii <= len; ii++){
console.log( $tmp.eq(ii).val());
};
console.log("New line #" + i);
};

How to get this jQuery script to run individually on more than one element

I'm not sure if the title is correct. I can't seem to express this problem properly in words!
I have the following text fields in my HTML that I'm trying to limit the number of characters that can be entered into:
<div class="limited limit-200">
<div class="label">
<label for="_je_industries_desc">Industry Description</label>
</div>
<div class="input">
<textarea class="large-text" name="industries_desc" id="industries_desc" cols="60" rows="3"></textarea>
<p id="industries_desc_description" class="description">Put a short description of this industry.</p>
</div>
</div>
<div class="limited limit-100">
<div class="label">
<label for="_je_seo_description">Meta Description</label>
</div>
<div class="input">
<textarea class="large-text" name="seo_description" id="seo_description" cols="60" rows="3"></textarea>
<p id="seo_description_description" class="description">Put a short description of the content of this page.</p>
</div>
</div>
Here's my jQuery so far.
It gets the character limit from the class name in the HTML limit-200 for example. Then calculates the amount of characters left as you type and outputs the remaining characters under the textarea.
jQuery(document).ready(function(){
jQuery('.limited').each(function() {
// Get the class names of any element that has the class .limited
var className = jQuery(this).attr('class');
// Use regex to capture the character limit class (limit-#)
var limit = className.match(/[?:limit-](\d+)/);
// Set the limit var to the match from the regex
var limit = limit[1];
// Calculate the number of characters that are still available (limit - characters in field)
var chars_left = limit - jQuery('textarea', this).val().length;
//alert(chars_left);
// Attach an event handler to each textarea with the class .limited
jQuery('textarea', this).on('keyup', function() {
var maxchar = limit;
var cnt = jQuery(this).val().length;
var remainingchar = maxchar - cnt;
if(remainingchar < 0){
jQuery('#limit-counter span').html('<strong>0</strong>');
jQuery(this).val(jQuery(this).val().slice(0, limit));
} else {
jQuery('#limit-counter span').html('<strong>' + remainingchar + '</strong>');
}
});
// Display number of characters left
jQuery('textarea', this).after('<span id="limit-counter">Remaining characters: <span><strong>' + chars_left + '</strong></span></span>');
});
});
This works great for a single textarea but if I have more than one and type in one of the textareas the other textarea updates its counter with the same value as the one I'm typing in.
Could someone please help me spot what I'm doing wrong? Hopefully I'm just missing something simple somewhere!
Thanks!
You can simplify this a lot. Start by just putting the maximum restraint in a maxlength attribute:
<textarea name="seo_description" maxlength="100"></textarea>
Then, select all textareas that have a maxlength attribute, and loop through them:
$('textarea[maxlength]').each(function() {
var $this = $(this),
limit = $this.attr('maxlength'),
$counter = $('<span class="limit-counter">Remaining characters: <strong></strong></span>')
.insertAfter(this).find('strong');
$this.on('keyup', function() {
$counter.text( limit - $this.val().length );
})
.trigger('keyup');
});
See it here in action: http://jsfiddle.net/U4Mk6/
I've added this to a fiddle and done the modifications:
http://jsfiddle.net/KQKnN/
var $textarea=jQuery(this).find('textarea');
var uniqueId= $textarea.attr('id');
Trouble here that your limit-counter has to be unique, you can't have two elements with the same id on one page.
if(remainingchar < 0){
jQuery('#limit-counter-'+uniqueId+' span').html('<strong>0</strong>');
jQuery(this).val(jQuery(this).val().slice(0, limit));
} else {
jQuery('#limit-counter-'+uniqueId+' span').html('<strong>' + remainingchar + '</strong>');
// .....
$textarea.after('<span id="limit-counter-'+uniqueId+'">Remaining characters: <span><strong>' + chars_left + '</strong></span></span>');
I also added the textarea to a cached selector - you'll get better performance because of this but it's totally optional.
As far as your specific problem goes, I think this line and the one within the else is the culprit:
jQuery('#limit-counter span').html('<strong>0</strong>');
which should be:
jQuery('#limit-counter span', this).html('<strong>0</strong>');
Does this help?

Categories