How to center an ngx-bootstrap modal - css

Trying to center this ngx-boostrap modal using CSS like this but it's not working:
.modal.fade.in{
display: flex;
justify-content: center;
align-items: center;
}
But in the dev tool, I'm able to add CSS like this:
.modal.dialog{
top: 50%
}
So at least it is centered vertically, but this is in the dev tool, and there is no .modal.dialogclass in the html template
Is there a way to center properly the ngx-bootstrap modal ?
I want to create a generic modal component to use it anywhere, by providing an input message and adding a yes/no dialog and output the user choice (using EventEmitter)
I've found an example in the following Plunker, but not able to reproduce it in a separate custom component.
The plunker example comes from this website: https://github.com/valor-software/ngx-bootstrap/issues/2334
Update:
After #Wira Xie answer, when I use the Static modal and this CSS:
.modal-sm
{
top: 50%;
left: 50%;
width:30em;
height:18em;
background-color: rgba(0,0,0,0.5);
}
The modal shows centered, but only the Esc key can hide it, so when I click outside the modal, it's still visible.

Why not to use bootstrap modal-dialog-centered class:
this.modalRef2 = this.modalService.show(ModalContentComponent,
{
class: 'modal-dialog-centered', initialState
}
);

in the .ts file you have a code like this (to open modal popup)...
private showModal(template: TemplateRef<any>): BsModalRef {
return this.modalService.show(
template,
{ class: 'modal-lg modal-dialog-centered',
ignoreBackdropClick: true,
keyboard: false
});
}
You can see that I've added modal-dialog-centered to the class. after doing this you can also modify the modal-dialog-centered class in your css.

Try adding this attribute to your CSS: vertical-align: middle to your .modal.dialog class
Plunker for modal
.modal.fade {
display: flex !important;
justify-content: center;
align-items: center;
}
.modal-dialog {
vertical-align:middle;
height:18em;
background-color: rgba(0,0,0,0.5);
}

You need to use the bootstrap class.
Add .modal-dialog-centered to .modal-dialog to vertically center the modal.
import { Component, OnInit, TemplateRef } from '#angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
#Component({
...
})
export class ModalComponent {
modalRef: BsModalRef;
// Here we add another class to our (.modal.dialog)
// and we need to pass this config when open our modal
config = {
class: 'modal-dialog-centered'
}
constructor(private modalService: BsModalService) { }
openModal(template: TemplateRef<any>) {
// pass the config as second param
this.modalRef = this.modalService.show(template, this.config);
}
}

You have to pass the modal-dialog-centered bootstrap class for the BsModalService.show() function like this:
const initialState = {
organization: organization,
};
this.modalRef = this.modalService.show(AdminOrganizationCreateComponent, {
class: 'modal-dialog-centered', initialState
});
Note: if you need to pass initial data you can pass it using the initalState object.

A bit late, but for reference.
The reason the styling of the dialog in the component is not working, is because component styling is isolated and restricted to elements within the component. The dialog created through the bsmodalservice is outside of this component. (directly under <body>).
So, while your styling is encapsulated in the component and some random identifier, the dialog itself is not. The final css (like mycomponent[_ngcontent_bla_323] .modal) does not apply to the div.modal that is added by the service.
Possible solutions are:
Move your css for this dialog to some global (s)css file instead of the (s)css for the component
Instead of using bsModalService with a template, use the bsmodal directive with a div within your component. That way the component local (s)css will apply.

I have added mat-step inside the modal and because of that it didn't align centered for modal-dialog-centered bootstrap class ether. But modal-lg class worked for me. Sample code is very similar to the accepted answer. Only change the bootstrap class which is passed to the modal.
this.modalRef = this.modalService.show(AddDevelopersGroupComponent,{
class: 'modal-lg',
initialState,
});

This is a snippet from my personal project using ngx-bootstrap too.
.modal-sm
{
top: 50%;
left: 50%;
width:30em;
height:18em;
margin-top: -9em;
margin-left: -15em;
background-color: #001b00;
/*position:fixed;*/
}
<!--typecript files-->
<script>
//here is the typesciprt file
export class AppComponent
{
//for default ngx-bootstrap modal
public modalRef: BsModalRef;
constructor(private modalService: BsModalService) {}
public openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
}
</script>
<!--end of ts file-->
<!--Modal-->
<div class="container">
<div bsModal #smModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title pull-left">Small modal</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="smModal.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
<!--enf of modal-->

