Changing pages disables navbar menu on Ruby on Rails - javascript

I have this problem. When the screen width goes below 1024px, the navbar changes to a responsive navbar that activates when a burger menu is clicked, this is made using javascript (it is being correctly compiled, the file is imported in application.js). This functionality works fine, but when I change pages (from home to store for example) it stops working, and I can't find the reason. Here's the code:
/* Javascript file */
document.addEventListener('DOMContentLoaded', () => {
let responsiveMenu = document.querySelector('.responsive-navbar');
let body = document.querySelector('body');
let burgerBtn = document.querySelector('.burger-menu');
let responsiveLinks = document.querySelectorAll('.responsive-menu-links')
burgerBtn.addEventListener('click', () => {
burgerBtn.classList.toggle('cross')
responsiveMenu.classList.toggle('menu-open');
body.classList.toggle('disable-scroll');
responsiveLinks.forEach(link => {
link.classList.toggle('trigger-anim')
})
})
})
/* _navbar.html.erb partial */
<div class="navbar-header">
<div class="navbar-menu">
<%=link_to 'Inicio', root_path%>
ustedes
contacto
sobre mi
<%=link_to 'Tienda', store_path%>
</div>
<div class="burger-menu">
<span></span>
<span></span>
<span></span>
</div>
<div class="responsive-navbar">
<div class="menu-background"></div>
<div class="menu-links">
<%=link_to 'Inicio', root_path, class: 'responsive-menu-links'%>
ustedes
contacto
sobre mi
<%=link_to 'Tienda', store_path, class: 'responsive-menu-links'%>
</div>
</div>
<div class="navbar-items">
<div class="logo">
</div>
</div>
</div>
/* styles */
.trigger-anim {
animation: scaleIn .2s forwards;
}
.menu-open {
width: 100vw !important;
a {
opacity: 1 !important;
}
}
.disable-scroll {
overflow: hidden;
.home-container {
height: 100vh !important;
overflow: hidden !important;
}
}
.cross {
span {
&:nth-of-type(1) {
transform: rotate(40deg) translateY(20px);
}
&:nth-of-type(2) {
transform: translateX(500px);
opacity: 0;
}
&:nth-of-type(3) {
transform: rotate(-40deg) translateY(-20px);
}
}
}

Sounds like you are using Rails with Turbolink so your event needs to be turbolinks:load and not DOMContentLoaded so:
document.addEventListener("turbolinks:load", function() {
// ...
})
From the Turbolinks documentation:
You may be used to installing JavaScript behavior in response to the
window.onload, DOMContentLoaded, or jQuery ready events. With
Turbolinks, these events will fire only in response to the initial
page load, not after any subsequent page changes.
Turbolinks triggers a series of events during navigation. The most
significant of these is the turbolinks:load event, which fires once on
the initial page load, and again after every Turbolinks visit.
Hope that helps.

Related

Keep a parent element the same size before and after conditionally showing a button in it with vue.js

