i have this html code:
<div class="online-users">
online users
<span class="user-online">
<i class="fa fa-circle"></i>
<span class="user-name">Ster</span>
</span>
<span class="user-online">
<i class="fa fa-circle"></i>
<span class="user-name">dimitris</span>
</span>
<!-- ... more users... -->
</div>
this code showing which users are online. I need a code to change the icons "i" before users names. Every user have specific icon.
i have try with this jquery code:
<script>
$(document).ready(function(){
$('.online-users span.user-name').each(function(){
$(this:contains('Ster')).siblings('i').toggleClass('fa-solid fa-user-gear');
$(this:contains('dimitris')).siblings('i').toggleClass('fa-solid fa-user-pen');
});
});
</script>
But nothing change.
Any idea what is wrong with my code?
2
Answers
The main error in your code was using a selector like this:
$(this:contains('Ster'))
You need to pass a string to the jQuery
$
function if you want to return the result of a css selector.I refactored better your code to achieve the desired result, so that there’s a dedicated function to change the style, toggling those fontawesome css classes, of the
<i>
element next to an element containing the username you wish to style.The selector I used to fetch the
.user-name
element containing a given string was:$(`.online-users > .user-online > .user-name:contains('${username}')`)
That’s a template string (and it’s wrapped by upticks instead of single quotes or double quotes). It looks for the element
.user-name
in that defined hierarchy and containing the value hold in theusername
variable.When document is ready, each username found gets styled like that.
…But the painful truth:
Your approach doesn’t play well with every scenario. Consider if you have a list of users where there’s one containing the other like:
user
anduser2
. In that case the:contains
selector will hit twice on the same element and will screw the style because you were toggling the class and not just adding it.EDIT: Later I better factored 4 modes to deal with the problem where one of them doesn’t have issue with usernames sharing the same root.
The problem with your own code is:
The
:contains()
jQuery selector works – as does a CSS Selector – as part of a string, whereas you’ve attempted to couple it to a DOM node (this
), which results in a syntax error:You could work your way around this – if you wanted to – by using:
Which gives the following approach:
JS Fiddle demo.
Or, instead of
filter()
, we could instead use the.is()
method, which returns a Boolean (true
/false
) if the element matches, or does not match, the supplied CSS selector:JS Fiddle demo.
However it’s worth noting that both of the previous approaches require you to code to explicitly check for each user-name, and hard-code those user-names and matching icons into the code. Not only does this require an update to the code each time a user is added, or removed and sets or changes their chosen icon the code itself has to check for every user; this leads to bloated code that’s difficult to maintain.
Instead, I’d suggest the following approach, which requires one Object to be updated (which can be automatically generated on the back-end), and otherwise lets the code handle the checks automatically, this code has explanatory comments in the code:
JS Fiddle demo.
Or, in plain JavaScript:
JS Fiddle demo.
References:
document.querySelectorAll()
.Element.classList
.Element.matches()
.EventTarget.addEventListener()
.NodeList.prototype.forEach()
.String.prototype.trim()
.:contains()
selector.each()
.filter()
.is()
.prev()
.text()
.toggleClass()
.