Сложный селектор JQuery - как выбрать одно произвольное «поколение»? - PullRequest
2 голосов
/ 28 июня 2011

Мы используем платформу, которая создает произвольно вложенные элементы данных HTML, идентифицируемые атрибутом data-type=[some data type]. Каждое из них может содержать поля прямого ввода, а также другие data-type в виде синглетонов или массивов. Единственная грация сохранения структуры вложенности - data-type никогда не будет содержать data-types того же типа на любой глубине.

HTML I должен работать с

<div data-type='project' id='example1'>
  <input name='start-date'/>
  <div data-type='project-lead' id='example2'>
    <input name='department'/>
    <input name='email'/>
    <div data-type='analyst'>      
      <input name='department'/>
      <input name='email'/>
    </div>
    <div data-type='analyst'>      
      <input name='department'/>
      <input name='email'/>
    </div>
    <div data-type='analyst'>      
      <input name='department'/>
      <input name='email'/>
    </div>
  </div>
  <div class="JustToMakeMyLifeMoreDifficult">
    <div data-type='sponsor'>      
      <input name='department'/>
      <input name='email'/>
    </div>
    <div data-type='sponsor'>      
      <input name='department'/>
      <input name='email'/>
    </div>
  </div>
</div>

Проблема селектора

Мне нужен селектор поиска JQuery, который дает мне набор data-type элементов на один data-type уровень ниже заданного объекта:

myData($obj){
  return $obj.find('[data-type]').not([data-type elements further down]);
}

такой, что:

myData($('#example1'))
myData($('#example2'))

соответственно дает результаты jquery:

[project-lead,sponsor,sponsor]
[analyst, analyst, analyst]

Мастера JQuery, пожалуйста, помогите мне. Вы единственные, кто может.

Ответил

Это невозможно с селекторами JQuery. Я обернул очень элегантное решение Патрика ниже в обобщенную функцию JQuery-

(function( $ ){
  $.fn.dataChildren = function(_selector) {
        var iter = this;
        var res = this.children(_selector);
        while ( ( iter = iter.children(':not(' + _selector +')') ).length ) {
                res = res.add(iter.children(_selector));
        }
        return res;
  };
})( jQuery );

Так что:

$('#example1').dataChildren('[data-type]')

Работает как описано выше. Я <3 СО. </p>

Ответы [ 4 ]

2 голосов
/ 28 июня 2011

РЕДАКТИРОВАТЬ 2: Я думаю, это то, что вы ищете:

var el = $('#example1');

var res = el.children('[data-type]');

while ( ( el = el.children(':not([data-type])') ).length ) {
    res = res.add(el.children('[data-type]'));
}

Этот процесс идет рекурсивно глубоко, но рекурсия в любой дочерней ветви останавливается, когда элементнайдено с data-type, поэтому оно продолжается только до тех пор, пока есть ребенок, который не имеет data-type.

Возможно, будет легчеследуйте, если я использую цикл do-while, и раскрутите часть кода:

var el = $('#example1');  // el is the current level
var res = $();            // res holds the result
var data_types;           // holds the children with data-type for the current level

do {
      // from current level, get children with data-type
    data_types = el.children('[data-type]'); 

      // add those to the result set
    res = res.add( data_types );

      // make the current level be the children of the current level that
      //      do NOT have data-type
    el = el.children().not( data_types );

} while( el.length ); // continue as long as the new current level
                      //     has at least one element

.

.

РЕДАКТИРОВАТЬ: Возможно, я неправильно понял одну часть.

Похоже, элемент с data-type может иметь детей, которые также имеют data-type.Если это так, замените селектор следующим образом:

var ex = $('#example1');

var res = ex.find('> [data-type], > * > [data-type]');

Итак, чтобы подвести итог, он говорит, что все 1010 * детей и внуков имеют data-type атрибут.


Оригинальный ответ:

Если я понимаю, вы хотите, чтобы у детей был data-type, а из детей, которые не data-type,Вам также нужно добавить своих детей, которые data-type.

var ex = $('#example1');

var res = ex.find('> [data-type], > :not([data-type]) > [data-type]');

. Используются multiple-selector [документы] .

Первый селектор:

'> [data-type]'

... который получит потомков с атрибутом data-type.

Второй селектор:

'> :not([data-type]) > [data-type]'

... который сначала получит детей, которые имеют , а не , имеют data-type, но из них, они получат своих детей, которые имеют , имеют data-type.

Это похоже на то, что вы хотите?

1 голос
/ 28 июня 2011

Функция POJS, которая делает то, что вы хотите, и возвращает массив соответствующего элемента:

function getNodes(id) {
  var el = (typeof id == 'string')? document.getElementById(id) : id;
  var result = [];
  var node, nodes = el.childNodes;
  var prop = 'data-type';
  var tag = 'div';

  for (var i=0, iLen=nodes.length; i<iLen; i++) {
    node = nodes[i];

    if (node.tagName && node.tagName.toLowerCase() == tag) {

      if (node.getAttribute(prop)) {
        result.push(node);

      } else {
        result = result.concat(getNodes(node));
      }
    }
  }
  return result;
}

Однако я не уверен, что вы хотите, чтобы он пошел так глубоко, как этот.Его можно изменить, чтобы он доходил только до определенной глубины (скажем, одного или двух уровней).

0 голосов
/ 28 июня 2011
$obj.children().map(function () {return this.name;})

возможно?

0 голосов
/ 28 июня 2011

Это

$obj.find('> [data-type]');

должно работать, если я правильно понял вашу проблему.

Селектор '> [data-type]' означает "дать мне все элементы, для которых определен тип данных и которые являются непосредственными потомками".контейнера.

...