Materialize CSS: How to prevent default behaviour for Collapsibles? - javascript

I want to use a Materialize CSS collapsible list for steps in an import process.
The next step's details will only be visible when the first step is completed, so I want to disable collapsing the panel when clicking it and manually trigger the event when the first step is completed.
I have tried onclick="return false;" but it is not working.
Any other ideas?

Turn off the event handlers for the collapsible.
Set css property 'pointer-events' to 'none' if you want the default cursor.
var $panel_headers = $('.collapsible').find('> li > .collapsible-header');
$('.collapsible').off('click.collapse', '.collapsible-header');
$panel_headers.off('click.collapse').css('pointer-events', 'none');
You can then display the panels by setting the 'display' property to 'block';
$('.collapsible-body').css('display', 'block');
This example applies to all the collapsible items on your page to demonstrate.
Modify the selectors to manipulate specific collapsibles.

The way I did this is to not initialize the collapsible at all and manually control when the collapsible-body is displayed.
For example here how you would control a collapsible using a switch (with Vanilla JS):
const addEmailCCSwitch = document.getElementById("add-email-cc-switch")
addEmailCCSwitch.addEventListener("click", (e) => {
const isChecked = addEmailCCSwitch.querySelector('input').checked;
if (isChecked) {
document.querySelector('.collapsible-body').style.display = "block"
} else {
document.querySelector('.collapsible-body').style.display = "none"
}
});
Here is a codepen with the functional example: https://codepen.io/dsudomoin/pen/zYBeYyW

Related

Simplifying Active States

I have a question that I believe comes down to method preference.
In the following code when the div parent element is clicked on, the div itself expands and also triggers an icon animation
var slideSection6 = document.getElementById("manualsHandbooks").addEventListener("click", function()
{
if (this.parentElement.style.height == "60px" || this.parentElement.style.height == "")
{
this.parentElement.style.height = "215px";
document.getElementById("MAHB").classList.add("active");
}
else
{
this.parentElement.style.height = "60px";
document.getElementById("MAHB").classList.remove("active");
}
}, false);
I was thinking about how easy it was just to add a class and change the state of the icon and I wanted to experiment and try adding the another click event just to the icon to make it animate on a click and active the parent element in the div as well. Basically the reverse of the above.
I thought it would be as simple as adding another condition to the if statement to the effect of
|| document.getElementId("MAHB").classList.add=("active") == true
But this doesn't work and I know it's not proper form. Could someone get me started so I could figure this out?
Element.classList has a toggle method that could make things a bit easier. If you want to check if a certain class is present, you can also use classList.contains.
I'd suggest not using the height of your elements to determine their current state. Why don't you alter the height using an active css class?
Your click handler could then be:
var button = document.getElementById("manualsHandbooks");
button.addEventListener("click", function() {
this.parentElement.classList.toggle("active");
document.getElementById("MAHB").classList.toggle("active");
}, false);
You can read more about classList here: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList

JQuery/ Jquery Mobile - best way to remove instance of class from div by toggling

I'm using JQuery mobile framework here, so i've got two 'pages' which in reality both exist in one HTML document. You can navigate between the two via the hamburger menu icon on the top left.
There is an events page. each events has an 'add to favourites' button. when clicked the event populates the favourites page. I'm doing this by cloning the div class.
var add = $('.add-to-fav');
add.on('click', function(){
//change button status
if ($(this).text() == "Add to favourites")
{
$(this).text("Remove from favourites");
$(this).closest(".event-block").clone().appendTo('#fav-list');
} else {
$(this).text("Add to favourites");
//get this instance of event block and remove from #fav-list
}
});
My issue comes with trying to remove (or unfavourite) the event by clicking again on the same button. I want this to be achievable from both the events page and the favourites page.
What's the most elegant way to achieve this?
here's a codepen - i've tried to remove as much unrelated code as possible
http://codepen.io/MartinBort/pen/EajBXB/
First of all, you are using the same panel for both pages with same ID. Either use an external panel or give each one a unique ID. If you plan to use an external panel, place it outside any page and initialize it manually.
$(function () {
$("#menu-panel").panel().enhanceWithin();
});
To add listeners, use pagecreate it fires once per page. This way, you can assign different functions for buttons based on containing page. Use event.target to target buttons .add-fav within created page not other ones in DOM.
You can remove "Event" from favourites page from public-events page by retrieving its' header's text since you aren't using IDs' or classes to differentiate between events.
$(document).on("pagecreate", "#public-events", function (event) {
$('.add-to-fav', event.target).on('click', function () {
if ($(this).text() == "Add to favourites") {
$(this).text("Remove from favourites");
$(this).closest(".event-block").clone().appendTo('#fav-list');
} else {
$(this).text("Add to favourites");
/* retrieve event title */
var eventTitle = $(this).closest(".event-block").find("h2").text();
/* loops through event blocks in favourite page */
$('#favourites #fav-list .event-block h2').each(function () {
if ($(this).text() == eventTitle) {
/* remove matching event */
$(this).closest(".event-block").remove();
}
});
}
});
}).on("pagecreate", "#favourites", function (event) {
$('.add-to-fav', event.target).on('click', function () {
$(this).closest(".event-block").remove();
});
});
Demo

