How to change shared state in Alpine.js? - javascript

I'm trying to hide multiple elements inside the DOM by changing shared state when window is resized.
<body class="font-body relative" x-data="{hideOnMobile:false}">
<section class="mt-5" :class={'section' : !hideOnMobile , 'hidden' : hideOnMobile}">
...
</section>
</body>
And when i try to
window.onresize = function (event) {
let data = document.querySelector('[x-data]');
if (window.innerWidth > 639) {
return data.__x.$data.hideOnMobile = true;
}
};
It should change the state ** hideOnMobile** to true but it doesn't somehow any idea?

Have you tried using #resize.window? (ie. adding the resize listener using Alpine.js) it should make your code simpler than using window.onresize + trying to update Alpine.js __x.$data internal.
<body
class="font-body relative"
x-data="{hideOnMobile:false}"
#resize.window="hideOnMobile = window.innerWidth > 639"
>
<section class="mt-5" :class={'section' : !hideOnMobile , 'hidden' : hideOnMobile}">
...
</section>
</body>

You have no space before x-data attribute. Try to change this line:
<body class="font-body relative"x-data="{hideOnMobile:false}">
to this:
<body class="font-body relative" x-data="{hideOnMobile:false}">

Looks like this is used as an example in the AlpineJS readme. Check this out:
.window modifier Example:
<div x-on:resize.window="isOpen = window.outerWidth > 768 ? false : open"></div>
Adding .window to an event listener will install the listener on the
global window object instead of the DOM node on which it is declared.
This is useful for when you want to modify component state when
something changes with the window, like the resize event. In this
example, when the window grows larger than 768 pixels wide, we will
close the modal/dropdown, otherwise maintain the same state.

Related

Vue 3 - Always scroll to specific position on page when component appears

I have a basic form component and that shows up once I click a button (router is not used). I want the scroll position of the form to scroll down a bit (ex. y-axis of 40) once the form shows up, but I'm not entirely sure how to achieve this. There are various examples about this, but I couldn't get any of them to work. Can someone kindly advice a solution for this, please? I also started using vue 3.
<template>
<div class="appointment-wrapper" :class="[showForm ? 'appointment' : 'appointment-success']">
// Scroll down to a certain point
// ....
<form #submit.prevent="validateForm" novalidate>
// ....
</form>
</div>
</div>
</template>
If you need to scroll to an element position
document.getElementById(el).scrollIntoView();
Or if you need to scroll by the axis
window.scrollTo(0, 1000)
you can use window.scrollTo(0, 40) if the condition is true after you clicked the button.
Vue.createApp({
data() {
return {
showForm: true
}
},
mounted() {
if (this.showForm) window.scrollTo(0, 400) // only demo value - use 40
}
}).mount('#options-api')
#options-api {
height: 1000px;
}
<script src="https://unpkg.com/vue#next"></script>
<div id="options-api">
<h1>hidden title</h1>
</div>

resize event not triggered on div

