jQuery transform both existing and dynamically created elements

Viewed 68

Suppose I want to transform all (existing and dynamically created) <a> tags having a data-params property, e.g. by setting the href attribute.

It seems that this code:

$('body').on('change', 'a[data-params]', function() { ... })

only works on dynamically created elements, not existing elements.

On the other hand, this code:

$('a[data-params]').each(function(index) { ... });

only works on existing elements.

So if I want both (existing and dynamically created), I need both codes, ideally defining my transformation function first, then:

$('a[data-params]').each(function(index) { processDataParams(this); });
$('body').on('change', 'a[data-params]', function() { processDataParams(this); });

or am I missing some simpler way to do this?

2 Answers

$('a[data-params]') returns all nodes with this data attribute. Always.

I think that the problem is before, in the creation of dinamic elements. Avoid use the jQuery data method when you add the elements, because it does not update the DOM (don't adds the desired data-params attribute).

// Add some elements to the current doc
['magenta', 'olive'].forEach(color => {
  $('<a>', {html:color})
    // .data('params', color) <-- this don't updates de DOM,  jQuery
    .attr('data-params', color)
    .appendTo('#root')
})

// Element unable to find with $('a[data-params]')
$('<a>', {html: 'This elemnt won\'t update'})
  .data('params', 'purple')
  .appendTo('#root')

function transform() {
  $('a[data-params]').each((i, node) => {
    $(node).css('color', $(node).data('params'))
    $(node).attr('href', '#' + $(node).data('params'))
  })
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div style="display: flex; flex-direction: column" id="root">
  <a data-params='red'>red</a>
  <a data-params='blue'>blue</a>
  <a data-params='green'>green</a>
</div>

<hr>

<button onclick="transform()">Transform Elements</button>

Edited with the corrections of @Spectric and @RokoC.Buljan. Thanks to all.

You can use Jquery Event Delegation to run code (an event listener) on all child (internal) elements of an element, whether or not they already exist (because its set on the parent, which does already exist). You can read more about Event Delegation in JQuery's docs - https://learn.jquery.com/events/event-delegation/

Example:

$('ul').on('click', 'li', function(event) {
//code that will run on al <li> element clicks
});

this code is set on ul element, and allows an event listener to be set for all current and future li elements that are within the ul.

Related