What I want to do
I want to be able to work out how much of a string is shown before it is truncated.
Why I want to do it
I have a list of items. You can select any amount of items from this list. I have a panel element that shows a comma separated string of the selected selected item names. If the string is too long, it should be truncated and display a +{number} value of any additional selected items hidden by the truncate.
Basic example
https://stackblitz.com/edit/angular-ivy-cbyemy
The stackblitz above shows a basic example of the use case.
Currently panel title:
an item, another item, som... +6
Desired result:
an item, another item, som... +3
What I have tried
Using element.innerHTML and element.innerText to read the displayed string. both show the full string, not the displayed truncated string.
Borrowed an answer from here and modified it a bit as per requirement.
Your forked stackblitz, updated working demo here.
You can get the count of visible characters from this function -
countVisibleCharacters(element): number {
var text = element.firstChild.nodeValue;
var count = 0;
element.removeChild(element.firstChild);
for (var i = 0; i < text.length; i++) {
var newNode = document.createElement('span');
newNode.appendChild(document.createTextNode(text.charAt(i)));
element.appendChild(newNode);
if (newNode.offsetLeft < element.offsetWidth) {
count++;
}
}
return count;
}
Then you can get the suffix this way -
getTitleSuffix(): void {
let element = document.getElementById('title');
let count = this.countVisibleCharacters(element);
let substr = element.textContent;
substr = substr.substring(count - 1);
this.titleSuffix = substr.split(',').length;
}
Related
Is it possible to change the index of the last item of a multidimensional input when my new item is created ?
Let me explain.
I have a button that is clone an item from my list, into my list. Each item contains several properties (date, category...)
This is an example of what I have when I display my form :
validation_form[classe][0][matieres][11][ressources][XXXXX][hasBeenRenewed]
What I do is that I clone all my item, but for now, the index XXXX is not updated.
How can I update the XXXX directly when I clone my item ? I thought I could count the number of items, and then change the index, but this would be painful and time consuming...
Use a regex in match() to create array of them then update the one you want and join() back together
const el = document.querySelector('input');
const prefix = el.name.split('[')[0],
ind = el.name.match(/\[(.*?)\]/g);
ind[5]= `[AAA]`;
el.name = `${prefix}${ind.join('')}`
console.log(el)
<input name='validation_form[classe][0][matieres][11][ressources][XXXXX][hasBeenRenewed]'/>
With a little bit of change, the #charlietfl answer works (had to change to fit into my case)
let inputs = new_ressource_clone.find('input');
let new_index = parseInt(count_ressource) + 1;
inputs.each(function() {
let input = $(this)
const prefix = input.attr('name').split('[')[0],
ind = input.attr('name').match(/\[(.*?)\]/g);
ind[5]= '['+new_index+']';
matiere_zone.attr('data-matiere-count-ressources', new_index);
let new_name = `${prefix}${ind.join('')}`;
input.attr('name', new_name);
})
new_ressource_clone.appendTo(liste_zone);
I'm using the following code to delete text between a range of characters.
However, when I try to delete multiple paragraphs of text, I receive the following error:
Index (548) must be less than the content length (377). (line 195, file "")
How I can remove unlimited amounts of text between two text values?
function removeCbSevHD1(X) {
var rangeElement1 = DocumentApp.openById(X).getBody().findText('<CS1>');
var rangeElement2 = DocumentApp.openById(X).getBody().findText('<CS2>');
Logger.log(rangeElement1.getElement());
if (rangeElement1.isPartial()) {
var startOffset = rangeElement1.getStartOffset();
var endOffset = rangeElement2.getEndOffsetInclusive();
rangeElement1.getElement().asText().deleteText(startOffset,endOffset);}
}
}
Expanding on my answer to your previous question, you cannot select from the beginning of one range to the end of another range. That is what the if (element.isPartial()) { ... } else { ... } condition is for. If the range is the entire element, it will remove the whole element.
If you want to remove multiple ranges, then you have to remove one at a time.
In the following example I do this by looping through an array of search strings and applying the function to each.
function removeCbSevHD1(X) {
// If you want to add more things to match and remove, add to this array
var search = /<CS1>.*<CS2>/;
var rangeElement = DocumentApp.openById(X).getBody().findText(search);
if (rangeElement.isPartial()) {
var startOffset = rangeElement.getStartOffset();
var endOffset = rangeElement.getEndOffsetInclusive();
rangeElement.getElement().asText().deleteText(startOffset,endOffset);
} else {
rangeElement.getElement().removeFromParent();
}
}
Note: Not tested.
Tiny G! Thanks for all the help man.
I was able to find some help. Here's the answer:
function removeSection3(X) {
for (var i = 1; i <= 7; i++) {
var search = '<ZY' + i + '>';
var rangeElement = DocumentApp.openById(X).getBody().findText(search);
if (rangeElement) {
rangeElement.getElement().getParent().removeFromParent();
}
}
}
I was wanting to count the occurrences of input fields that has a class name of text where that text input contains a specific value.
document.getElementById('c_files').getElementsByClassName('text').length;
So far this counts all textboxes with the class name of text but how can i make it value specific, say if i have 50 textboxes but i only want to count the ones where the value of that textbox contains abc somewhere within the string.
Thanks.
Edit: Thank you everyone for your time and answers, i have voted you all up, but i prefer John Bupit's solution out of them all so thats the one i will accept. Thanks again.
You can iterate over the elements and see which ones have the desired value:
var elems = document.getElementById('c_files').getElementsByClassName('text');
var count = 0;
for(var i = 0; i < elems.length; i++) {
if(elems[i].value.match(/abc/)) count++;
}
You can select all textboxes first and after that filter those matching your criteria. For example, by using Array.prototype.filter method:
var allText = document.getElementById('c_files').getElementsByClassName('text'),
filtered = [].filter.call(allText, function(textbox) {
return textbox.value.indexOf('abc') > -1;
});
Above code will produce and array of text elements where value contains substring "abc".
Hi I think you need to review this SO post-
https://stackoverflow.com/a/9558906/3748701
https://stackoverflow.com/a/10095064/3748701
This is something which would help in getting your solution.
You'll need to loop over all of the text boxes with the specified class and calculate it from there.
Something like the following logic should work:
var counter = 0;
var inputElements = document.getElementById('c_files').getElementsByClassName('text').length;
for (var i = 0; i < inputElements.length; i++) {
if (inputElements.value == "someText") {
counter++;
}
}
I am trying to figure out how to get each value within my div. I am using
var cart = $('.basic-cart-cart-node-title.cell').text();
It is giving the results of OI-01OP-01OS-10-5SOR-04OR-05
I need to view them one by one: OI-01, OP-01, OS-10-5S, OR-04 OR-05.
So that I can match them against another field.
If you care to help me further, I have another div on the page:
var ParNum = $('.assess-title').text();
I would like to compare the values returned from the var cart and see if that value is in the ParNum. If it is there, I would like to apply a class.
Any help would be greatly appreciated.
Thanks!
You can store the values in an array using .map() method:
var values = $('.basic-cart-cart-node-title.cell').map(function() {
return $.trim( $(this).text() );
}).get();
For checking existence of the ParNum value in the array:
var does_exist = values.indexOf(ParNum) > -1;
Try this to iterate over elements:
var text = '';
$('.basic-cart-cart-node-title.cell').each(function (i, div) {
text += ' ' + $(div).text();
});
or this to get an array of matching div elements:
var divs = $('.basic-cart-cart-node-title.cell').toArray();
for (var i = 0; i < divs.length; i++) {
// $(div).text();
}
Reason for this is that $('.basic-cart-cart-node-title.cell') returns all div's at once, and you need to loop through the result. More specifically, $(selector) returns a so-called "wrapped set". It can be used to access each matching element (as I've shown above) or it can be used to apply any other jQuery function to the whole set at once. More info here.
var text = "";
$('.basic-cart-cart-node-title.cell').each(function(){
text += $(this).text() + ", ";
});
// remove the last ", " from string
text = text.substr(0, text.length -2);
var cart = [];
$('.basic-cart-cart-node-title.cell').each(function {
cart.push($(this).text());
}
This performs the matching and class adding you mentioned in the question.
var ParNum = $('.assess-title').text();
$('basic-cart-cart-node-title.cell').each(function () {
if ($(this).text() == ParNum) {
$(this).addClass("someclass");
}
}
You should try using
var cart ='';
$('.basic-cart-cart-node-title'.find('.cell').each(function()
{
cart = cart + $(this).val();
});
Hope it works for you.
var cart = $('.basic-cart-cart-node-title.cell').text().match(/.{5}/g);
This will give you an array with items 5 chars long. Regexes arent very fast, but a loop might be slower
Or easier to read, and in a string with commas:
var cart = $('.basic-cart-cart-node-title.cell').text(); // get text
cart = cart.match(/.{1,5}/g); // split into 5 char long pieces
cart = cart.join(",",); join on comma
I've implemented an auto-completion list in javascript so that if User types 'a', all names starting with 'a' are displayed in drop-down menu. Now I want to make the text bold depending on user input in the drop down menu. So if user types 'ab', the letters 'ab' should appear bold in drop-down menu containing the word about.
Here is some part of my JS code where I'm displaying the names:
document.getElementById('dropmenu').style.visibility='visible';
var element = document.createElement("div");
var namecontainer = document.createElement("div");
namecontainer.setAttribute('id', "name" + div_id);
namecontainer.className = "namecontainerclass";
element.setAttribute('id', "div" + div_id);
element.className = "elementclass";
var text = document.createTextNode(myArray[i].name);
element.appendChild(text);
document.getElementById('dropmenu').appendChild(namecontainer);
document.getElementById("name" + div_id).appendChild(element);
var img=document.createElement("img");
img.setAttribute("src", myArray[i].image);
img.setAttribute("width", 25);
img.setAttribute("height", 25);
namecontainer.appendChild(img);
This is something that came up my mind. You want to check the user-input against the name (myArray[i].name), at that point create some textnodes (or an element if it matches), and append those to the container element (a div in this case). I didn't test it, but it is a bit pseudocode to show how to handle this higlighting without using any javascript framework.
// searchString is the string entered by the user...
// split by the searchString, but group the selection so the matches
// also get added to the result array.
var match = new RegExp('\\('+ searchString +')\\',"gi");
var textParts = myArray[i].name.split(match);
var nodes = [];
var element = document.createElement("div");
// only create elements for names that actually match.
// if there is only one match, there wasn't a match by the split
if (textParts.length > 1){
for(i = 0; i < textParts.length; i++){
if (textParts[i] == searchString) {
nodes[i] = document.createElement("em");
nodes[i].createTextNode(searchString);
} else {
nodes[i] = document.createTextNode(textparts[i]));
}
element.appendChild(nodes[i]);
}
}