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?
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 the username
variable.
When document is ready, each username found gets styled like that.
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
and user2
. 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.
$(document).ready(function(){ toggleUsersIconStyle(); }); function styleUser(username){ $(`.online-users >.user-online >.user-name:contains('${username}')`).siblings('i').toggleClass('fa-solid fa-user-gear'); } function toggleUsersIconStyle(){ $('.online-users span.user-name').each((i, username)=>{ styleUser( $(username).text() ); }); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" /> <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>
The problem with your own code is:
$(this:contains('Ster'))
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:
Uncaught SyntaxError: missing ) after argument list
You could work your way around this – if you wanted to – by using:
// we need to wrap this in a jQuery Object to enable
// the use of jQuery methods:
$(this)
// and then we can use filter() to check if the
// <string> is present within the element and
// if so we can then chain further methods:
.filter(':contains("<string>")')
Which gives the following approach:
$(document).ready(function() { $('.online-users span.user-name').each(function() { let userName = $(this).text(); $(this).filter(':contains("dimitris")').prev('i').toggleClass('fa-solid fa-user-pen'); $(this).filter(':contains("Ster")').prev('i').toggleClass('fa-solid fa-user-gear'); }); });
*, ::before, ::after { box-sizing: border-box; font-size: 16px; margin: 0; padding: 0; }.online-users, .user-online { border: 1px solid currentColor; display: grid; gap: 0.25em; padding-block: 0.25em; padding-inline: 0.5em; }.online-users { inline-size: fit-content; margin-block: 1em; margin-inline-start: 1em; }.user-online { grid-template-columns: repeat(2, max-content); }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <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>
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:
$(document).ready(function() { $('.online-users span.user-name').each(function() { let userName = $(this).text(); if ($(this).is(':contains("dimitris")')) { $(this).prev('i').toggleClass('fa-solid fa-user-pen'); } else if ($(this).is(':contains("Ster")')) { $(this).prev('i').toggleClass('fa-solid fa-user-gear'); } }); });
*, ::before, ::after { box-sizing: border-box; font-size: 16px; margin: 0; padding: 0; }.online-users, .user-online { border: 1px solid currentColor; display: grid; gap: 0.25em; padding-block: 0.25em; padding-inline: 0.5em; }.online-users { inline-size: fit-content; margin-block: 1em; margin-inline-start: 1em; }.user-online { grid-template-columns: repeat(2, max-content); }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <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>
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:
// An object mapping user-names to the icons to show for // the given user: const userIcons = { Ster: 'fa-user-gear', dimitris: 'fa-user-pen' } $(document).ready(function() { // selecting the <span class="user-name"> elements within the // '.online-users' element, and iterating over that collection // with the each() method: $('.online-users span.user-name').each(function() { // caching the current user-name, from the text of the current // element and removing leading/trailing white-space with // String.prototype.trim(): let userName = $(this).text().trim(); // accessing the previous <i> element sibling: $(this).prev('i') // and toggling the listed class-names, which uses a // a template literal to always toggle the 'fa-solid' // class-name, and interpolating the result of the // userIcons[userName] expression: .toggleClass(`fa-solid ${userIcons[userName]}`); }); });
*, ::before, ::after { box-sizing: border-box; font-size: 16px; margin: 0; padding: 0; }.online-users, .user-online { border: 1px solid currentColor; display: grid; gap: 0.25em; padding-block: 0.25em; padding-inline: 0.5em; }.online-users { inline-size: fit-content; margin-block: 1em; margin-inline-start: 1em; }.user-online { grid-template-columns: repeat(2, max-content); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <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>
Or, in plain JavaScript:
// As before, an Object used to map the user-specific icon(s) // to a named user: const userIcons = { Ster: 'fa-user-gear', dimitris: 'fa-user-pen' } // an alternative to jQuery's $(document).ready(): window.addEventListener('DOMContentLoaded', ()=>{ // retrieving a NodeList of all <span class="user-name"> elements // within the '.online-users' element, and iterating over that // NodeList with NodeList.prototype.forEach() and its anonymous // (Arrow) function: document.querySelectorAll('.online-users span.user-name').forEach( // passing in a reference to the current Node of the NodeList // over which we're iterating: (el)=>{ // caching the user-name from the current node, and // removing leading/trailing white-space with String.prototype.trim(): let userName = el.textContent.trim(), // caching a reference to the previousElementSibling node: previousSibling = el.previousElementSibling; // if the previous element matches the selector (here: 'i') supplied: if (previousSibling.matches('i')) { // we then use the Element.classList API to add the listed // comma-separated, class-names: previousSibling.classList.add('fa-solid', userIcons[userName]); } }); });
*, ::before, ::after { box-sizing: border-box; font-size: 16px; margin: 0; padding: 0; }.online-users, .user-online { border: 1px solid currentColor; display: grid; gap: 0.25em; padding-block: 0.25em; padding-inline: 0.5em; }.online-users { inline-size: fit-content; margin-block: 1em; margin-inline-start: 1em; }.user-online { grid-template-columns: repeat(2, max-content); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <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>
References:
:contains()
selector . each()
. filter()
. is()
. prev()
. text()
. toggleClass()
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.