According to the documentation you can center the modal vertically via setting centered property to true (as it is false by default)
const modalRef = this.modalService.open(ConfirmationDialogComponent, {
size: dialogSize,
centered: true
});

Related

Unable to alter CSS styles by id

I have a very simple div in my footer:
import React from "react";
import { useHistory } from "react-router-dom";
import style from "./DesktopFooter.module.css";
const DesktopFooter = () => {
const history = useHistory();
return (
<div className={style.container}>
<div className={style.footerNav} id="phoneNumber">
999-999-9999
</div>
<div className={style.footerNav}>
</div>
<div className={style.footerNav}></div>
</div>
);
};
export default DesktopFooter;
In my CSS I want to style both on the class and id:
.footerNav {
width: 50%;
display: flex;
}
#phoneNumber {
font-size: 2rem;
}
However my component is not recognizing the id styling I try to apply.
Could anyone point me in the right direction.
Ya, After you update a question, I found the issue, you are try to load style for id as normal Dom, but its will not work since you are not include css file as is, you are import style file to style param...
so, what you need to do is replace id="PhoneNumber" to this
<div className={styles["footerNav"]} id={styles["phoneNumber"]}>
999-999-9999
</div>
Check the demo url
Full Code:
import React from "react";
import style from "./MyComponent.module.css";
export default function App() {
return (
<div className={style.container}>
<div className={style["footerNav"]} id={style["phoneNumber"]}>
999-999-9999
</div>
<div className={style.footerNav}></div>
<div className={style.footerNav}></div>
</div>
);
}
I would suggest having it as either a class or an id. Classes usually have a higher priority, meaning that the id will be ignored.
This is what it should look like:
.phoneNumber {
font-size: 2rem;
width: 50%;
display: flex;
}
<div class = "phoneNumber">999-999-9999</div>
However, if you would like to get around this, I would use another element within the div, such as:
#myID{
font-size: 2rem;
}
.phoneNumber {
width: 50%;
display: flex;
}
<div class = "phoneNumber">
<p id="myID"> 999-999-999 </p>
</div>
Ok I found a solution, or at least a work around. The problem seems to be that the file was a css module and not just a css file.
I changed the name of the css file from DesktopFooter.module.css to DesktopFooter.css
and I changed my import statement from
import style from "./DesktopFooter.module.css" to import "./DesktopFooter.css

Target native dom element <input>...</input> with styled-components

