Question

I'm having a hard time figuring out how to run a method on certain elements/nodetypes but not others.

For instance here's some HTML:

<div id="parent">
    <div class="subparent">Changing Text
        <div class="no-change">Changing Text</div>
    </div>
    <div class="subparent">Changing Text</div>
        <div class="child">Changing Text
            <div class="no-change">Changing Text</div>
        </div>
    <div class="subparent">Changing Text</div>
</div>

My method is something like this:

jQuery.fn.changingtext = function(expr) {
    return this.each(function() {
        this.innerHTML = this.innerHTML
        .replace(/Changing Text/ig, "Edited!")
    });
};

Now I want to change the text of everything except what's in div.no-change. The end result should be something like this:

<div id="parent">
    <div class="subparent">Edited!
        <div class="no-change">Changing Text</div>
    </div>
    <div class="subparent">Edited!</div>
        <div class="child">Edited!
            <div class="no-change">Changing Text</div>
        </div>
    <div class="subparent">Edited!</div>
</div>

I don't know of any way to select a parent without also running the method on its child. Any help would be appreciated. Thanks!

Edit: Here is using Paulo's code and not working: http://jsbin.com/usaxa

Edit@Jeff Meatball Yang: Hi, using your inplace replacement it outputs as text rather than html: http://jsbin.com/idina

I also wasn't able to get the other methods working: http://jsbin.com/aguca

Could you provide an example please?

Thanks!

Was it helpful?

Solution

Try this:

jQuery.fn.changingtext = function(expr) {
    return this.each(function() {
      // filter for text node
      var nodes = $(this).contents().filter(function() { return this.nodeType == 3); });

      // or do in-place editing
      for(var i = 0, len = nodes.length; i < len; i++) {
        nodes[i].nodeValue = nodes[i].nodeValue.replace(/Changing Text/ig, "Edited!");
      }
    });
};

// prove that no change is still white
$("#parent div.no-change").css("color", "white");

// change text, then make it red using jQuery
$("#parent div:not(.no-change)").changingtext().css("color", "red");

The end result is already HTML. So, you will be able to chain other jQuery functions after the plugin call. See my edit.


instead of setting the text node value (nodes[i].nodeValue), you can remove it and append a DIV after it. Instead of using a for loop and replacing the text, you can remove the for loop and use jQuery's built-in functions:

jQuery.fn.changingtext = function(expr) {
    return this.each(function() {
      // filter for text node
      var nodes = $(this).contents().filter(function() { return this.nodeType == 3); });

      // you can replace the text nodes:
      // insert a DIV after each one, 
      // then remove it from the DOM
      nodes.after("<div>Edited!</div>").remove();
    });
};

This is documented in the jQuery Docs (http://docs.jquery.com) on Manipulation and Traversing.

OTHER TIPS

I'm not really sure why you're writing a plugin to do this. This would find all the <div> elements inside #parent, filter out those that don't have the class of .no-change, and edit the text contents of them:

$('#parent').find('div').not('.no-change').text('Edited!');

Which could also be written as:

$('#parent div:not(.no-change)').text('Edited!');

jQuery is very good at working on set of elements, you don't have to loop through them and such.

EDIT:

This should work to take account CMS's good observation:

$('#parent').find('div').not('.no-change').each(function() {
    $(this).contents().not('*').eq(0).replaceWith('Whatever');    
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top