I'm trying to build a tab navigation bar like the example below (copied from Ionic docs) with Angular Material. Each of these tabs will lazy load different pages.
To lazy load pages on each tab, the doc suggests using nav mat-tab-nav-bar component. However, this component presents the tabs bar at the top of the page and I need this bar at the bottom of it.
As in the docs, the mat-tab-group has this attribute called headerPosition that can be used to position the tab bar at the bottom of the page, but it doesn't work on the nav mat-tab-nav-bar component.
Can anyone help me either create a tab that can open pages/components in lazy mode with mat-tab-group or position the nav mat-tab-nav-bar component at the bottom of the page?
Currently my component is:
tabs.page.html
<nav mat-tab-nav-bar headerPosition="below" >
<a mat-tab-link *ngFor="let page of pages" (click)="activePage = page.path" [active]="activePage == page.path"> {{ page.label }} </a>
</nav>
<router-outlet></router-outlet>
tabs.page.ts
// ...
export class TabsPage implements OnInit {
readonly pages = [
{
path: 'page1',
label: 'Page 1',
},
{
path: 'page2',
label: 'Page 2',
},
];
activePage = this.pages[0].path;
constructor() { }
// ...
}
Heres the sample.
.page-container {
background-color: #f8f9fa;
padding: 10px;
width: 90%;
min-width: 378px;
}
.parent-container,
.d-flex {
display: flex;
}
.child-centered,
.m-auto {
/* Magic! */
margin: auto;
max-width: 430px;
min-width: 220px;
}
div#topdiv, div#bottomdiv{
position:fixed;
left: 0px;
width: 100%;
color: #CCC;
}
div#topdiv{top:0px;}
div#bottomdiv {bottom:0px;}
<div class="parent-container">
<div class="child-centered">
<router-outlet>
</router-outlet>
<div style="height: 150px;"> </div>
<footer id="bottomdiv" class="parent-container">
<nav mat-tab-nav-bar class="child-centered mat-tab-group-inverted-header main-nav" >
<a mat-tab-link style="height: 80px; width: 40px;" *ngFor="let link of navLinks"
routerLink="{{ link.location }}" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">
<div style="padding: 10px;">
<mat-icon class="example-tab-icon">{{ link.icon }}</mat-icon>
<div>{{ link.label }}</div>
</div>
</a>
</nav>
</footer>
</div>
</div>
Related
The following importmap had to have the entry for stimulus commented out
pin "application", preload: true
pin "#hotwired/turbo-rails", to: "turbo.min.js", preload: true
# pin "#hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "#hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "trix"
pin "#rails/actiontext", to: "actiontext.js"
in order to run the following HTML behaviour with CSS using a link target
<div class="thumb-wrapper">
<a href="#img1">
<img src="https://unsplash.it/800/400?image=17" class="thumbnail_lb">
</a>
<a href="#img2">
<img src="https://unsplash.it/800/400?image=13" class="thumbnail_lb">
</a>
<a href="#img3">
<img src="https://unsplash.it/800/400?image=3" class="thumbnail_lb">
</a>
</div>
<!-- lightbox container hidden with CSS -->
<a href="#" class="lightbox" id="img1">
<img src="https://unsplash.it/800/400?image=17">
</a>
<a href="#" class="lightbox" id="img2">
<img src="https://unsplash.it/800/400?image=13">
</a>
<a href="#" class="lightbox" id="img3">
<img src="https://unsplash.it/800/400?image=2">
</a>
stylesheet
.thumbnail_lb {
max-width: 80px;
margin: 1em;
float: left;
}
.lightbox {
display: none;
position: fixed;
z-index: 999;
width: 100%;
height: 100%;
text-align: center;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
}
.lightbox img {
max-width: 90%;
max-height: 80%;
margin-top: 2%;
}
.lightbox:target {
outline: none;
display: block;
}
.thumb-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
with stimulus enabled, the browser inspector shows the hidden container being highlighted as its source wrapper is clicked upon, but nothing happens in the browser. Reloading the browser with say #img3 generates the overlay,but clicking on it does not return to the page overlay-less.
stimulus is entirely geared around targetting. I have not found documentation indicating that CSS-targetting HTML would be impeded by the presence of this library, although I may have missed it.
How can CSS-driveng taargetting co-exist with stimulus?
I don't know about stimulus, but turbo intercepts click events and does it's own url fetching, and it looks like it doesn't play well with # urls.
You can disable turbo around the lightbox links:
<div data-turbo="false">
<!-- lightbox code -->
</div>
https://turbo.hotwired.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms
or you can bypass turbo navigation by catching click events first:
// for any clicks
document.addEventListener("click", e => {
const target = e.target.closest("a[href^='#']")
if (target) {
// this is what Turbo does, normally, which doesn't work.
// Turbo.visit(target.href)
window.location = target.href // bypass Turbo navigation
e.preventDefault();
}
})
// for link clicks
document.addEventListener("turbo:click", e => {
if (e.target.matches("a[href^='#']")) {
e.preventDefault();
}
})
https://turbo.hotwired.dev/reference/events
I have a bootstrap 5 menu outside the canvas and I want to change the hamburger icon when closing and opening the menu so that a cross and the hamburger appear, but I can't do it
<nav id="main-nav" class="navbar navbar-expand-md navbar-dark bg-primary nav-menu-
home" aria-labelledby="main-nav-label">
<h2 id="main-nav-label" class="screen-reader-text">
<?php esc_html_e( 'Main Navigation', 'understrap' ); ?>
</h2>
<div class="<?php echo esc_attr( $container ); ?>">
<!-- <button type="button" class="btn-close btn-close-white text-reset" data-bs-
dismiss="offcanvas"
aria-label="Close"></button> -->
<!-- data-
toggle="modal" data-target="#menuModal" -->
<button class="navbar-toggler colapsed" type="button" data-bs-toggle="offcanvas" data-
bs-target="#navbarNavOffcanvas" aria-controls="navbarNavOffcanvas" aria-
expanded="false" aria-label="<?php esc_attr_e( 'Toggle navigation', 'understrap'
); ?>">
<span class="toggler-icon top-bar"></span>
<span class="toggler-icon middle-bar"></span>
<span class="toggler-icon bottom-bar"></span>
</button>
<!-- <button type="button" class="btn-close text-reset" data-bs-
dismiss="offcanvas" aria-label="Close"></button> -->
<div class="offcanvas offcanvas-start bg-primary" tabindex="-1"
id="navbarNavOffcanvas">
<div class="offcanvas-header justify-content-end">
<button type="button" class="btn-close btn-close-white text-reset" data-
bs-dismiss="offcanvas" aria-label="Close"></button>
</div><!-- .offcancas-header -->
<!-- The WordPress Menu goes here -->
<?php
wp_nav_menu(
array(
'theme_location' => 'primary',
'container_class' => 'offcanvas-body ',
'container_id' => '',
'menu_class' => 'navbar-nav justify-content-end flex-grow-1 pe-
3',
'fallback_cb' => '',
'menu_id' => 'main-menu',
'depth' => 2,
'walker' => new Understrap_WP_Bootstrap_Navwalker(),
)
);
?>
</div><!-- .offcanvas -->
</div><!-- .container(-fluid) -->
</nav><!-- .site-navigation -->
CSS
.navbar-toggler {
border: 0 !important;
}
.navbar-toggler:focus,
.navbar-toggler:active,
.navbar-toggler-icon:focus {
outline: none !important;
box-shadow: none !important;
border: 0 !important;
}
/* Lines of the Toggler */
.toggler-icon{
width: 30px;
height: 3px;
background-color: #e74c3c;
display: block;
transition: all 0.2s;
}
/* Adds Space between the lines */
.middle-bar{
margin: 5px auto;
}
/* State when navbar is opened (START) */
.navbar-toggler .top-bar {
transform: rotate(45deg);
transform-origin: 10% 10%;
}
.navbar-toggler .middle-bar {
opacity: 0;
filter: alpha(opacity=0);
}
.navbar-toggler .bottom-bar {
transform: rotate(-45deg);
transform-origin: 10% 90%;
}
/* State when navbar is opened (END) */
/* State when navbar is collapsed (START) */
.navbar-toggler.collapsed .top-bar {
transform: rotate(0);
}
.navbar-toggler.collapsed .middle-bar {
opacity: 1;
filter: alpha(opacity=100);
}
.navbar-toggler.collapsed .bottom-bar {
transform: rotate(0);
}
/* State when navbar is collapsed (END) */
/* Color of Toggler when collapsed */
.navbar-toggler.collapsed .toggler-icon {
background-color: #777777;
}
Please use the following tutorial https://jsfiddle.net/8xvaozm2/1/
but it is being used with toggle navigation and not with off canvas, does anyone know how it could be done?
there is a .show class that shows the menu when clicking, I used it but it didn't work for me
I wish to have all the tabs have the same height, no matter what contents are inside.
The tabs reside inside a div. Preferably I don't need to set a fixed height for this div, but instead the div should have the height of the mat-tab that has the most stuff.
Haven't found anything really works yet, if someone could help that will be wonderful!
My current code:
HTML:
<div fxLayout="column" style="min-height: 100%; height: 100%">
<mat-tab-group style="height: 100%">
<mat-tab label="1">
<mat-card fxFill class="mat-elevation-z4 about-card">
this mat-card contains the most amount of stuff
</mat-card>
</mat-tab>
<mat-tab label="2">
<mat-card fxFill class="mat-elevation-z4 about-card">
...a bunch of things
</mat-card>
</mat-tab>
<mat-tab label="3">
<mat-card fxFill class="mat-elevation-z4 about-card">
...a bunch of things
</mat-card>
</mat-tab>
</mat-tab-group>
</div>
CSS:
.about-card {
display: flex;
align-items: center;
justify-content: center;
margin: 16px;
padding: 16px;
border-radius: 8px;
}
Edit: Some boilerplate example:
First tab:
Second tab:
See how the heights of the content are different
This is a solution using javascript. You need to get the element with the max height and update the height of mat-tab-body-wrapper container :
ngAfterViewInit() {
const groups = document.querySelectorAll("mat-tab-group");
groups.forEach(group => {
const tabCont = group.querySelectorAll("mat-tab-body");
const wrapper = group.querySelector(".mat-tab-body-wrapper")
const maxHeight = Math.max(...Array.from(tabCont).map(body => body.clientHeight));
wrapper.setAttribute("style", `min-height:${maxHeight}px;`);
});
}
You can transform it using the angular API
Try this.
<mat-tab-group #myTabGroup id="myTabGroup">
ngAfterViewInit() {
this.setTabHeights();
}
#HostListener('window:resize', ['$event'])
handleResize(event: Event) {
this.setTabHeights();
}
setTabHeights() {
const tabCardBody = document
.querySelectorAll('mat-tab-group#setupWarehouseDataTab mat-tab-body');
if (!tabCardBody) return;
const maxHeight = Math.max(...Array.from(tabCardBody)
.map((elm: any) => elm.clientHeight));
tabCardBody.forEach((elm => {
elm.setAttribute('style', `height:${maxHeight}px;`);
});
}
I'm using jQuery-UI v1.11.2 in order to create some draggable and droppable divs, and Boostrap 3.1.1 as well.
I'd like to know why a Boostrap column class is interfering with the draggable "hint".
In other words, as I drag an image from my Gallery div to my Dashboard div, the Dashboard div comes in FRONT of the image hint. Then once I DROP my image on the Dashboard div, the image re-appears.
If I remove the col-md-8 class from the Dashboard div, this problem goes away.
Here are two screen shots to demonstrate:
1) WITHOUT the Bootstrap column class on the right div (image hint looks good)
2) With the Bootstrap column class on the right div (image hint disappears)
Here's the HTML code :
<section id="gadgets-view" class="mainbar" data-ng-controller="gadgets">
<div class="container-fluid">
<div class="row-fluid">
<!-- based on http://jqueryui.com/droppable/#photo-manager -->
<div class="ui-widget ui-helper-clearfix col-md-4"> <-- GALLERY OF WIDGETS -->
<ul id="gallery" class="gallery ui-helper-reset ui-helper-clearfix">
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Tree Grid</h5>
<img src="images/treegrid.jpg" alt="Hierarchy Grid" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Area Chart</h5>
<img src="images/chart_area.jpg" alt="Area Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Bar Chart</h5>
<img src="images/chart_bar.png" alt="Bar Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Column Chart</h5>
<img src="images/chart_column.png" alt="Column Chart" width="96" height="72">
</li>
<li class="ui-widget-content ui-corner-tr">
<h5 class="ui-widget-header">Line Chart</h5>
<img src="images/chart_line.png" alt="Line Chart" width="96" height="72">
</li>
</ul>
</div>
<div class="col-md-8">
<div id="dashboard" class="ui-widget-content ui-state-default "> <-- DROPPABLE DASHBOARD -->
<h4 class=""><span class="ui-icon ui-icon-image"></span>Dashboard</h4>
</div>
<div>
</div>
</div>
</section>
The CSS :
<style>
.ui-widget-header{
font-size: 65%;
font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif";
}
.ui-state-highlight {
border: 2px dashed #d3d3d3; /* override to show dashed border when dragging */
}
#gallery {
float: left;
width: 75%;
min-height: 12em;
}
.gallery.custom-state-active {
background: #eee;
}
.gallery li {
list-style: none;
float: left;
width: 96px;
padding: 0.4em;
margin: 0 0.4em 0.4em 0;
text-align: center;
}
.gallery li h5 {
margin: 0 0 0.4em;
cursor: move;
}
.gallery li a {
float: right;
}
.gallery li a.ui-icon-zoomin {
float: left;
}
.gallery li img {
width: 100%;
cursor: move;
}
#dashboard {
float: left;
width: 45%;
height:500px;
padding: 1%;
}
#dashboard h4 {
line-height: 25px;
margin: 0 0 0.4em;
}
#dashboard h4 .ui-icon {
float: left;
}
#dashboard .gallery h5 {
display: none;
}
The JavaScript to create drag/drop areas :
<script>
$(function () {
// there's the gallery and the dashboard
var $gallery = $("#gallery"),
$dashboard = $("#dashboard");
// let the gallery items be draggable
$("li", $gallery).draggable({
cancel: "a.ui-icon", // clicking an icon won't initiate dragging
revert: "invalid", // when not dropped, the item will revert back to its initial position
containment: "document",
helper: "clone",
cursor: "move"
});
// let the dashboard be droppable, accepting the gallery items
$dashboard.droppable({
accept: "#gallery > li",
activeClass: "ui-state-highlight",
drop: function (event, ui) {
debugger;
deleteImage(ui.draggable);
}
});
// let the gallery be droppable as well, accepting items from the dashboard
$gallery.droppable({
accept: "#dashboard li",
activeClass: "custom-state-active",
drop: function (event, ui) {
recycleImage(ui.draggable);
}
});
// image deletion function
var recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off' title='Remove gadget' class='ui-icon ui-icon-minus'></a>";
function deleteImage($item) {
$item.fadeOut(function () {
var $list = $("ul", $dashboard).length ?
$("ul", $dashboard) :
$("<ul class='gallery ui-helper-reset'/>").appendTo($dashboard);
//$item.find("a.ui-icon-dashboard").remove(); // DO NOT REMOVE ORIGINAL WIDGET ICON - 11/19/2014 BM:
$item.append(recycle_icon).appendTo($list).fadeIn(function () {
//$item.animate({ width: "48px" }).find("img").animate({ height: "36px" });
$item.animate().find("img").animate();
});
});
}
// image recycle function
var dashboard_icon = "<a href='link/to/dashboard/script/when/we/have/js/off' title='Add this gadget' class='ui-icon ui-icon-plus'</a>";
function recycleImage($item) {
$item.fadeOut(function () {
$item
.find("a.ui-icon-refresh")
.remove()
.end()
.css("width", "96px")
.append(dashboard_icon)
.find("img")
.css("height", "72px")
.end()
.appendTo($gallery)
.fadeIn();
});
}
// image preview function, demonstrating the ui.dialog used as a modal window
function viewLargerImage($link) {
var src = $link.attr("href"),
title = $link.siblings("img").attr("alt"),
$modal = $("img[src$='" + src + "']");
if ($modal.length) {
$modal.dialog("open");
} else {
var img = $("<img alt='" + title + "' width='384' height='288' style='display: none; padding: 8px;' />")
.attr("src", src).appendTo("body");
setTimeout(function () {
img.dialog({
title: title,
width: 400,
modal: true
});
}, 1);
}
}
// resolve the icons behavior with event delegation
$("ul.gallery > li").click(function (event) {
var $item = $(this),
$target = $(event.target);
if ($target.is("a.ui-icon-dashboard")) {
deleteImage($item);
} else if ($target.is("a.ui-icon-zoomin")) {
viewLargerImage($target);
} else if ($target.is("a.ui-icon-refresh")) {
recycleImage($item);
}
return false;
});
});
I found the problem you describe (but i did not found a relation with the Bootstrap Grid Classes).
For my the problem seems to be related to the z-index and can be solved by adding the following style rules at the end of your CSS code:
.ui-draggable-handle {
z-index: 1;
}
so I'm using the Twitter Bootstrap plugin for Grails and I'm having trouble centering modals. When I remove the class="modal" part from the div that contains the modal, my centering function works properly, but when I put it back (which is necessary for it to have the functionality of a modal it gets stuck halfway off the page). Any help would be very nice :D
Here's my code:
<a style="position: relative; top: 2px;" data-toggle="modal" href="#myModal${instanceType.id}"
id="${instanceType.id}"> ${message} </a>
<div class="modal" style="background: black; overflow: hidden; top: 0px; left: 0px; display: none; border: 2px solid white; float: center; position: absolute"
id="myModal${instanceType.id}">
<div style="border:none" class="modal-header">
<a style="color:white;" class="close" data-dismiss="modal">X</a>
</div>
<iframe id="iFrame" style="border: none;"width=800px height=675px src="${action}/${instanceType.id}">
</iframe>
<div class="modal-body" style="background: black;"></div>
<div style="border:none; background: black;" class="modal-footer">
<a "="#" class="btn" data-dismiss="modal">Close</a>
</div>
</div>
<script>
jQuery.fn.center = function () {
this.css("position","absolute");
this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px");
this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px");
return this;
}
$(myModal${instanceType.id}).css({
'width' : $(window).width()*.75,
'height' : $(window).height()*.75
})
$(myModal${instanceType.id}).center()
$('#modal-footer').append('${saveName}')
function submitFunction(){
$("iFrame").contents().find("#submit").click()
}
function changePre(){
$("iFrame").contents().find(".buttonNew").submit()
alert('hi')
}
</script>
If you're using the default modal styling centers the modal by absolute positioning. So when you customize a modal windows, and you change the size of it, you shall adjust relevant elements also. Like the modal-body and modal header and the .modal class.
And to answer your question, and if I got your question right, that is you were trying to position your modal VERTICALLY.
Open bootstrap.css , then find and edit .modal.fade.in
The default value is 50%. Try to play with it until you achieve your desired position. Increase it to move the modal to the bottom, decrease it and it will do the opposite.
Default modal size modal window positions Horizontal centre of the screen, once the modal customizes(width changes), need to position it with script.
sample script:
$('#myModal').modal({
backdrop: true,
keyboard: true
}).css({
width: '800',// custom width
'margin-left': function () {
return -($(this).width() / 2);
}
});