I am having trouble getting my styled component to make a change to an <input /> wrapped in a React component. In Dev Tools I can see the style I am trying to override here:
.ui.input input {...}
I think the wrapping component needs to pass className to input i.e
<input className = {this.props.className} ..> ... </input>
but I cannot get the style to override with or without that. I will provide some snippets below.
//styled component
const StyledSearch = styled(Searchbar)`
&.ui.input input{
border: 0px !important;
}
`;
class SearchBar extends Component {
...
render() {
const style = {
display: this.state.showResults ? 'block' : 'none',
maxHeight: 500,
overflowY: 'scroll',
};
return (
<div className="ui search fluid" ref="container">
<div
className={`ui icon fluid input ${this.props.loading ? 'loading' : ''}`}>
<input type="text"
placeholder={this.props.placeholder}
onFocus={this.focus}
className = {this.props.className}
value={this.props.value}
onChange={this.props.onChange}/>
<i className="search icon"></i>
</div>
<div
className="results"
style={style}>
{
this.props.results.map((result, index) => (
<a
className="result"
key={index}
onClick={this.select.bind(this, result)}>
<div className="content">
{
result.get('image') ?
(
<div className="image">
<img src={result.get('image')} style={{ maxWidth: 50 }}/>
</div>
) : null
}
<div className="title">
{result.get('title')}
</div>
<div className="description">
{result.get('description')}
</div>
</div>
</a>
)
)
}
</div>
</div>
);}}
Basically, styled-components creates a new unique class name (in other words, a new namespace) for any DOM or React Components for which the styled function is called.
That means, when you use styled(SearchBar), styled-components wraps SearchBar component and attaches a unique class name to its root DOM. Then it passes that unique class name to the descendent DOMs and components (in your cases, nested div, input, a).
For this method to work, your root DOM must have a className that can be configured from outside. That's why, styled-components expects that, root DOM has the definition ${this.props.className} as the value of its className props. If your component lacks this, styled-components will not be able to create a new namespace which it can use to apply styling specific to it.
So, for your technique to work, you must assign ${this.props.className} as one of the values of className prop defined at the root div of SearchBar.
Working Demo
If you don't have access to SearchBar, you can wrap it with another component. Overhead of this process is that, you have to use an extra DOM level
Working Demo
From what I can tell, you need to apply the styles generated with styled-components to the wrapper element. This is due to the specificity of the .ui.input input external style. Meaning we can't simply target the input element with a new style because the .ui.input input selector is more specific and takes precedence. Here's a simple CSS example showing how the specificity of the .ui.input input selector takes precedence over the input styling:
.ui.input input {
border:2px solid red !important;
}
input {
border: 0px !important;
}
<div class="ui input">
<input />
</div>
This same issue is at play in your case. In the example below I've created a new Wrapper component, which has a style of:
&.ui.input input {
border: 0px !important;
font-size: 24px;
}
defined on it. This targets the inner input element, with more specificity, to override the external styles.
import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
class InputWrapper extends React.Component {
render() {
const Wrapper = styled.div`
&.ui.input input {
border: 0px !important;
font-size: 24px;
}
`;
return(
<Wrapper className="ui input">
<input type="text" placeholder="Input" />
</Wrapper>
)
}
}
ReactDOM.render(
<InputWrapper />,
document.getElementById("app")
);
Here's a WebpackBin example.
Currently at version 4 you can do it as simple as
const Input = styled.input`
border:2px solid red !important;
`;
it will rendered as native input with SC className

Angular Material Side Bar with "Half" side mode

