Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get just the visible text with jQuery (or Javascript)?

I have website that converts Japanese Kanji into Romaji (roman letters):

and the output shows and hides with CSS what the user needs to see depending on their input criteria. For example:

<div id="output"><span class="roman">watashi</span> <span class="english">I</span></div>

The interface allows the user to flip between and output of watashi or I depending on what they want to see. The CSS hides one or the other using jQuery and a toggle button. (the hiding mechanism involves simple adding a class to the body and letting CSS do its thing).

The problem is that when users copy/paste the text into Word it copies everything. So I decided to use a system to copy paste the text using JavaScript and jQuery, but the problem repeats itself:

$('#output').text() outputs watashi I even if I is invisible on the page itself rather than watashi. Is there any way to get just the visible text?

like image 507
Gazzer Avatar asked Dec 04 '09 10:12

Gazzer


People also ask

How do I get text in jQuery?

Get Content - text(), html(), and val() Three simple, but useful, jQuery methods for DOM manipulation are: text() - Sets or returns the text content of selected elements. html() - Sets or returns the content of selected elements (including HTML markup) val() - Sets or returns the value of form fields.

How do I get text in Javascript?

Use the textContent property to get the text of an html element, e.g. const text = box. textContent . The textContent property returns the text content of the element and its descendants. If the element is empty, an empty string is returned.

How do you make something visible in Javascript?

visibility = 'visible'; If you are using jQuery, you can do it even easier as long as you want to set the display property: $(elem). hide(); $(elem).

Is visible using jQuery?

Answer: Use the jQuery :visible Selector You can use the jQuery :visible selector to check whether an element is visible in the layout or not. This selector will also select the elements with visibility: hidden; or opacity: 0; , because they preserve space in the layout even they are not visible to the eye.


2 Answers

the other solutions did not give me what I needed.

Short Answer

my answer is :

$('#output *:not(:has(*)):visible').text() 

plunkr

TL;DR

The problem with marcgg's solution

You should not ask the text of all element under some root element..

why? - it will repeat output and ignore hidden flag

lets look at a simple example

<div id="output" class="my-root">     <div class="some-div">          <span class="first" style="display:none"> hidden text </span>          <span class="second" > visible text </span>     </div> <div> 

now if I do $('#output').children(":visible").text()

I will get .some-div and .second.. when in fact .some-div is of no concern to me..

when I ask for text() on those elements, .some-div will return the hidden text as well..

so technically marcgg's solution is wrong IMHO...

The reason for my answer

Now, in order to properly answer the question, we have to make an assumption. One that, for me, seems reasonable enough.

The assumption is that text only appears in leaf elements..

So we won't see something like this:

<div id="output" class="my-root">     <div class="some-div">          <span class="first" style="display:none"> hidden text </span>          <span class="second" > visible text </span>     </div>      some text here..   <div> 

Why does this assumption seem reasonable to me? two reasons:

  • Because it is hard to maintain a page that is constructed this way - and with time people with experience learn that and avoid it.
  • It is easy to convert your html to such a structure. just wrap parents' text with spans. So even if this assumption does not exist right now, it is easy to get there.

With that assumption, what you want to do is request all leaf elements (elements without children) , filter out the visible, and ask for their text..

$('#output *:not(:has(*)):visible').text() 

This should generate the correct result.

Gotta have text outside leaf element?

the comments suggest sometimes you just got to have text outside leaf element

<div> This is some <strong style="display:none"> text </strong>  </div> 

As you can see, you have <strong> as a leaf and it is common to have text outside it like in this example.

You could go around it with the workaround I suggest above.. but what if you can't?

You can clone the dom and then remove all hidden elements. The problem here is that in order for :visible selector or :hidden selectors to work, I must have the dom element on the document (which means actually visible to the user). And so, this method comes with some side effects, so be careful.

Here is an example

for this html

 <div id="output" class="my-root">      <span>          some text <strong style="display:none">here.. </strong>      </span> </div> 

This javascript works

$(function(){      var outputClone = $('#output').clone();     $('#output :hidden').remove();      console.log($('#output').text()); // only visible text     $('#output').replaceWith(outputClone);     console.log($('#output').text()); // show original state achieved.  }) 

see plunker here

as mentioned - side effects may appear like a momentary flicker, or some initialization script that should run.. some may be avoided with some original thinking (div with size 1px/1px to contain the clone alongside original content?) depending on your scenario.

like image 148
guy mograbi Avatar answered Oct 02 '22 13:10

guy mograbi


Use the :visible selector of jQuery

In your case I think you want to do:

$('#output').children(":visible").text()  
like image 38
marcgg Avatar answered Oct 02 '22 13:10

marcgg