JQuery заменить текст, оставив братьев и сестер нетронутыми - PullRequest
12 голосов
/ 23 февраля 2010

У меня проблемы с нахождением головы над тем, что должно быть простым решением. Я хочу заменить текст в теге метки, не затрагивая других «братьев и сестер», если они существуют.

Пример разметки:

<fieldset class="myFieldsetClass">
    <legend>Sample Fieldset</legend>
    <ol>
        <li>
            <label>
                <span class="marker">*</span>
                Some Label 1
            </label>
        </li>
        <li>
            <label>
                Some Label 2
            </label>
        </li>
        <li>
            <label>
                Text that doesn't match...
            </label>
        </li>
    </ol>
</fieldset> 

Цель:

  • Заменить текст Some Label X на Some Label (т.е. удалить X из текста метки).
  • span внутри метки должны оставаться неизменными, если они существуют, например <span class="marker"> выше.
  • Я не знаю значение X, которое может быть длиной 1 или более символов.

Текущий сценарий:

Мой скрипт jQuery ниже работает, но я знаю, что он очень неэффективен. По какой-то причине я не могу обернуться вокруг этого ...

//for each label in the fieldset that contains text "Some Label "
$(".myFieldsetClass label:contains('Some Label ')").each(function() {

    if ($(this).has("span").length > 0) {

        //if the label has the span tag within, remove it and prepend it back to the replaced text
        $(this).find("span").remove().prependTo($(this).text(labelText));

    }
    else {

        //otherwise just replace the text
        $(this).text('Some Label');

    }

});  

Сначала я подумал, что могу просто сделать:

$(".myFieldsetClass label:contains('Some Label ')").text("Some Label");

Но это очищает все содержимое метки и, следовательно, удаляет интервал, который я не хочу. Я не могу использовать функции замены для замены Some Label X на Some Label, потому что я не знаю, что будет X.

Кто-нибудь может предложить более элегантный / эффективный подход к этой проблеме?

Спасибо.

EDIT

После попытки нескольких ответов, я думаю, что проблема, кажется, в том, что даже если я выберу правильную коллекцию, они будут текстовыми узлами, которые jquery не хочет изменять. Я использовал FireBug, чтобы выбрать коллекцию (многие ответы ниже всех выбираются правильно, но немного по-разному). В консоли Firebug результирующий набор:

[<TextNode textContent="Some Label 1:">,
 <TextNode textContent="Some Label 2:">, 
 <TextNode textContent="Some Label 3:">, 
 <TextNode textContent="Some Label 4:">, 
 <TextNode textContent="Some Label 5:">]

Кажется, проблема в том, что вызовы .replaceWith (), .replace (), .text () и т. Д., По-видимому, не влияют на коллекцию jquery. Если я позволю вышеупомянутой коллекции содержать один из диапазонов, то вызовы .replaceWith (), .replace () и т. Д. Будут корректно работать с диапазоном, но текстовые узлы останутся такими, как есть.

Ответы [ 4 ]

10 голосов
/ 23 февраля 2010

Попробуйте:

$(".myFieldsetClass label:contains('Some Label ')").contents().filter(':last-child').text("Some Label");

Это должно работать при условии, что заменяемый текст всегда будет в конце. Функция contents() выбирает все узлы, включая текстовые узлы.

http://api.jquery.com/contents/

РЕДАКТИРОВАТЬ: я должен был использовать filter () вместо find (). Исправлено.

РЕДАКТИРОВАТЬ: работает сейчас. Вот один из способов.

// Store proper labels in a variable for quick and accurate reference
var $labelCollection = $(".myFieldsetClass label:contains('Some Label ')");

// Call contents(), grab the last one and remove() it
$labelCollection.each(function() {
    $(this).contents().last().remove()
});

// Then simply append() to the label whatever text you wanted.
$labelCollection.append('some text')
7 голосов
/ 23 февраля 2010

Как отмечает Патрик, вы можете использовать contents(), чтобы выделить только один текст, а затем выполнить замену всего этого. Адаптируя приведенный там пример, вы также можете попробовать:

$(".myFieldsetClass label:contains('Some Label ')").contents().filter(function() {
  return this.nodeType == 3 && $(this).is(":contains('Some Label ')");
})
.replaceWith("Some Label");

Однако, если вы знаете, что «Некоторая метка» всегда будет последним элементом в <label>, то, по-моему, метод Патрика будет быстрее.

2 голосов
/ 23 февраля 2010

Почему бы просто не выполнить полную замену с помощью регулярных выражений?

$(".myFieldsetClass label:contains('Some Label ')")
    .each(function() {
            $(this).html($(this).html().replace(/Some Label ./, "Some Label")); 
        });
0 голосов
/ 08 января 2015

Однострочник:

$('.myFieldsetClass label').contents().last().remove().end().first().after('New Label')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...