I am working on the dynamic side bar for our project, basically what we want to do is to set up a dynamic side bar when user click on the side bar it will spread when user click back sidebar should collapse and show only icons (but not totally collapse it will keep the icons) for example before user click the icon. We are using sidenav.toggle()from angular material function which basically closes the sidebar completely and if I don't use toggle() function "Side" mode for navbar does not work. So I want collapse to icon with side mode. (The other reason we need to keep the side mode is that we also need to make sure when user spread the sidebar, right side content should push to right)
After user click the icon
Is there a way to do that?
Thanks.
Option 1: Generating Automatically:
You can create a navigation component from templates provided by Material itself using 'Angular CLI component schematics'
ng generate #angular/material:nav your-component-name
The above command will generate a new component that includes a toolbar with the app name and a responsive side nav based on Material breakpoints.
See more about angular material schematics here
Option 2: Implementing Manually:
To implement that, you just have to refer these two links:
Resizing Sidenav | Angular Material
Navigation List | Angular Material
glance through the following code. Implementation will be something like this:
<mat-drawer-container class="example-container mat-typography" autosize>
<mat-drawer #drawer mode="side" disableClose="true" opened="true">
<button mat-mini-fab (click)="isExpanded = !isExpanded" color="warn" style="margin: 10px;">
<mat-icon aria-label="Menu">menu</mat-icon>
</button>
<mat-nav-list>
<mat-list-item>
<mat-icon mat-list-icon>person</mat-icon>
<h4 mat-line *ngIf="isExpanded">Management A</h4>
</mat-list-item>
<mat-list-item>
<mat-icon mat-list-icon>assignment</mat-icon>
<h4 mat-line *ngIf="isExpanded">Management B</h4>
</mat-list-item>
<mat-list-item>
<mat-icon mat-list-icon>domain</mat-icon>
<h4 mat-line *ngIf="isExpanded">Management C</h4>
</mat-list-item>
<mat-list-item>
<mat-icon mat-list-icon>folder_shared</mat-icon>
<h4 mat-line *ngIf="isExpanded">Management X</h4>
</mat-list-item>
</mat-nav-list>
</mat-drawer>
<div class="example-sidenav-content">
You cards and screen Contents goes here..
Will be pushed towards right on expanding side navbar.
</div>
</mat-drawer-container>
I did this with a bit of CSS
mat-sidenav:not(.mat-drawer-opened) {
transform: translate3d(0, 0, 0) !important;
visibility: visible !important;
width: 60px !important;
overflow: hidden;
}
So when the draw is NOT open, the width of the sidenav is 60px and not 0. Just enough to show your icons.
OK, the next issue is that you'll need to hide a bunch of stuff like button name and other descriptive stuff, for me I need to change the height of the profile image and hide additional text. I did this in the same way as above using the :not selector:
mat-sidenav:not(.mat-drawer-opened) div.leftNav div.navProfile img {
width: 40px; margin: 16px 0 0px 0;
}
mat-sidenav:not(.mat-drawer-opened) .navTitle,
mat-sidenav:not(.mat-drawer-opened) .profileTitle {
display: none;
}
When collapsed I didn't want to show the button names so I wrapped the name in a *ngIf
<span class="navName" *ngIf="opened">{{ page?.name }} </span>
This should work, and it does but there is a problem. The ngIf is bound to the opened event and you will notice a delay when the event is firing (to account for it animation) to show your labels when the drawer is open.
To fix this I had to delve into the api of sidenav and found an eventemitter call openedStart and closedStart. I created a new bool in the component class,
showNavLabels: boolean;
then bound the events to this bool in the HTML.
<mat-sidenav class="sidenav" #sidenav mode="side" [(opened)]="opened"
(openedStart)='showNavLabels = !showNavLabels'
(closedStart)='showNavLabels = !showNavLabels' >
I am sure there is better way as I am not that experienced with Angular yet.
I hope it helps you out.
I created an example based on scss. Maybe someone can help to create the mobile version according to this sample.
Step 1: Add below style to styles.scss
// src/styles.scss
:root {
--menu-width-open: 200px;
--menu-width-closed: 64px;
}
.mat-drawer-container {
.mat-drawer {
box-sizing: content-box;
width: var(--menu-width-open);
transition: all 0.3s ease-in-out !important;
}
.mat-drawer-content {
// transform: translateX(200px);
margin-left: var(--menu-width-open) !important;
transition: all 0.3s ease-in-out !important;
}
&.container-closed {
.mat-drawer {
width: var(--menu-width-closed);
}
.mat-drawer-content {
// transform: translateX(64px) !important;
margin-left: var(--menu-width-closed) !important;
}
}
}
Step 2: Add drawer to app.componenet.html
<mat-drawer-container class="example-container" autosize [ngClass]="{ 'container-closed': !showFiller }">
<mat-drawer #drawer class="example-sidenav" mode="side" disableClose="true" opened="true">
<button (click)="showFiller = !showFiller" mat-raised-button>click</button>
</mat-drawer>
<div class="example-sidenav-content">
<router-outlet></router-outlet>
<button type="button" mat-button (click)="drawer.toggle()">Toggle sidenav</button>
</div>
</mat-drawer-container>
Step 3: And add showFiller = false; to app.component.ts file.
// app.component.ts
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
showFiller = false;
}
There is a feature request for this https://github.com/angular/material2/issues/1728
if you read the comments you'll also find a few examples on how to implement it yourself while it's not officialy available.

How to style one react component inside another?

I'm new to css and I can't figure out how to position one component inside another in React. I can show them separately, but when I put one inside another. I don't see the one inside. I think the problem is in the css file
#homePage{
section{
h1{
text-align: left; //this is shown
}
//here I want to add the other React component but I don't know how
}
}
And the render method:
<div id="homePage">
<Component1>
<section>
<h1>Hi</h1>
<Component2>
</Component2>
</section>
</Component1>
</div>
Thanks.
From what i understand , you could have the className attribute defined inside your Component2's HTML tags.
class Component2 extends Component{
render(){
return(
<section className="component2styles">
This is Component2
</section >
);
} }
Now , you can change ur style sheet as
#homePage{
section{
h1{
text-align: left; //this is shown
}
//components2 style will be nested here
section.component2styles{
border:1px solid blue;
}
}
}
Or as an alternative you can try inline-styles , seems to be gaining a lot of traction in React development.
render(){
var styleobj={color:'red'};
return( <section style={styleobj} > This is Component 2 </section> )
}
Did you add some class/id to your Component2 like <Component2 className="my-specific-class" /> to style it?
(btw, I hope your css is less/sass one to allow nested styles like you did)
EDIT
By adding className attr. to your Component2, I mean adding it in Component2 render method like
render: function() {
return (
<div id="your-id" className="your-class">
some html here
</div>
);
}

