@memberjunction/ng-container-directives v2.48.0
@memberjunction/ng-container-directives
Angular directives for container management in MemberJunction applications, providing flexible and responsive layout utilities.
Overview
This package provides two essential directives for managing container layouts in Angular applications:
- mjContainer: Exposes a ViewContainerRef for dynamic component loading
- mjFillContainer: Automatically resizes elements to fill their parent containers with intelligent context awareness
Features
mjContainer
directive for view container management and dynamic component loadingmjFillContainer
directive for responsive filling of parent containers- Automatic resizing on window resize events with dual debounce strategy
- Manual resize event handling via MJGlobal event system
- Customizable margin and dimension settings
- Smart context detection (automatically skips resizing in grids, hidden tabs, and elements with
mjSkipResize
) - Efficient resize event handling with configurable debouncing
- Debug mode for troubleshooting resize behavior
Installation
npm install @memberjunction/ng-container-directives
Usage
Import the module in your application:
import { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';
@NgModule({
imports: [
// ...
ContainerDirectivesModule
]
})
export class YourModule { }
mjContainer
The mjContainer
directive exposes a ViewContainerRef for dynamic component loading. This is particularly useful when you need to programmatically create and insert components into the DOM.
<div mjContainer></div>
In your component:
import { Component, ViewChild, ViewContainerRef } from '@angular/core';
import { Container } from '@memberjunction/ng-container-directives';
@Component({
selector: 'app-your-component',
template: `<div mjContainer></div>`
})
export class YourComponent {
@ViewChild(Container, { static: true }) container!: Container;
ngOnInit() {
// Access the ViewContainerRef for dynamic component creation
const viewContainerRef: ViewContainerRef = this.container.viewContainerRef;
// Example: Create a dynamic component
// const componentRef = viewContainerRef.createComponent(YourDynamicComponent);
}
}
mjFillContainer
Use the mjFillContainer
directive to make an element fill its parent container:
<!-- Basic usage (fills both width and height) -->
<div mjFillContainer>Content</div>
<!-- With custom settings -->
<div
mjFillContainer
[fillWidth]="true"
[fillHeight]="true"
[rightMargin]="10"
[bottomMargin]="20">
Content with margins
</div>
<!-- Fill only width -->
<div
mjFillContainer
[fillWidth]="true"
[fillHeight]="false">
Content that fills width only
</div>
Skip Resize
If you need to prevent the resize behavior for certain elements:
<!-- This element will not be resized by the directive -->
<div mjSkipResize>Content</div>
Manual Resize Triggering
You can trigger manual resizing using the MemberJunction global events:
import { MJGlobal, MJEventType } from '@memberjunction/global';
// Trigger resize
MJGlobal.Instance.RaiseEvent({
event: MJEventType.ManualResizeRequest,
args: null
});
Configuration
The mjFillContainer
directive has several configuration options:
Property | Type | Default | Description |
---|---|---|---|
fillWidth | boolean | true | Whether to fill the parent's width |
fillHeight | boolean | true | Whether to fill the parent's height |
rightMargin | number | 0 | Right margin in pixels |
bottomMargin | number | 0 | Bottom margin in pixels |
How It Works
The mjFillContainer
directive dynamically calculates and sets element dimensions based on its parent container:
Parent container detection: The directive identifies the nearest block-level parent element.
Size calculation:
- When
fillWidth
is true, it calculates the element's width based on its parent's width, accounting for the element's position within the parent and anyrightMargin
. - When
fillHeight
is true, it calculates height similarly, accounting for thebottomMargin
.
- When
Event handling: The directive listens for:
- Window resize events (with two debounce times: 100ms during active resizing, 500ms after resizing completes)
- Custom MJ application resize events via the MJGlobal event system
Context-aware behavior: The directive automatically skips resizing under certain conditions:
- Elements with the
mjSkipResize
attribute (or any parent with this attribute) - Elements within a grid (role="grid")
- Elements within hidden tabs (not currently active)
- Elements with hidden or not displayed parents
- Elements with the
Common Use Cases
When to Use [fillHeight]="true" [fillWidth]="false"
- Vertical scrollable areas where you want fixed width but dynamic height
- Content panels that should stretch to fill available vertical space
- Example: Sidebar navigation that fills vertical space but has fixed width
When to Use [fillHeight]="false" [fillWidth]="true"
- Horizontal elements like headers or toolbars that span full width
- Fixed-height components that need to adapt to different screen widths
- Example: Form controls that adjust width but maintain consistent height
When to Use Both (Default)
- Main content areas that should fill the entire available space
- Split panels or layouts that need to adapt to window resizing
- Example: Dashboards, content editors, or any primary workspace area
Performance Optimization
- Minimize unnecessary instances: Only apply to containers that truly need dynamic sizing
- Use
mjSkipResize
appropriately: Apply to elements that don't need resizing - Consider debouncing: The directive already implements debouncing, but be aware of performance impact with many instances
Nested Containers
When nesting components with mjFillContainer
:
- The parent container should have the directive applied with appropriate settings
- Child elements inherit the size constraints of their parents
- Adjustments are calculated top-down, so parent resizing triggers child resizing
- Example:
<div mjFillContainer [fillHeight]="true" class="main-container">
<div class="header" style="height: 60px;">Header</div>
<div mjFillContainer [fillHeight]="true" class="content-area">
<!-- This will fill the remaining height after the header -->
Content
</div>
</div>
Dependencies
This package depends on:
@memberjunction/core
- Core MemberJunction utilities and logging@memberjunction/global
- Global event system for manual resize triggersrxjs
- For event handling and debouncing
Peer dependencies:
@angular/common
^18.0.2@angular/core
^18.0.2@angular/router
^18.0.2
Troubleshooting
Element not resizing properly
- Check if any parent has
mjSkipResize
attribute - Verify the element isn't within a grid (role="grid") or hidden tab
- Ensure parent elements have proper CSS display properties (must be 'block')
- Check z-index and overflow settings
- Verify parent visibility (elements with hidden or not displayed parents are skipped)
Flickering during resize
- This is usually caused by cascading resize calculations
- Try applying
mjFillContainer
only where necessary - Use CSS transitions for smoother visual changes
- Consider the dual debounce strategy (100ms during resize, 500ms after)
Height calculation issues
- Ensure parent element has a defined height or position
- For full window height, apply directive to a root element
- Check for competing CSS that might override the directive's styles
- Note that padding is accounted for in calculations
Advanced Controls
For debugging or special cases, there are static properties on the FillContainer class:
import { FillContainer } from '@memberjunction/ng-container-directives';
// Disable resize globally (for all instances)
FillContainer.DisableResize = true;
// Enable resize debugging (logs to console)
FillContainer.OutputDebugInfo = true;
API Reference
Container Directive
@Directive({
selector: '[mjContainer]'
})
export class Container {
constructor(public viewContainerRef: ViewContainerRef) { }
}
FillContainer Directive
@Directive({
selector: '[mjFillContainer]'
})
export class FillContainer {
@Input() fillWidth: boolean = true;
@Input() fillHeight: boolean = true;
@Input() rightMargin: number = 0;
@Input() bottomMargin: number = 0;
static DisableResize: boolean = false;
static OutputDebugInfo: boolean = false;
}
Contributing
When contributing to this package:
1. Follow the MemberJunction development guidelines
2. Ensure all TypeScript compiles without errors: npm run build
3. Update this README if adding new features or changing behavior
4. Add appropriate TSDoc comments to all public APIs
8 months ago
4 months ago
8 months ago
6 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
6 months ago
6 months ago
4 months ago
8 months ago
8 months ago
8 months ago
6 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
5 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
9 months ago
5 months ago
9 months ago
8 months ago
9 months ago
9 months ago
8 months ago
7 months ago
5 months ago
9 months ago
9 months ago
5 months ago
5 months ago
8 months ago
8 months ago
7 months ago
9 months ago
9 months ago
9 months ago
5 months ago
5 months ago
8 months ago
8 months ago
5 months ago
5 months ago
9 months ago
5 months ago
8 months ago
4 months ago
10 months ago
6 months ago
11 months ago
10 months ago
11 months ago
6 months ago
11 months ago
4 months ago
8 months ago
8 months ago
12 months ago
6 months ago
6 months ago
8 months ago
12 months ago
12 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago