Closed nsksaisaravana closed 7 years ago
Cool component. We have a full page overlay variant in our project (called it lightbox).
In future whether we can have such components in Primeng ?
Would be nice to have - currently a lot of our app depends on a sidebar. We end up using ng-sidebar - but the quality is often spotty and updates unreliable.
IF you consider this - make sure to have a option for non fixed sidebar that could be placed inside a container (like relative parent and absolute sidebar).
A vertical scrollbar would be nice if contents do not fit - instead of stretching the whole page (or leave room to customize it with css). Another major issue with hiding overflows is that it ends up clipping dropdown menus etc - perhaps you can find a solution to that as well?
Separate template able header (where close button is - so we could add extra buttons like toggle for wider sidebar etc).
We created our own component for something like this. basically just a menu that can slide in from the top/bottom/left/right of a container. Material has something similar called a bottom sheet.
I would consider this an essential component for PrimeNG
This component will be very useful, instead of pop up window we can use this. Currently, we are using ng-office UI slide bar in AngularJS but in Angular 2 we don't have such component.
Implemented for 4.2.2.
Thanks a lot for your hard work and looks awesome.
Can we have properties like small, medium, large and according to that we can have a size of the panel?
Cool. The next topic for PrimeNG's book, second edition -:).
Can we do the sidebar responsive? I mean a "full screen" mode on small screens, like Angular Material Dialog.
Since it has no documentation yet - does it use "fixed" display or relative-absolute? For example could i put it inside the "Documentation" tab in the demo above? Does it close when clicked outside? Or provides a attribute to toggle and implement the open/close ourselves?
Initial features are;
Will we be able to attach this to a certain element? it would be cool to use these as a sort of slide over menu inside of a dialog for example.
@cagataycivici I am after those features mentioned above !!! Thanks, guys.
I dont see this in the demo https://www.primefaces.org/primeng/#/setup
Can't find SidebarModule in 4.2.2... the component is there but the module is not exported.
@cagataycivici How do I prevent closing of the sidebar when outside is clicked?
Thanks
Will be great when ready! Looks like export not included in primeng.d.ts. Also, can't tell for sure by think sidebar.d.ts needs to implement ngOnDestroy in class declaration. In the demo page source code, there are a bunch of closing curly braces that make for unusable code if someone copies/pastes from there. Hope that helps!
Ah, and the export is missing from primeng.js, I believe. Yes -- that does the trick. On to testing. Thank you!
@bjareczek can you share code fix
@pantonis , PR is pending: https://github.com/primefaces/primeng/pull/4116
Sidebar gets not closed on ESC key. @cagataycivici: is it possible to implement this behavior like in Dialog?
Is it possible to have different modes like here? https://material.angular.io/components/sidenav/overview#sidenav-mode
Is there an example how to use appendTo. Can't get it work.
Thanks for work. Can sidebar have options to: 1) Not to display overlay mask over rest of area 2) Have a pin button to make sidebar "sticky" and get a part of parent area as "position: relative" ?
Something like this ... (@ralph-wermke take a look) This component has
import {NgModule,Component,AfterViewInit,AfterViewChecked,OnDestroy,Input,Output,EventEmitter,ViewChild,ElementRef,Renderer2} from '@angular/core';
import {trigger, state, style, transition, animate, AnimationMetadata} from '@angular/animations';
import {CommonModule} from '@angular/common';
import {DomHandler} from 'primeng/primeng';
import {AnimationBuilder, AnimationPlayer, AnimationFactory} from "@angular/animations";
import {Directive, HostBinding, HostListener } from '@angular/core';
@Component({
selector: 'p-sidebarex',
template: `
<div #sidebar_tassel *ngIf="useTassel" class="sidebar-ex-tassel" (click)="tasselClick($event)"></div>
<div #container [ngClass]="{'ui-sidebar ui-widget ui-widget-content ui-shadow':true, 'ui-sidebar-active': visible,
'ui-sidebar-left': (position === 'left'), 'ui-sidebar-right': (position === 'right'),
'ui-sidebar-top': (position === 'top'), 'ui-sidebar-bottom': (position === 'bottom'),
'ui-sidebar-full': fullScreen}"
[@panelState]="visible ? 'visible' : 'hidden'" [ngStyle]="style" [class]="styleClass">
<a *ngIf="pinable" [@pinbtnState]="pinned ? 'pinned' : 'unpinned'" [ngClass]="{'ui-sidebar-close ui-corner-all':true}" href="#" role="button" (click)="pin($event)">
<span class="fa fa-fw fa-thumb-tack"></span>
</a>
<a [ngClass]="{'ui-sidebar-close ui-corner-all':true}" href="#" role="button" (click)="close($event)">
<span class="fa fa-fw fa-close"></span>
</a>
<ng-content></ng-content>
</div>
<div #sidebar_workarea_wrapper class="sidebar-ex-workarea-wrapper"></div>
`,
styleUrls: ['./sidebar-ex.component.scss'],
styles: ['.sidebar-ex-tassel {background: linear-gradient(to right,darkgrey, white); position:absolute;} '],
animations: [
trigger('panelState', [
state('hidden', style({
opacity: 0
})),
state('visible', style({
opacity: 1
})),
transition('visible => hidden', animate('300ms ease-in')),
transition('hidden => visible', animate('300ms ease-out'))
]),
trigger('pinbtnState', [
state('pinned', style({
transform: 'rotate(0deg)',
opacity: 1
})),
state('unpinned', style({
transform: 'rotate(45deg)',
opacity: 0.7
})),
transition('pinned => unpinned', animate('300ms ease-in')),
transition('unpinned => pinned', animate('300ms ease-out'))
]),
],
providers: [DomHandler]
})
export class SidebarEx implements AfterViewInit, AfterViewChecked, OnDestroy {
_useMask: boolean = true;
_useTassel: boolean = true;
_tasselVisible: boolean = false;
@Input() position: string = 'left';
@Input() fullScreen: boolean;
@Input() appendTo: string;
@Input() blockScroll: boolean = false;
@Input() style: any;
@Input() styleClass: string;
@Input() autoZIndex: boolean = true;
@Input() baseZIndex: number = 0;
@ViewChild('container') containerViewChild: ElementRef;
@Output() onShow: EventEmitter<any> = new EventEmitter();
@Output() onHide: EventEmitter<any> = new EventEmitter();
@Output() visibleChange:EventEmitter<any> = new EventEmitter();
@Output() pinChange:EventEmitter<any> = new EventEmitter();
initialized: boolean;
_visible: boolean;
_pinned: boolean;
_pinable: boolean;
preventVisibleChangePropagation: boolean;
mask: HTMLDivElement;
@ViewChild('sidebar_workarea_wrapper') workareaWrapper: ElementRef;
@ViewChild('sidebar_tassel') tassel: ElementRef;
maskClickListener: Function;
executePostDisplayActions: boolean;
constructor(public el: ElementRef, public domHandler: DomHandler, public renderer: Renderer2, private _builder: AnimationBuilder) {}
//or use ElementRef.nativeElement.addEventListener(...)
@HostListener('document:mousemove', ['$event'])
coordinates(event: MouseEvent): void {
if (this._useTassel && !this.visible) {
let tasselDelta = 20;
const brect = this.containerViewChild.nativeElement.getBoundingClientRect(); //x, y, width, height, left, right, top, bottom
switch (this.position) {
case 'left': {
this.tasselVisible = event.clientX - brect.right <= tasselDelta;
break;
}
case 'right': {
this.tasselVisible = brect.left - event.clientX <= tasselDelta;
break;
}
case 'top': {
this.tasselVisible = event.clientY - brect.bottom <= tasselDelta;
break;
}
case 'bottom': {
this.tasselVisible = brect.top - event.clientY <= tasselDelta;
break;
}
}
}
}
ngAfterViewInit() {
this.initialized = true;
if(this.appendTo) {
if(this.appendTo === 'body') {
document.body.appendChild(this.containerViewChild.nativeElement);
}
else {
this.domHandler.appendChild(this.containerViewChild.nativeElement, this.appendTo);
}
}
this.renderer.appendChild(this.containerViewChild.nativeElement.parentElement.parentElement, this.workareaWrapper.nativeElement)
let i = 0;
while(i < this.containerViewChild.nativeElement.parentElement.parentElement.children.length) {
let child = this.containerViewChild.nativeElement.parentElement.parentElement.children[i];
if (child !== this.containerViewChild.nativeElement.parentElement && child !== this.workareaWrapper.nativeElement) {
this.renderer.appendChild(this.workareaWrapper.nativeElement, child);
continue;
}
i++;
}
if(this.visible) {
this.show();
}
}
@Input() get tasselVisible(): boolean {
return this._tasselVisible;
}
set tasselVisible(val: boolean) {
if (this._tasselVisible === val)
return;
let anim = <AnimationMetadata>{};
let hide_style = style({width:0,height:0, ['background-color']:'black', position: 'absolute'});
let show_style = style({});
const tasselsize = 20;
switch (this.position) {
case 'left': {
show_style = style({width: tasselsize, height: '100%', position: 'absolute', left:0, top:0});
hide_style = style({width:0,height:"100%", position: 'absolute', left:0, top:0});
break;
}
case 'right': {
show_style = style({width: tasselsize, height: '100%', position: 'absolute', right:0, top:0});
hide_style = style({width: 0, height: '100%', position: 'absolute', right:0, top:0});
break;
}
case 'top': {
show_style = style({width: '100%', height: tasselsize, position: 'absolute', left:0, top:0});
hide_style = style({width: '100%', height: 0, position: 'absolute', left:0, top:0});
break;
}
case 'bottom': {
show_style = style({width: '100%', height: tasselsize, position: 'absolute', left:0, bottom:0});
hide_style = style({width: '100%', height: 0, position: 'absolute', left:0, bottom:0});
break;
}
}
let factory = <AnimationFactory>{};
if(val) {
factory = this._builder.build([hide_style, animate('300ms ease-in', show_style)]);
} else {
factory = this._builder.build([show_style, animate('300ms ease-out', hide_style)]);
}
const player = factory.create(this.tassel.nativeElement, {});
player.play();
this._tasselVisible = val;
}
@Input() get visible(): boolean {
return this._visible;
}
set visible(val:boolean) {
this._visible = val;
if(this.initialized && this.containerViewChild && this.containerViewChild.nativeElement) {
if(this._visible) {
this.show();
this.tasselVisible = false;
}
else {
if(this.preventVisibleChangePropagation)
this.preventVisibleChangePropagation = false;
else
this.hide();
}
}
}
@Input() get pinned(): boolean {
return this._pinned;
}
set pinned(val: boolean) {
this._pinned = val;
this.workareaAnimate(val);
}
@Input() get useMask(): boolean {
return this._useMask;
}
set useMask(val: boolean) {
this._useMask = val;
if(val)
this.enableModality();
else
this.disableModality();
}
@Input() get useTassel(): boolean {
return this._useTassel;
}
set useTassel(val: boolean) {
this._useTassel = val;
}
private workareaAnimate(like_pinned: boolean) {
console.log('workareaAnimate ' + like_pinned);
let anim = <AnimationMetadata>{};
//let unpinned_style = style('*');
let unpinned_style = style({['margin-' + this.position]: 0});
let pinned_style = style({['margin-' + this.position]:
this.position == 'left' || this.position == 'right' ?
this.domHandler.getOuterWidth(this.containerViewChild.nativeElement) + 'px' :
this.domHandler.getOuterHeight(this.containerViewChild.nativeElement)+ 'px'
});
let factory = <AnimationFactory>{};
if(like_pinned) {
factory = this._builder.build([unpinned_style, animate('300ms ease-in', pinned_style)]);
} else {
factory = this._builder.build([pinned_style, animate('300ms ease-out', unpinned_style)]);
}
const player = factory.create(this.workareaWrapper.nativeElement, {});
player.play();
}
@Input() get pinable(): boolean {
return this._pinable;
}
set pinable(val: boolean) {
this._pinable = val;
}
ngAfterViewChecked() {
if(this.executePostDisplayActions) {
this.onShow.emit({});
this.executePostDisplayActions = false;
}
}
show() {
this.executePostDisplayActions = true;
if(this.autoZIndex) {
this.containerViewChild.nativeElement.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex));
}
this.enableModality();
if (this._pinned)
this.workareaAnimate(true);
}
hide() {
if (this._pinned)
this.workareaAnimate(false);
this.onHide.emit({});
this.disableModality();
}
pin() {
this.pinned = !this.pinned;
this.pinChange.emit({});
}
close(event: Event) {
this.preventVisibleChangePropagation = true;
this.hide();
this.visibleChange.emit(false);
this.visible = false;
event.preventDefault();
}
tasselClick(event: Event) {
this.preventVisibleChangePropagation = false;
if (this.visible) {
//this.close(event);
this.preventVisibleChangePropagation = true;
this.visible = false;
}
else {
this.visible = true;
}
this.preventVisibleChangePropagation = false;
}
enableModality() {
if(!this.mask && this._useMask) {
this.mask = document.createElement('div');
this.mask.style.zIndex = String(parseInt(this.containerViewChild.nativeElement.style.zIndex) - 1);
this.domHandler.addMultipleClasses(this.mask, 'ui-widget-overlay ui-sidebar-mask');
this.maskClickListener = this.renderer.listen(this.mask, 'click', (event: any) => {
this.close(event);
});
document.body.appendChild(this.mask);
if(this.blockScroll) {
this.domHandler.addClass(document.body, 'ui-overflow-hidden');
}
}
}
disableModality() {
if(this.mask) {
this.unbindMaskClickListener();
document.body.removeChild(this.mask);
if(this.blockScroll) {
this.domHandler.removeClass(document.body, 'ui-overflow-hidden');
}
this.mask = null;
}
}
unbindMaskClickListener() {
if(this.maskClickListener) {
this.maskClickListener();
this.maskClickListener = null;
}
}
ngOnDestroy() {
this.initialized = false;
if(this.visible) {
this.hide();
}
if(this.appendTo) {
this.el.nativeElement.appendChild(this.containerViewChild.nativeElement);
}
this.unbindMaskClickListener();
}
}
//@NgModule({
// imports: [CommonModule],
// exports: [SidebarEx],
// declarations: [SidebarEx]
//})
//export class SidebarModuleEx { }
I am using primeng sidebar for named routing outlets. I need to get alert when we click on either outside sidebar or cross ( X ) on top of sidebar. I have no idea! help me!
Why is the .ui-sidebar-lg class style so small on small screens? It should be over 60% of the screen width IMHO
Any working example of appendTo property in sidebar? It is always showing up for the entire browser window. Any help would be great.
The appendTo working for me when pointing to the variable attached to a @ViewChild(). Not found much use for it yet though.
Initial features are;
- Fixed position relative to the document itself, not to another element
- 4 positions, top, bottom, left, right
- Closes when outside is clicked
- Has a close icon at top right corner to close manually
- Can be managed from model like a dialog using visible property
- Has sm, md and lg as built-in sizes
- Responsive
- Full screen mode
how to let the sidebar open when I clicked outside the screen?
How to adjust the content of sidebar when it s small device? and also scrollable may be?
Thanks for work. Can sidebar have options to:
- Not to display overlay mask over rest of area
- Have a pin button to make sidebar "sticky" and get a part of parent area as "position: relative" ?
Is this item 2 (pin button) being developed?
A sticky/lock button would be nice, which would take away the shadow and make it fixed.
Initial features are;
- Fixed position relative to the document itself, not to another element
- 4 positions, top, bottom, left, right
- Closes when outside is clicked
- Has a close icon at top right corner to close manually
- Can be managed from model like a dialog using visible property
- Has sm, md and lg as built-in sizes
- Responsive
- Full screen mode
Thanks for this feature. For some reason we've to hide or disable this close button. Can you give me an working example of this? I've recently started using primefaces. I tried to closable="false" but didn't work. After searching through found this is available here https://github.com/primefaces/primeng/issues/5757. Can you share me detailed link on how to use this? Thank you.
All components are very nice. I looking for a component like Office UI Fabric Panel, to check, please have a look at this url
https://dev.office.com/fabric#/components/panel
I'm submitting a ... (check one with "x")
Plunkr Case (Bug Reports) Please fork the plunkr below and create a case demonstrating your bug report. Issues without a plunkr have much less possibility to be reviewed.
http://plnkr.co/edit/Wj39h1?p=preview
Current behavior
Expected behavior
Minimal reproduction of the problem with instructions
What is the motivation / use case for changing the behavior?
Please tell us about your environment:
Angular version: 2.0.X
PrimeNG version: 2.0.X
Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
Language: [all | TypeScript X.X | ES6/7 | ES5]
Node (for AoT issues):
node --version
=