How to detect if an element is accompanied by some text with jQuery?

4

I have a certain div.box that will be repeated several times, and some of them have a link ( a.link ) with a specific class.

Example:

<div class="box" data-id="1">
Primeiro texto
</div>

<div class="box" data-id="2">
Segundo texto <a class="link">Clique aqui</a>
</div>

<div class="box" data-id="3">
<a class="link">Clique aqui</a>
</div>

<div class="box" data-id="4">
Testando
</div>

Of the divs shown above, I need to detect that, around a.link , there are no texts. That is, from the above example it could return only div.box whose data-id equals 3 .

How can I detect this through jQuery?

That is, I have to make sure that the div.box only contains within that element a.link (and nothing else).

    
asked by anonymous 25.09.2015 / 18:50

3 answers

3

There are several conditions that need to be checked. The way I think it's the right one is to go through all childNodes and check how many there are that are not empty. At the same time check if at least one of them has the desired element / class:

function temSoClasse(elInicial, seletor) {
    return = $(elInicial).filter(function () {
        var hasLink = false;
        var nodes = $(this.childNodes).filter(function (i, el) {
            if (el.nodeType == 1) {
                if ($(el).parent().find(seletor).length) hasLink = true;
                return true;
            }
            return el.textContent.trim().length;
        });
        return nodes.length == 1 && hasLink;
    });
}

And then you can use it like this:

var els = temSoClasse('.box', 'a.link');
els.css('color', 'blue'); // vai mudar a côr do elemento que se procura

jsFiddle: link

A more compressed version might look like this:

function temSoClasse(elInicial, seletor) {
    return $(elInicial).filter(function () {
        return this.querySelector(seletor) && $(this.childNodes).filter(function (i, el) {
            return el.textContent.trim().length;
        }).length == 1;
    });
}

jsFiddle: link

    
25.09.2015 / 19:41
2

As @DontVoteMeDown said, "... this is a good exercise."

$(".box").filter(function(i) 
{
    var $that =  $(this);

    var node = $that.contents().get(0);

     if ($that.contents().length == 1 && $(node).is('a')) {
        return true;
     }

     return false;

});

When we use the $.contents function, jQuery returns the nodes present within that element.

So, I check if there is only one node with $(this).contents().length == 1 .

I then check if the node is an element whose tag is a , via $(node).is('a') .

Using the $.is function, we check if the element is a link. Since node is not a jQuery selector, you need to use it with jQuery through $(...) .

The $(this).contents().get(0) is in charge of getting the first element.

So we have the check that div.box has a node, and if that node is a link.

Update : Following the example of the @DontVoteMeDown response, we could also, instead of using $(node).is('a') , do as follows:

 if ($that.contents().length == 1 && node.nodeType == 3) {
     return true;
 }
    
25.09.2015 / 19:34
2

I think I found a way:

var list = $(".box").filter(function(i, el) 
{
    return Array.from(el.childNodes).filter(function(cn) 
    {
        return  cn.textContent.trim() != "" && 
                cn.nodeType == 3;
    }).length == 0;
});

Fiddle

Explanation:

  • Above the selector $(".box") we run a filter() , since the intention is to filter the elements that do not have text between the element a ;
  • For each element, we get the childNodes collection containing the elements of text that we will check;
  • The nodeList is not quite an array, so in order to run another filter() we create an array with Array.from() ", and then run filter() ;
  • The condition of this last filter() is that it is of text type ( nodeType == 3 ) and not be empty ( textContent.trim() != "" ), since there is textNodes only with line break;
  • This last filter() being empty ( .length == 0 ), we are sure - hopefully haha - that it does not have textNodes immedi- ately below it.
  • UPDATE

    $.fn.checarElemento = function(checarFilhos)
    {
        return $(this).filter(function(i, el) 
        {
            return $(el).find(checarFilhos).length > 0 && Array.from(el.childNodes).filter(function(cn) 
            {
                return  cn.textContent.trim() != "" && 
                        cn.nodeType == 3;
            }).length == 0;
        });
    };
    

    And to ensure that there is the selector you want within the element in question, I have added the simple condition $(el).find(checarFilhos).length > 0 , which if not satisfied, nor does it spin filter() on childNodes . Micro optimization maybe? Usage:

    $(".box").checarElemento("a.link");
    

    Fiddle

        
    25.09.2015 / 19:16