javascript function is reset everytime I call a livewire action - javascript

What I'm trying to do is setting 'active' on the class of the button that was clicked, and on every other button remove the class 'active' if it was present in it, problem is everytime I click the button that isn't active, it gives the attribute 'active' and removes it from the other one for a second and then returns everything to how it was before I clicked.
My view:
<ul class="nav" id="myDIV">
<li class="nav-item active" wire:click="$emit('PaginaPrincipal')">
<a class="nav-link" href="#" onclick="event.preventDefault();" >
<i class="nc-icon nc-icon nc-paper-2"></i>
<p>Página Principal</p>
</a>
</li>
#foreach ($titulos as $titulo)
<li class="nav-item" wire:click="ViewNiveis">
<a class="nav-link" href="#" onclick="event.preventDefault();" >
<i class="nc-icon nc-icon nc-paper-2"></i>
<p>{{ $titulo }}</p>
</a>
</li>
#endforeach
My javascript:
var header = document.getElementById("myDIV");
var btns = header.getElementsByClassName("nav-item");
for (var i = 0; i < btns.length; i++)
{
btns[i].addEventListener("click", function()
{
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
After some trial and error I have found out that if I remove the livewire action that is inside the foreach it stops resetting itself, is there any way to stop it from resetting itself while still keeping my livewire action?
Thanks in advance.
Update:
I have tried other javascript functions online to see if the problem was some confusion between javascript and livewire, but it stills produces the same error.

try btns[i] instead of this in the event listener code.
You could also change the previous code to document.querySelector(‘.active’) instead of selecting all elements with the class name and then using index of 0 to select the first active element.

Related

Toggle class between list elements on click of a button

I need to remove and add a class between elements of a list, if I hit the #swapThumb button it should remove the selected class from the current element and then added to the next element.
Here's what I have
html
<ul id="product-thumbnails" class="thumbnails list-inline">
<li class="vtmb vt-123 selected" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-456" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-789" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-101" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-121" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
</ul>
<button id="swapThumb">Next</button>
javascript
let thumbsNailsList = $('#product-thumbnails').find('li');
let swapButton = $('#swapThumb');
thumbsNailsList.each((index, item) => {
let thumbsAvailable = $(item).attr('style');
if (thumbsAvailable === '') {
$(swapButton).on('click', () => {
$(item).removeClass('selected');
$(item).closest($(item)).next().addClass('selected');
});
}
});
First I'm checking if the li element has an empty style attribute (this is needed), if so, trigger the click validation.
The click should remove the selected class from the first element and then added to the next one and so on (it should match the empty style attribute). Once the selected class hits the last element of the list it should return the class to the first element.
This code snippet will change the class of the element beneath it to selected and remove it from the current one, while keeping all the other classes. It will also loop back to the beginning element if next is clicked when on the last element. I've heard jQuery functions are more expensive that document functions and shouldn't be used for these kinds of things. Apply this to your problem and you should get the expected result
let i = 0;
let thumbsNailsList = document.getElementById("product-thumbnails").children;
let btn = document.getElementById("btn");
btn.onclick = function() {
var prevClasses = thumbsNailsList[i].className;
thumbsNailsList[i].className = prevClasses.replace("selected", "");
i = (i+1) % thumbsNailsList.length;
thumbsNailsList[i].className = "selected";
console.log(thumbsNailsList);
}
<ul id="product-thumbnails">
<li class='selected'></li>
<li class=''></li>
<li class=''></li>
<li class=''></li>
</ul>
<button id="btn">Next</button>

How can I keep class active after refreshing the page (using jQuery)

I have been searching for whole day and found several examples but none of them work correctly. I have a navigation bar and I want to keep class active after clicking on it and refreshing page but it gets lost.
This is my code:
HTML
<li class="sub-menu" style="border-bottom: 1px solid grey;">
<a class="menuItem active" href="#Url.Action("Index", "Administrator")">
<i class="fa fa-th"></i>
<span>Index</span>
</a>
</li>
<li class="sub-menu">
<a class="menuItem normal" href="#Url.Action("Products", "Administrator")">
<i class="fa fa-shopping-cart"></i>
<span>product</span>
</a>
</li>
Javascript
var retrievedObject = localStorage.getItem('classChange');
if (retrievedObject) {
$('.menuItem').addClass(retrievedObject)
}
$(".menuItem").click(function () {
if ($(this).hasClass("normal")) {
$(this).removeClass('normal').addClass('active');
localStorage.setItem('classChange', 'active');
} else {
$(this).removeClass('active').addClass('normal');
localStorage.setItem('classChange', 'normal');
}
});
I expected to change class on active after click but all classes change after click, I understand why it happens but don't know how to fix it.
Can you give each element an id value and, in the function, store in the local storage the id of the element and the class? Then, on reload check for the both id's?
And if you need for more elements you can save an array of the id's and then use it to loop between all id's if necessary.
So something like this:
var ids = ['id1','id2'];
for(i of ids) {
var retrievedObject = localStorage.getItem(i);
if (retrievedObject) {
var id = "#" + i;
$(id).addClass(retrievedObject);
}
}
$(".menuItem").click(function (event) {
if ($(this).hasClass("normal")) {
$(this).removeClass('normal').addClass('active');
localStorage.setItem('classChange', 'active');
} else {
$(this).removeClass('active').addClass('normal');
localStorage.setItem(event.target.id, 'normal');
}
});
The code
if (retrievedObject) {
$('.menuItem').addClass(retrievedObject)
}
should be wrapped on jQuery.ready().

Disable dropdown item with CSS or Javascript

I need to disable, deactivate or at least hide a dropdown item called Private request and I can only use CSS or Javascript to do so.
When I inspect the dropdown item it has the class a.js-dropdown-list. But every item in my dropdown has this class. So I can't just use {display: none;} because it will hide all options. Is there no more specific ID for every item in the drop down or can I deactivate items with Javascript?
Drop Down looks like this:
Here the code (1st block is for the picker field, 2nd for the drop-down menue):
<div id="js-organization-picker">
<sd-select class="js-share-with-organisation-picker is-private" data-type="link" data-id="customfield_10203" data-value="38" data-options="[{"label":"Private request","styleClass":"is-private","icon":"locked"},{"label":"Share with Testorganisation","value":38,"icon":"unlocked"}]" resolved="">
<a id="js-customfield_10203-dropdown-trigger" class="aui-dropdown2-trigger aui-button aui-button-link js-trigger customfield_10203-trigger select-dropdown-trigger aui-alignment-target aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left active aui-dropdown2-active aui-alignment-enabled" aria-controls="customfield_10203-dropdown" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger="" data-dropdown2-hide-location="js-customfield_10203-dropdown-container" resolved="" aria-expanded="true" href="#customfield_10203-dropdown">
<span class="aui-icon aui-icon-small aui-iconfont-locked">
: : before
</span> Private request
: : after
</a>
<input name="customfield_10203" type="hidden" class="js-input" value="">
<div id="js-customfield_10203-dropdown-container" class="hidden"></div>
</sd-select>
</div>
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled" role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" style="z-index: 3000; top: 0px; left: 0px; position: absolute; transform: translateX(602px) translateY(918px) translateZ(0px);" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
E.g. you could give the dropdown item ids to identify them. In HTML this would look like this: <p id="yourIdHere"></p>
You can access this item through Javascript using the document.getElementById() function like this: document.getElementById('yourIdHere').style.display = 'none';
If you can't edit the existing html code, youi have to get the element by it's name/value. This is a bit difficult. You have to iterate through all elements of that type and evaluate each name/value. If you have found the one, you was looking for, you can edit/hide it. You would do so (untested):
var elements = document.getElementsByTagName('div'); //div will be the name of the tag of your elements in the dropdown list
var length = elements.length;
for (var i=0, item; item = elements[i]; i++) {
if(item.value == "Private request") { //"Private request" is the name of the element we are looking for
item.style.display = 'none'; //Hide the element
}
}
You could loot trough all 'js-dropdown-items', check its innerText for 'Private request' and set its parentNodes display-property to 'none':
var list = document.getElementsByClassName('js-dropdown-item');
for(var i = 0; i < list.length; i++){
if(list[i].innerText === 'Private request') list[i].parentNode.style.display = 'none';
}
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
VannillaJS Solution document.querySelectorAll(".aui-list > li")[0].style.display = "none";
Welcome!
If I get you right there are plenty of elements with the same ID js-dropdown-list and you want to hide a specific one and there is no additional class for the element and you're not allowed to add specificity to it, let's say by adding of an additional class, you can do the following:
Grab all elements with this id by:
let elements = document.querySelectorAll('.js-dropdown-list'); // this is an array of these elements
let elementToHide = elements[n] // whene n is the number of that element
//hiding the element
elementToHide.style.display = 'none';
Hope that helps!
NOTE: I believe you will have to actually hide it OR use whatever you are using for this pseudo drop down (there was no reference in the question) to manage the disabled state if it provides that. Reference: https://www.w3.org/TR/2014/REC-html5-20141028/disabled-elements.html
Get the element by its text and then hide it. Might need the parent but this directly answers the question. Note this could all be wrapped in a function and then called from where you wish.
function HideByText(elId, findText) {
let group = document.getElementById(elId).getElementsByClassName('js-dropdown-item');
let found = Array.prototype.filter.call(group, function(el) {
return el.innerText === findText;
});
found.forEach(function(el) {
el.style.display = 'none';
});
return found;// in case you need the elements ref.
}
let foundFiltered = HideByText('customfield_10203-dropdown', 'Private request');
<div id="customfield_10203-dropdown" class="aui-dropdown2 filter-dropdown aui-style-default js-filter-dropdown select-dropdown aui-layer aui-alignment-element aui-alignment-side-bottom aui-alignment-snap-left aui-alignment-element-attached-top aui-alignment-element-attached-left aui-alignment-target-attached-bottom aui-alignment-target-attached-left aui-alignment-enabled"
role="menu" aria-hidden="false" data-id="customfield_10203" resolved="" data-aui-alignment="bottom auto" data-aui-alignment-static="true">
<div role="application">
<ul class="aui-list">
<li>
<a class="js-dropdown-item " href="#">Private request</a>
</li>
<li></li>
<li>
<a class="js-dropdown-item " href="#" data-value="38">Share with Testorganisation</a>
</li>
<li></li>
</ul>
</div>
</div>
Alternate for parent would be:
Change el.style.display = 'none'; to
if (node.parentElement) {
el.parentElement.style.display = 'none';
}
Have you tried using CSS? Not an ideal solution, but it might be better than using JS for this.
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child {
display: none;
}
If you need to hide the first 2 elements, you could do something like:
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child,
#js-organization-picker + .aui-dropdown2 .aui-list li:first-child + li {
display: none;
}

changing the text color according to the active tab

Following my question posted here
Unable to add a background colour to the button in navigation
I have managed to fix my issues and move on with my work, however, an issue I came across was to change the font color of the navigation bar elements according to the active tab. The "currently active" tab is given the correct color through CSS so I'm hoping the CSS part is correct thus leaving the JavaScript part an issue.
var header = document.getElementById("navbar");
var btns = header.getElementsByClassName("topnavbar");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
.active {
text-decoration: none;
color: #4da6ff;
outline: none;
}
<div id="navbar" >
<ul>
<li> <a class="topnavbar active" href="" id="home"title="Home">HOME </a> </li>
<li> <a class="topnavbar" href="" id="movies" title="Movies">MOVIES </a> </li>
<li> <a class="topnavbar" href="" id="theaters" title="Theaters">THEATERS </a></li>
<li> <a class="topnavbar" href="" id="buytickets" title="Buy Tickets Online">BUY TICKETS ONLINE </a> </li>
<li style="float:right"><a class="btn btn-scope1 navbar-btn" id="btn1" href="">TEST YOUR KNOWLEDGE </a> </li>
</ul>
</div>
What have I done wrong?
Check below, i have pasted your exact code, it seems to be working fine, all i did was adding # on your href so that it stays on the same page.
var header = document.getElementById("navbar");
var btns = header.getElementsByClassName("topnavbar");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
.active {
text-decoration: none;
color: #4da6ff;
outline: none;
background: #34495e;
}
<div id="navbar" >
<ul>
<li> <a class="topnavbar active" href="#" id="home"title="Home">HOME </a> </li>
<li> <a class="topnavbar" href="#" id="movies" title="Movies">MOVIES </a> </li>
<li> <a class="topnavbar" href="#" id="theaters" title="Theaters">THEATERS </a></li>
<li> <a class="topnavbar" href="#" id="buytickets" title="Buy Tickets Online">BUY TICKETS ONLINE </a> </li>
<li style="float:right"><a class="btn btn-scope1 navbar-btn" id="btn1" href="">TEST YOUR KNOWLEDGE </a> </li>
</ul>
</div>
I managed to fix it . Like you all said , what I had done was right but the issue was where i tried to use the script tag. I read in an article where it was said that using the script tag inside the <head> tag was correct. But for some reason it seems to give a negative effect. After re used it inside the body tag it worked. Sorry for the trouble caused by me. Thank you for those who took time to help me.

click event bound to the last or first element in the loop

As I googled out the above mentioned issue, I came across some sources saying, the loop finish executing the click thus when clicking on one of the item in the loop only executes the last one. Some sort of javascript closure issue. However I didn't find the solution to my problem.
I'm displaying chats on a page dynamically. So each chat should bind the click event on the dropdown element within it. Each time the dropdown icon is clicked, dropdown should display.
Now when I click on other chats they don't display the dropdown but only the last chat does.
How to solve this?
HTML
<div class="btn-group ckit-btn-group t-lg-mt--lg t-lg-mr--lg" role="group" data-dropdown-wrapper>
<button type="button" class="btn btn-default-o btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-inner-toggle-header>
<i class="fa fa-ellipsis-h"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right" data-dropdown-header>
<li><a href="#" data-view-participants>View Participants</a></li>
<li><a href="#" data-new-participants>Add Participants</a></li>
<li><a href="javascript:void(0);" data-leave-conversations>Leave Conversation</a></li>
</ul>
</div>
SCRIPT
$('[data-inner-toggle]').on('click', function(e) {
console.debug('click');
$(this).closest('[data-dropdown]').css('display', 'block');
});
Tried this based on online reference to overcome the so-called closure issue.
$('[data-inner-toggle]').on('click', function(e) {
console.debug('click');
var oList = $('[data-inner-toggle]');
var aListItems = $('[data-dropdown]');
for(var i = 0; i < aListItems.length; i++) {
var oListItem = aListItems[i];
// Here I try to use the variable i in a closure:
oListItem.onclick = function() {
console.debug(i);
}
}
});

Categories