Take a look at this example: https://jsfiddle.net/vxun2Lgg/2/
I've attached an "resize" event listener on container div. After opening up dev tools, and modifying the width of container, resize callback does not get called. What am I missing?
PS:
I am not interested in window resize event, only in container div.
var container = document.getElementsByClassName("container")[0];
container.addEventListener("resize", function() {
console.log("resizing")
});
<div class="container"></div>
resize is only valid for the window. If supported you can use ResizeObserver.
new ResizeObserver(() => console.log("resizing")).observe(container);
Otherwise, you will probably have to poll using setInterval and check the size.
This answer extends the accepted answer by providing a runnable code in pure JavaScript that you can try on the snippet runner (button at the bottom). I kept the explanations directly on the code.
Believe or not, you only need a 3-line function (the onresize function) to simulate the resize event.
Enjoy it!
// This function works like an Event Listener for
// resizing a dom element.
//
// The ResizeObserver calls the callback function
// whenever the size of the dom_element changes
// (because it's "observing" the dom_elem)
//
// Do this:
//
// understand_it_first
// .then(copy_it)
// .then(use_it);
//
// THIS IS THE 3-LINE FUNCION YOU WANT TO USE :)
//
const onresize = (dom_elem, callback) => {
const resizeObserver = new ResizeObserver(() => callback() );
resizeObserver.observe(dom_elem);
};
// USING IT
//
// Using constants to make it easier to read the code
//
const bb = document.getElementById('bad_boss');
const be = document.getElementById('bad_employee');
// Finally, register the observer for the dom_elem
//
onresize(bb, function () {
be.style.width = bb.offsetWidth + 'px';
be.style.height = bb.offsetHeight + 'px';
});
#bad_boss, #bad_employee{
font-size : 32px;
height : 200px;
width : 200px;
}
/* Colors that Talk*/
#bad_boss {
background-color : #0badb055;
}
#bad_employee {
background-color : #0b00c0de;
color : #0badc0de;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ResizeObserver - onresize Demo</title>
</head>
<body>
<!-- Experiment to resize this <textarea> -->
<textarea id="bad_boss">Always do whatever I say!</textarea>
<div id="bad_employee">Always, Boss!</div>
</body>
</html>
I don't think you can.
https://developer.mozilla.org/en-US/docs/Web/Events/resize
It is still possible to set onresize attributes or use addEventListener() to set a handler on any element. However, resize events are only fired on (sent to) the window object (document.defaultView). Only handlers registered on the window object will receive events.
What's the end goal? There is probably an alternative.
You can use getBoundingClientRect() on an element. I have included a code sample that uses polling to get the width of a div element and output the result.
let demo = document.getElementById('demo');
let demoInfo = document.getElementById('demo-info');
setInterval(() => {
let demoSize = demo.getBoundingClientRect();
demoInfo.innerHTML = demoSize.width;
}, 500);
*{
box-sizing: border-box;
}
#demo{
display: flex;
width:50%;
background-color: red;
padding: 50px;
}
<div id="demo">Demo Div Element</div>
<p id="demo-info"></p>

Check if window height is greater than div#content height in AngularJS

I'd like to add css styles (position: fixed) to footer only if window.height is greater than height of div with main content.
In my solution (below) the condition is always true, so it dosn't work as I expect. Moreover I'm not sure if I used $scope.$watch in right way to control window height - I don't want to press f5 every time when I change page (eg. form home page to contact page) to refresh scope and apply additional styles.
I've found similar topics (eg. Forcing footer to bottom of page, if document height is smaller than window height ) but nothing for AngularJS
I'm using AngularJS 1.6.
This is my code:
controllersFooter.controller( 'footer' , [ '$scope' , '$window' , function( $scope , $window ){
var $footer = angular.element(document.querySelector('#site-footer'));
$scope.windowHeight = jQuery( window ).height();
$window.onload = function() {
$scope.$watch(function(){
var contentHeight = document.getElementById('content-container').scrollHeight;
return contentHeight;
}, function(value){
var contentHeight = value;
if ( contentHeight < $scope.windowHeight ) {
$footer.css(
{
"position":"fixed",
"bottom":0,
"left": 0,
"right": 0
}
);
}
});
}; }]);
You can use ng-class in the footer with a scope variable and make it true or false according the height of the page
More about ng-class
https://docs.angularjs.org/api/ng/directive/ngClass
1
Please make sure that the document body has a scroll.
Just it can be any other div with overflow: auto... you expect that it will be document.body, but that is not always true
2
I advice you to just subscribe to scroll event on element with scroll-bar, like:
jQuery( elementWithScrollBar ).scroll(function() {
$scope.fixed = calculateIfFooterIsFixed();
$scope.$digest(); // run angular digest cycle to reflect scope changes to DOM,
// most likely you will need it
});
Event on windows resize is available natively in angularjs.
angular.element($window).on('resize', this.onResize);
In your case for example sth like that:
var footerHeight = document.getElementById('side-footer').scrollHeight;
this.onResize = function() {
var contentHeight = document.getElementById('content-container').scrollHeight;
$scope.$apply(function() {
$scope.isFixed = contentHeight > $window.innerHeight - footerHeight
});
}
and use ng-class:
<div id="side-footer" ng-class="{'fixed': isFixed}">
Position "fixed" when main content is smaller than visible window:
https://jsfiddle.net/UncleGoogle/jpy4zse9/25/
(for some reason need to run twice to set fiddle footer size properly)