Using vue.js (and quasar framework), I have a card component. When an event is triggered a button at the bottom of the card is shown. When the button appears, the size of the card increases due to the height of the button which is added. I find this ugly and would prefer the size of the card to be the same before and after having a button.
I tried with some <br> before the button is added to compensate for the height difference, but this is clumsy and does not work properly when I animate the appearance of the button with a fade-in e.g.
As the card(s) will contain various content(size), making a fixed size for card will not really work.
How can I have the same size of my card before and after showing the button?
Quick fix: you must know button height before. Then nest it to element with same height achieved with min-height property :
<div id="button-container" style="min-height: /* your button height */">
<button>Hidden yet</button>
</div>
It is not very elegant way. Use it only if you are not able to use visibility: hidden on button, instead of display: none, as #musicformellons suggest in comment.
I think, this example demonstrates your problem:
new Vue({
el: '#app',
data: {
canShow: false
},
methods: {
toggleButton () {
this.canShow = !this.canShow
}
},
created () {
setInterval(function () {
this.toggleButton()
}.bind(this), 500)
}
})
.bordered {
position: absolute;
border: 2px solid black;
}
<div id="app">
<div class="bordered">
<p>Lorem Ipsum, bla, bla, bla...</p>
<button v-if="canShow">I am just troublemaker</button>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
And I think this is the most elegant, "true Vue way" solution. Moreover, with this solution you need not to know button height before...
new Vue({
el: '#app',
data: {
visibility: false
},
methods: {
toggleButton () {
this.visibility = !this.visibility
},
logIt () {
console.log('button clicked')
}
},
created () {
setInterval(function () {
this.toggleButton()
}.bind(this), 1000)
}
})
.bordered {
position: absolute;
border: 2px solid black;
}
.animate-me {
transition: all .4s;
}
.is-hidden {
opacity: 0;
}
<div id="app">
<div class="bordered">
<p>Lorem Ipsum, bla, bla, bla...</p>
<!-- Render it always, but change visibility as needed instead -->
<button
class="animate-me"
:class="{'is-hidden': visibility}"
#click="logIt"
:disabled="visibility"
>
I am just troublemaker
</button>
</div>
</div>
<script src="https://unpkg.com/vue"></script>
You could give the css of the button position: absolute and the card position: relative, and then fiddle around with the bottom; left; top; right; position settings of the button.

How to change the background image "on click" with jQuery?

