diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html
index 4c46fb25..4e9c5419 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html
@@ -5,15 +5,20 @@
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts
index 4fd618ee..b1402cfc 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts
@@ -10,6 +10,7 @@ import {
ParticipantPanelItemDirective,
ParticipantPanelItemElementsDirective,
ParticipantsPanelDirective,
+ PreJoinDirective,
StreamDirective,
ToolbarAdditionalButtonsDirective,
ToolbarAdditionalPanelButtonsDirective,
@@ -114,6 +115,12 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
*/
@ContentChild(StreamDirective) externalStream: StreamDirective;
+ // *** PreJoin ***
+ /**
+ * @internal
+ */
+ @ContentChild(PreJoinDirective) externalPreJoin: PreJoinDirective;
+
/**
* @internal
*/
@@ -198,6 +205,10 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
* @internal
*/
openviduAngularStreamTemplate: TemplateRef
;
+ /**
+ * @internal
+ */
+ openviduAngularPreJoinTemplate: TemplateRef;
/**
* Provides event notifications that fire when the local participant is ready to join to the room.
@@ -435,6 +446,7 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
this.setupToolbarTemplate();
this.setupPanelTemplate();
this.setupLayoutTemplate();
+ this.setupPreJoinTemplate();
}
/**
@@ -576,6 +588,19 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
}
}
+ /**
+ * @internal
+ */
+ private setupPreJoinTemplate(): void {
+ if (this.externalPreJoin) {
+ this.log.d('Setting EXTERNAL PREJOIN');
+ this.openviduAngularPreJoinTemplate = this.externalPreJoin.template;
+ } else {
+ this.log.d('Setting DEFAULT PREJOIN');
+ // Keep the default behavior - no template is set
+ }
+ }
+
/**
* @internal
*/
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts
index 7ba55d15..793f923d 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts
@@ -12,7 +12,8 @@ import {
ToolbarAdditionalPanelButtonsDirective,
AdditionalPanelsDirective,
ActivitiesPanelDirective,
- BackgroundEffectsPanelDirective
+ BackgroundEffectsPanelDirective,
+ PreJoinDirective
} from './openvidu-components-angular.directive';
@NgModule({
@@ -29,6 +30,7 @@ import {
ToolbarAdditionalPanelButtonsDirective,
ParticipantPanelItemElementsDirective,
ActivitiesPanelDirective,
+ PreJoinDirective,
// BackgroundEffectsPanelDirective
],
exports: [
@@ -44,6 +46,7 @@ import {
ToolbarAdditionalPanelButtonsDirective,
ParticipantPanelItemElementsDirective,
ActivitiesPanelDirective,
+ PreJoinDirective,
// BackgroundEffectsPanelDirective
]
})
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts
index 933ec53b..13bef658 100644
--- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts
+++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts
@@ -1814,3 +1814,197 @@ export class StreamDirective {
public container: ViewContainerRef
) {}
}
+
+/**
+ * The ***ovPreJoin** directive empowers you to substitute the default pre-join component template with a custom one.
+ * This directive allows you to create a completely custom pre-join experience while maintaining the core functionality.
+ *
+ * In the example below, we demonstrate how to replace the pre-join template with a custom one that includes
+ * device selection and a custom join button.
+ *
+ *
+ * ```typescript
+ * import { HttpClient } from '@angular/common/http';
+ * import { Component } from '@angular/core';
+ * import { lastValueFrom } from 'rxjs';
+ * import { FormsModule } from '@angular/forms';
+ *
+ * import {
+ * DeviceService,
+ * ParticipantService,
+ * OpenViduComponentsModule,
+ * } from 'openvidu-components-angular';
+ *
+ * @Component({
+ * selector: 'app-root',
+ * template: `
+ *
+ *
+ *
+ *
Join Meeting
+ *
+ *
+ *
+ *
+ *
+ *
+ * `,
+ * styles: `
+ * .custom-prejoin {
+ * display: flex;
+ * flex-direction: column;
+ * align-items: center;
+ * justify-content: center;
+ * height: 100vh;
+ * background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ * color: white;
+ * }
+ * .prejoin-form {
+ * display: flex;
+ * flex-direction: column;
+ * gap: 20px;
+ * align-items: center;
+ * }
+ * .name-input {
+ * padding: 12px;
+ * border: none;
+ * border-radius: 8px;
+ * font-size: 16px;
+ * min-width: 250px;
+ * }
+ * .join-button {
+ * padding: 12px 24px;
+ * background: #4CAF50;
+ * color: white;
+ * border: none;
+ * border-radius: 8px;
+ * font-size: 16px;
+ * cursor: pointer;
+ * transition: background 0.3s;
+ * }
+ * .join-button:hover:not(:disabled) {
+ * background: #45a049;
+ * }
+ * .join-button:disabled {
+ * background: #cccccc;
+ * cursor: not-allowed;
+ * }
+ * `,
+ * standalone: true,
+ * imports: [OpenViduComponentsModule, FormsModule],
+ * })
+ * export class AppComponent {
+ * // For local development, leave these variables empty
+ * // For production, configure them with correct URLs depending on your deployment
+ * APPLICATION_SERVER_URL = '';
+ * LIVEKIT_URL = '';
+ *
+ * // Define the name of the room and initialize the token variable
+ * roomName = 'custom-prejoin';
+ * token!: string;
+ * participantName: string = '';
+ *
+ * constructor(
+ * private httpClient: HttpClient,
+ * private deviceService: DeviceService,
+ * private participantService: ParticipantService
+ * ) {
+ * this.configureUrls();
+ * }
+ *
+ * private configureUrls() {
+ * // If APPLICATION_SERVER_URL is not configured, use default value from local development
+ * if (!this.APPLICATION_SERVER_URL) {
+ * if (window.location.hostname === 'localhost') {
+ * this.APPLICATION_SERVER_URL = 'http://localhost:6080/';
+ * } else {
+ * this.APPLICATION_SERVER_URL =
+ * 'https://' + window.location.hostname + ':6443/';
+ * }
+ * }
+ *
+ * // If LIVEKIT_URL is not configured, use default value from local development
+ * if (!this.LIVEKIT_URL) {
+ * if (window.location.hostname === 'localhost') {
+ * this.LIVEKIT_URL = 'ws://localhost:7880/';
+ * } else {
+ * this.LIVEKIT_URL = 'wss://' + window.location.hostname + ':7443/';
+ * }
+ * }
+ * }
+ *
+ * // Function to request a token when a participant joins the room
+ * async onTokenRequested(participantName: string) {
+ * const { token } = await this.getToken(this.roomName, participantName);
+ * this.token = token;
+ * }
+ *
+ * // Function called when ready to join
+ * onReadyToJoin() {
+ * console.log('Ready to join the meeting');
+ * }
+ *
+ * // Function to join the meeting
+ * async joinMeeting() {
+ * if (this.participantName.trim()) {
+ * // Request token with the participant name
+ * await this.onTokenRequested(this.participantName);
+ * }
+ * }
+ *
+ * // Function to get a token from the server
+ * getToken(roomName: string, participantName: string): Promise {
+ * try {
+ * // Send a POST request to the server to obtain a token
+ * return lastValueFrom(
+ * this.httpClient.post(this.APPLICATION_SERVER_URL + 'token', {
+ * roomName,
+ * participantName,
+ * })
+ * );
+ * } catch (error: any) {
+ * // Handle errors, e.g., if the server is not reachable
+ * if (error.status === 404) {
+ * throw {
+ * status: error.status,
+ * message:
+ * 'Cannot connect with the backend. ' + error.url + ' not found',
+ * };
+ * }
+ * throw error;
+ * }
+ * }
+ * }
+ *
+ * ```
+ *
+ *
+ * For a detailed tutorial on customizing the pre-join component, please visit [this link](https://openvidu.io/latest/docs/tutorials/angular-components/openvidu-custom-prejoin/).
+ */
+
+@Directive({
+ selector: '[ovPreJoin]',
+ standalone: false
+})
+export class PreJoinDirective {
+ constructor(
+ public template: TemplateRef,
+ public container: ViewContainerRef
+ ) {}
+}