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.
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.
$(document).ready(function(){
toggleUsersIconStyle(4);
});
/**
* Toggles the classes fa-solid and fa-user-gear to the <i> tags
* matching this selector ran for each of the entry in the usernames list:
* `.online-users > .user-online > .user-name:contains('${username}') i.fa`
*
* Notes: it's the easiest approach but it relies on :contains so it won't be an exact match.
* Plus it loops the usernames list delegating the elements search to css
*/
function styleUsers(usernames){
debugger;
usernames.forEach(username=>{
//in our dreams this selector should return one element only
//but there's always the chance that multiple usernames have the same root
$(`.online-users > .user-online > .user-name:contains('${username}')`)
.each((i, el)=>{ $(el).siblings('i').toggleClass('fa-solid fa-user-gear') });
});
}
/**
* Toggles the classes fa-solid and fa-user-gear to the <i> tag
* included in all the elements .online-users > .user-online
* if the inner .user-name text content perfectly matches with any
* included in the usernames list passed as argument
*
* Notes: it loops through all the online element and makes the most accurate match
*/
function styleUsersAccurate(usernames){
const users = $('.online-users > .user-online > .user-name');
for(const user of users){
const username = $(user).text();
if(usernames.includes(username)){
$(user).siblings('i.fa').toggleClass('fa-solid fa-user-gear');
}
}
}
/**
* Toggles the classes fa-solid and fa-user-gear to the <i> tag
* hold inside the .user-online element containing the passed username
*/
function styleUser(username){
$(`.online-users > .user-online > .user-name:contains('${username}')`)
.siblings('i')
.toggleClass('fa-solid fa-user-gear');
}
function toggleUsersIconStyle(mode){
if(mode === 1)
//styleUsersAccurate approach
styleUsersAccurate(['Ster','dimitris']);
else if(mode === 2)
//styleUsers approach
styleUsers(['Ster','dimitris']);
else if(mode === 3)
//styleUser approach (styling only the username listed in the array)
['Ster','dimitris'].forEach((username)=>{
styleUser(username);
});
else if(mode === 4)
//styleUser approach (styling every single user existing in the dom)
$('.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>