I'm trying to make animation effect for background, it should listen an event that will change images on click.
For instance, I click Sajo Hapyo it should change the background image.
Main issue is that all images will be having different background-images and I'm really stuck with this.
I used backgroundColor: green in my JS for test, since wanted to check, whether it works or not.
At the final version, the background images will be added and it should change on click with nice jquery UI (effect).
Here is screenshot
Please help me out
Here is my code
HTML
<section id="main-showcase">
<div class="showcase-wrapper">
<div class="left-main col-lg-3 col-md-3">
<div class="shadow-effect"><p class="ottogi">OTTOGI</p></div>
<div class="shadow-effect"><p class="sajo">Sajo Hapyo</p></div>
<div class="shadow-effect"><p class="natura">Natura Bogata</p></div>
<div class="shadow-effect"><p class="maloo">ТОО Малу</p></div>
<div class="shadow-effect"><p class="dongush">Dongsuh</p></div>
<div class="shadow-effect"><p class="may">ООО Май</p></div>
</div>
<div class="right-main col-lg-9 col-md-9">
<div class="inner-container">
<h1>Ottogi</h1>
<h2>Южно - Корейские продукты питания высочайшего качества!</h2>
</div>
<div class="box-container">
<div class="main-wrap">
<div id="main-slider" class="first-slider">
[[getImageList?
&tvname=`goods`
&tpl=`goodsSlider.tpl`
]]
</div>
</div>
</div>
</div>
</div>
</section>
JS
$('button.sajo').click(function () {
$('.right-main').animate({
backgroundColor: 'green',
}, 1500);
});
Actually instead of using the jQuery.animate(). You can simply toggle a class on the same element. It is a good practice to avoid animate() and using css3 animations instead.
codepen
Check the codepen sample here. It will explain how to use it. Instead of using keyframes and all. You can simply obtain it using trnasition.
span {
background-color: red;
padding: 10px;
transition: all 1.5s ease;
color: white;
}
.change-color {
background-color: blue;
}
First of all, I cannot see in the HTML the button where you apply the click event listener. However, I assume this button is located somewhere in your HTML code and what you want to do is change the background image on the main slider by clicking on it. To do so you simply have to do the following:
$('button.sajo').click(function () {
$('.right-main').animate({opacity: 0}, 'slow', function() {
$(this)
.css({'background-image': 'url(your_url)'}) //Change url to your image url
.animate({opacity: 1});
}
});
Note that since you do not specify the exact animation you want, I just provided an example with a fade in animation where opacity goes from 0 to 1. You can change this animation to a different one by changing the content of .animate() and leaving the .css() like i wrote there. Hope this helps!
You can use like that
var imageUrl = your image url
$('button.sajo').click(function () {
$('.right-main').css('background-image', 'url(' + imageUrl + ')');
});
.bgcolor{
animation: colorchange 50s; /* animation-name followed by duration in seconds */
/* you could also use milliseconds (ms) or something like 2.5s */
-webkit-animation: colorchange 50s; /* Chrome and Safari */
}
#keyframes colorchange
{
100% {background: green;}
}
#-webkit-keyframes colorchange /* Safari and Chrome - necessary duplicate */
{
100% {background: green;}
}`
Then add this class to the element you want to change the background of:
$('button.sajo').click(function () {
$('.right-main').addClass('bgcolor');
});

On hover add / remove class - not always working

I'm implementing some animation by adding and removing classes to an element on mouseover and mouseout. I'm using this method as I found using CSS alone was not reliable; the animation would not complete if the mouse exited the element before the animation finished.
So I have the following code:
<div class="one flip-container">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
<!-- back content -->
</div>
</div>
</div>
<script>
jQuery(".flip-container").hover(function () {
jQuery(this).addClass("hover");
},function () {
jQuery(this).delay(2000).queue(function(){
jQuery(this).removeClass("hover");
});
});
</script>
<style>
.flip-container.hover .flipper {
transform: rotateY(180deg);
}
.flipper {
transition: 0.6s;
transform-style: preserve-3d;
position: relative;
}
</style>
This works but sometimes the class 'hover' is not removed, it stays, leaving the element in its animated state. Any idea how to make this more reliable?
Try using mouseenter and then set a timeout function to remove the class that way you wont be adding and removing classes except once each time the mouse enters the area. Also you may want to check to see if the area already has the class to avoid the function from being executed too many times like so:
jQuery(".flip-container").mouseenter(function () {
var el = jQuery(this);
if(!el.hasClass("hover")){
el.addClass("hover");
setTimeout(function(){
el.removeClass("hover");
}, 2000);
}
});
Here is a working fiddle Fiddle Demo

JQuery Hamburger Menu Functions

Below is the script I am trying to write to control two functions when the website's menu button is clicked; it is a hamburger menu that toggles the menu links. The first function shows/hides the menu links and the second fades an element on the page, both activated when the menu button is clicked.
In the first function, I am having trouble creating a delay/fadeIn for the menu links. I need '.navbar-item' to fade in and out when the menu is clicked. In the second function, I need to revert the opacity to 1.0 when the menu is clicked a second time. I can not get any of the effects to occur after the first effect has completed, i.e Menu is clicked to fade in menu links and dim '.values', menu is clicked to fade out menu links and revert '.values' to 100% opacity.
<div class="container">
<section class="header">
<h2 class="title">Title
<li class="client-item"><a class="client-link" href="#"><i class="fa fa-bars"></i></a></li></h2>
</section>
<nav class="navbar" style="display: none;">
<ul class="navbar-list">
<li class="navbar-item"><a class="navbar-link" href="#" target="_top">Contact</a></li>
<li class="navbar-item navbar-link">Store</li>
</ul>
</nav>
<div class="section values">
<div class="container">
<div class="row">
<div class="one-full column">
</div>
</div>
</div>
</div>
// Main Script For Site
$(document).ready(function() {
$('.client-link').click(function() {
$('.navbar').slideToggle("fast");
$('.values').animate({opacity:'0.6'});
});
});
This answer gives how to get simultaneous animations. jQuery's own docs describe slideToggle, including the bits you'd need to set similarly to how animate would need to be set.
I might also point out that there's no reason to separate the animate calls like you have. Since they're triggered by the same thing, they should be called from the same place.
Something like this, I think:
$(document).ready(function() {
$('.client-link').click(function() {
var $this = $(this);
var opening = !$this.data('isOpen');
$this.data('isOpen',opening);
if(opening) {
// opening animations
$('.navbar').slideDown({duration:'fast',queue:false});
$('.values').animate({opacity:1},{queue:false});
} else {
// closing animations
$('.navbar').slideUp({duration:'fast',queue:false});
$('.values').animate({opacity:0},{queue:false});
}
});
});
Though you may be better off moving your animations to CSS and just toggling a class.
You were very close, you have just made some simple mistakes. Here is a JSFiddle gives you a solution to your problem: https://jsfiddle.net/nv1gytrs/1/
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<div class="client-link"></div>
<div class="navbar"></div>
<div class="values"></div>
CSS:
.client-link {
height: 100px;
width: 100px;
border: 2px solid green;
}
.navbar {
height: 100px;
width: 100px;
border: 2px solid red;
}
.values {
height: 100px;
width: 100px;
border: 2px solid blue;
transition: all 1s;
}
.fade {
opacity: 0.2;
}
JS:
// Main Script For Site
$(document).ready(function() {
$('.client-link').on("click", function() {
$('.navbar').slideToggle("fast");
$('.values').toggleClass("fade");
});
});
Of course, all of your HTML and CSS would be unique to what you are trying to accomplish, this is just an example.

Add new animation on transition end

I'm using a script to make content boxes slide from the top upon entry and then slides down upon exit.
It's almost working perfectly however, when you click on the button for content box one, then content box two, then back to one again, one comes in from the bottom instead of the top.
I think I understand why this is happening (because the code runs all in one hit, and thus instead of going from below the viewport, to above the viewport and then into view, it just goes from below into view) but can't figure out how to make it always come in from the top.
HTML:
<div class="slidey slidey1 enter">
Content Box 1
</div>
<div class="slidey slidey2">
Content Box 1
</div>
<div class="slidey slidey3">
Content Box 1
</div>
CSS:
.slidey { top:-100% }
.enter { top:0; transition: all 0.7s ease-in-out; }
.exit { top:100%; transition: all 0.7s ease-in-out; }
jQuery:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(".changer").click(function(){
if ($(".slidey" + $(this).data("slidey")).hasClass("enter")) {
return false
} else {
$(".slidey").removeClass("exit");
$(".slidey.enter").addClass("exit").removeClass("enter");
$(".slidey" + $(this).data("slidey")).addClass("enter");
$(".changer").removeClass("link_change");
$(".changer" + $(this).data("slidey")).addClass("link_change");
return false;
}
});
});
</script>
The page is no longer available to be viewed.
After adding a class your should assign a "transitionend" listener like i.e:
$(".myElement").addClass("transitionClass").on("transitionend", function() {
// Transition ended.
// Do more stuff.
});
I recreated and simplified your HTML, CSS to create this example, so you might want to ignore that part, but focus on the jQ code. Should work even on your page out of the box.
$(document).ready(function(){
var $slides = $(".slidey");
$(".changer").click(function( e ){
e.preventDefault(); // Instead of return false;
var num = $(this).data("slidey");
var $target = $(".slidey"+ num);
$(".enter").not($target) // (not the already active one)
.removeClass("enter") // remove unwanted classes
.addClass("exit") // make it go to bottom
.on("transitionend", function(){ // snap it back to -100% top...
$(this).removeClass("exit"); // by removing the exit class.
});
$target.addClass("enter"); // Animate current down into view
// UL links
$(".changer").removeClass("link_change");
$(this).addClass("link_change");
});
});
*{margin:0;}
html, body{height:100%;}
body{overflow:hidden;}
#navbar{
position:absolute;
bottom:130px;
right:130px;
}
#navbar ul {list-style:none;}
.link_change{
color:fuchsia;
}
.slidey {
position:absolute;
width:50%;
height:90vh;
background:#ddd;
top:-100%;
}
.enter {
top:0;
transition: all 0.7s ease-in-out;
}
.exit {
top:100%;
transition: all 0.7s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="navbar">
<ul id="navlinks">
<li class="changer changer1 link_change" data-slidey="1">home</li>
<li class="changer changer2" data-slidey="2">profile</li>
<li class="changer changer3" data-slidey="3">message</li>
</ul>
</div>
<div class="slidey slidey1 enter">Content Box 1</div>
<div class="slidey slidey2">Content Box 2</div>
<div class="slidey slidey3">Content Box 3</div>

Categories