How to display a simple HTML5/CSS3 modal on Meteor using template?

I would like to use the modal window model as described by Keenan Payne, made with HTML5 & CSS3. For that, I simply created two files: modal.html with the HTML Modal template & modal.scss with the styling description
Modal.html
<template name="ModalSuggestion">
Open Modal
<div id="openModal" class="modalDialog">
<div>
X
<h2>Modal Box</h2>
<p>This is a sample modal box that can be created using the powers of CSS3.</p>
<p>You could do a lot of things here like have a pop-up ad that shows when your website loads, or create a login/register form for users.</p>
</div>
</div>
</template>
and simply invoke it through this simple
{{> iconSuggest}}
{{> ModalSuggestion}}
This should be dead simple and I feel ashamed to ask for help, but the should be on top of any other windows, independently of my app layout? I must have missed something...
Is there anything particular with Meteor that does prevent this from working right away?
Thanks for your help.
CSS
.modalDialog {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
z-index: 99990;
opacity: 0;
pointer-events: none;
}
.modalDialog:target {
opacity: 1;
pointer-events: auto;
}
.modalDialog > div {
width: 400px;
position: relative;
margin: 10% auto;
z-index: 99999;
}'
Is there a particular reason you want to use this technique? It's not clear from your question how it isn't working for you.
An alternative way to implement a modal in meteor:
HTML:
<template name="parentContainer">
{{#if modalOpen}}
{{> modal}}
{{/if}}
<div>Some content inside parent container</div>
<button class="open-modal">Exit</button>
</template>
<template name="modal">
<div class="modal-container">
<div>Are you sure you want to exit?</div>
<button class="confirm">Yes</button>
<button class="cancel">No</button>
</div>
</template>
Javascript:
Template.parentContainer.events({
'click .open-modal' : function() {
Session.set('modalOpen', true);
});
Template.parentContainer.helpers({
modalOpen: function() {
return Session.get('modalOpen');
}
});
Template.modal.events({
'click .confirm' : function() {
Session.set('modalOpen', false);
//closes modal
//do something else
};
'click .cancel' : function() {
Session.set('modalOpen', false);
//just closes modal
};
});
CSS:
I can't really provide specific css because it will depend on the context of the modal, but one option is to position the modal absolutely with a z-index that is higher than anything else on the page:
.modal-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
//z-index may be uncessary
z-index: 1; (or higher if necessary)
}
This would be a full width, full height modal that will cover anything else on the page. If you make it transparent or less than full width/height, then it will appear on top of the content behind it.
What is happening here:
The user clicks an element with an event listener attached to it, in this case it is a button with a class of 'open-modal'.
This event listener changes the value of a boolean session variable, in this case it sets the 'modalOpen' session variable to 'true'.
There is a helper function in our parent template that is watching the session variable, and will update the template whenever that variable changes, effectively adding our modal to the DOM. In this case, we're using a 'modalOpen' helper to track the 'modalOpen' session variable, and when it notices it has changed to true, it updates the template with this value. {#if modalOpen}} in the parent template notices that 'modalOpen' has changed, and because it now evaluates to 'true', it will insert our 'modal' template, represented by {{> modal}}.
We close the modal by changing the 'openModal' session variable to 'false'.
Hope that helps, and no need to be ashamed, this stuff is hard to learn. Like anything the more you do it the easier it gets.
it looks like this is a known issue when using Iron Router package... what I do use.
https://github.com/iron-meteor/iron-router/issues/711

Resources