set waypoint if statement if cannot access body element

I created this function to set a waypoint to fire if the following conditions are met. however on the main build I cannot access it like this due to it being built with Angular and the "header" section stays the same, so the body id and class cannot be changed.
I tried adding a div with the id="home" currently associated with the body tag but this does not work. any ideas how i could solve this dilemma?
var windowWidth = $(window).width();
function myWayPoint() {
// Search form stick to top using waypoints.js
if(windowWidth > 768 && $('body').attr('id') == 'home'){
var sticky = new Waypoint.Sticky({
element: $('.thm-search')[0],
offset: 54
});
}
}
myWayPoint();
Try like this.
<div id="home"></div>
Replace $('body').attr('id') WIth
$("body").find('div').attr('id')
JS
function myWayPoint() {
// Search form stick to top using waypoints.js
if(window.innerWidth; > 768 && $("body").find('div').attr('id') == 'home'){
var sticky = new Waypoint.Sticky({
element: $('.thm-search')[0],
offset: 54
});
}
}
myWayPoint();

How to change id of div element when browser resize?

I have this code
<div id="123"></div>
i want to change the id to 234 when the browser resized
<div id="234"></div>
I have use media query , but i think it is not possible
#media screen and (max-width: 479px) {
#123 {
}
}
You can do this easily with javascript or jQuery.
Here a example written in JS.
window.onresize = function(){
var div = document.getElementById("aaa");
if(div){
div.setAttribute("id", "bbb");
}
}
#aaa {
font-size: 10px;
}
#bbb {
font-size: 10em;
}
<div id="aaa">Resize</div>
Im not sure what you are trying to do but this can be solved with window.onresize
You generally shouldn't be changing your element IDs around but if you want to you will need some logic in the onresize function to deduce which ID your element will have when you resize your window.
You're right! It's not possible to do with CSS, but it can be possible to do with JavaScript &/or jQuery. Try this using jQuery:
$(window).on('resize',function() {
$('#123').attr('id','234');
});
The problem with the code above, is that it's a 1x only change. You could never re-target that id after the first resize. So after the browser detects that it has been resized by 2-3 pixels, then the JS will break.
The real question is, why would you want to change an id on resize? It would be better to change an HTML 5 data-* attribute, like: data-id. This allows you to be able to change it repeatedly, using the #myUniqueId attribute. Then your code should continue to run continuously, for as long as the window is being resized.
Here is a jsfiddle for this code:
HTML:
<div id="myUniqueId" data-id="123"></div>
<div id="output"></div>
jQuery:
$(window).resize(function() {
var id = $('#myUniqueId').attr('data-id');
id++;
$('#myUniqueId').attr('data-id',id);
// Double check: what is my id?
var myId = $('#myUniqueId').attr('data-id');
$('#output').html(myId);
});
I use similiar code so you can use different css for mobile or desktop... However it completely irritates me.
This way you use the same id or class. But depending on screen size it will do something different.
#media not all and (min-width:999px){
/* Big Screen */
body {background-color:green; }
#id { background-color:red}
}
#media all and (min-width:1000px)
{
/* Smaller Screen */
body {background-color:blue; }
#id { background-color:grey}
}
Notice how when you manually re size the screen with your mouse the color changes....to the smaller css automatically.
No jQuery answer
window.onresize = function(event) {
if(document.getElementById('123') != null)
document.getElementById('123').id = '234';
};
Just be careful id 234 is not assigned to another element, however you should not be changing your id for changing styles as it should be done by adding and removing css classes.
I hope this one work for you.
//detect window resize
$(window).resize(function() {
//test if window width is below 479
$(window).width() < 479 ? small() : big();
//small function is called when window size is smaller than 479
function small(){
//edited from $( "#id_changer" ).append( "<div id='123'>123</div>" );
document.getElementByID('id_changer').innerHTML = "<div id='123'>123</div>";
}
//big function is called when window size is bigger than 479
function big(){
//edited from $( "#id_changer" ).append( "<div id='234'>234</div>" );
document.getElementByID('id_changer').innerHTML = "<div id='234'>234</div>";
}
});
<body>
<div id="id_changer"></div>
</body>
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<script src="test.js"></script>

Categories

Resources