implement jquery show / hide toggles without accessing markup

I'm seeking a better way to rewrite a simple show / hide jQuery toggle that could allow implementation based on using div selectors; and without modifying HTML markup (so without added class .hidden etc)
I have a series of divs with class .djseform_field and no other selectors within; seeking to use only this class to turn these divs into show / hide jQuery toggles.
possibly something like this:
$(document).ready(function() {
// choose text for the show/hide link
var showText='read more...';
var hideText='hide';
// initialise the visibility check
var isVisible = false;
// append show/hide links to the element directly preceding the element with a class of "djseform_field"
$('.djseform_field').prev().append(' '+showText+'');
// hide all of the elements with a class of 'djseform_field'
$('.djseform_field').hide();
// capture clicks on the toggle links
$('a.toggleLink').click(function() {
// switch visibility
isVisible = !isVisible;
// change the link depending on whether the element is shown or hidden
if ($(this).html()==showText) {
$(this).html(hideText);
}
else {
$(this).html(showText);
}
// toggle the display
$(this).parent().next('.djseform_field').slideToggle('slow');
// return false so any link destination is not followed
return false;
});
});
Your jquery should look like :
$(document).ready(function() {
$('.toggle-div').click(function(){
$('.djseform_field').slideToggle( "slow", function() {
});
});
Your Html should :
<div class="djseform_field">111</div>
<div class="djseform_field">222</div>
<div class="djseform_field" >333</div>
toggle <!-- Whatever you want to on click hide / show divs for refs i used a tag -->

use intro.js on bootstrap dropdown element

I cannot figure out how to use intro.js on dropdown elements.
I found a similar question with no answer there: IntroJS Bootstrap Menu doesnt work
If you want to reproduce the error, follow these steps:
http://recherche.utilitaire.melard.fr/#/carto
You have to click on "Aide" (The green button on the top right), the problem occurs for the second step. on the change event, I do:
$scope.ChangeEvent = function (e) {
if (e.id === 'step2') {
document.getElementById('step1').click();
}
console.log("Change Event called");
};
When debugging, everything is working like a charm until that function end: _showElement
After that, I get lost in JQuery events, and the dropdown is closed...
If you want to reproduce, just add a breakpoint at the end of the _showElement function and you will understand what I mean...
Here a clearer solution
function startIntro(){
var intro = introJs();
intro.setOptions({
steps: [
{
element: "#mydropdown",
intro: "This is a dropdown"
},
{
element: '#mydropdownoption',
intro: "This is an option within a dropdown.",
position: 'bottom'
},
]
});
intro.onbeforechange(function(element) {
if (this._currentStep === 1) {
setTimeout(function() {
$("#mydropdown").addClass("open");
});
}
});
intro.start();
};
$(document).ready(function() {
setTimeout(startIntro,1500);
});
Note the setTimeout with no second argument (milliseconds) allows you to queue the function on event loop and run it after all events were processed (including the click closing the dropdown), also, it is better to add the class open to the dropdown if you want to set it to open state
In your template i.e. in
/views/nav/body-create.html
You have a code where ng-disabled is based on !currentPath.name. And the value of currentPath.name is null. Try inspecting the value on the following element. You will see that it is null.
<button class="dropdown-toggle btn btn-sm btn-default no-radius" ng-disabled="!currentPath.name">
Niveau{{currentPath.level?": "+currentPath.level:""}} <strong><b class="caret"></b>
</strong>
</button>
Make sure you have proper name or use different condition - I am not sure what you are trying to do with the condition.
Proof: Inspect the above element in chrome debugger at your recherche.utilitaire.melard.fr/#/carto link. Type the following in console and hit enter.
$scope.currentPath.name='Hello You';
And your "Niveau" menu starts working.
I found a workaround, it's quite ugly, but does the job:
$scope.ChangeEvent = function (e) {
if (e.id === 'step2') {
document.getElementById('step1').click();
setTimeout(function () {
document.getElementById('step2').style.display = 'block';
}, 500);
}
console.log("Change Event called");
};
I set the display attribute to block just after the click event I added in the change event
When clicking executing the click on the element 1, I noticed that jquery set the state of the style.display of the element 2 to '', so I wait a bit after clicking in order to set it back to 'block', I know it's ugly, but I didn't find anything better at the time
This happens because of the fixed position..
By using CSS, change the position for the parent item from fixed to absolute and it works perfectly.
For example:
position of .sidebar is fixed, leave it like that.
change position for .sidebar.introjs-fixParent to absolute.
Hope it helps you

Jquery Content Slider: Add an error class to a navigation menu that corresponds to empty section

I have a form that is broken up into a Jquery Content slider (i.e. vertical tabs).
This breaks the form into manageable chunks for the user to fill in.
At the moment, if the user forgets to fill in a field, an error class is applied to that section of the form. However, if that section is not visible, the user won't see the error styling.
I want to add the error class to the corresponding part of the vertical tab navigation menu. How can I do this?
The Jquery code that is used to flip between the sections is as follows:
$(".taptabs li").live('click', function() {
$(this).parent().parent().parent().$('.pages .page').hide().eq($(this).index()).show().addClass("animated").addClass(mode).addClass("fadeInLeft");
});
(Taptabs is the name of the navigation list. Each section of the form has a class of page Each section is also in the HTML element of <section> ).
I thought this would work to make the error message appear on the navigation:
$(".changing-room").submit(function () {
var isFormValid = true;
$("input.required").each( function () {
if ( $.trim( $(this).val() ).length === 0 ) {
$(this).parent().addClass("error");
var menulink = $(this).closest('section').index();
$('.tapnav li').index(menulink).addClass('error');
isFormValid = false;
}
});
});
In this code, when an Input is left empty, the closest Section tag is located (This section tag holds that particular section of the form). The index of that section tag is calculated and then it is applied to the corresponding LI of the Nav menu. However, it doesn't seem to work, it actually breaks all the code!
Here is a JS Fiddle
Two possibilities I guess. One is you don't let them go to the next tab until they finished their work on the current tab. That's option #1 below. Option #2 as you state is to style the tab somehow so they can see they need to return to it. See #2 below.
#1:
In your click event (use .on() not .live()) wrap the containing code in this:
if(!$('.error').length){
//All the code you have in your event now should be here - that is, there are no errors they can proceed.
} else {
//else is optional. Here you could do whatever you want to tell the user - "no, you can't move on because you have a validation issue. Here is a suggestion:
alert('You have errors! ' + someerrorvar);
}
#2
Again, as above use a .on() event instead of .live() because .live() is no more.
I'm going to make an assumption that there's a class that indicates a certain tab is the active tab. We'll call that class 'tater' for lack of a true class name. If so, just use that thusly:
//At the beginning of your event, before you pull the switch
$('.tater').addClass('incomplete');
Then use incomplete to style that tab as desired.
Final Thoughts:
I would go with #1. It's clear to the user that, hey, something's not right here and we need to fix it. Be sure and put the validation text clearly in the user's face.
I figured this out:
$(".MY-WRAPPER-CLASS").submit(function () {
var isFormValid = true;
$("input.required").each(function () {
if ($.trim($(this).val()).length === 0) {
$(this).parent().addClass("error");
var menulink = $(this).closest('section').index(); //Note 1
$('.tapnav li').eq(menulink).addClass('error'); //Note 2
isFormValid = false;
}
else {
$(this).parent().removeClass("error");
}
});
});
Note 1: We use .closest() to find the parent <section> tag of the empty form element.
We then use .index() to find the index value of the section.
It is then assigned to a variable called menu link.
Note 2: We then use .eq() to target the menu link that has the same index value as the section.

Categories

Resources