diff --git a/src/components/components.module.ts b/src/components/components.module.ts
index 1cf8543a4..d1dddb4fb 100644
--- a/src/components/components.module.ts
+++ b/src/components/components.module.ts
@@ -38,6 +38,7 @@ import { CoreTabsComponent } from './tabs/tabs';
import { CoreTabComponent } from './tabs/tab';
import { CoreRichTextEditorComponent } from './rich-text-editor/rich-text-editor';
import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons';
+import { CoreDynamicComponent } from './dynamic-component/dynamic-component';
@NgModule({
declarations: [
@@ -61,7 +62,8 @@ import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons';
CoreTabsComponent,
CoreTabComponent,
CoreRichTextEditorComponent,
- CoreNavBarButtonsComponent
+ CoreNavBarButtonsComponent,
+ CoreDynamicComponent
],
entryComponents: [
CoreContextMenuPopoverComponent,
@@ -92,7 +94,8 @@ import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons';
CoreTabsComponent,
CoreTabComponent,
CoreRichTextEditorComponent,
- CoreNavBarButtonsComponent
+ CoreNavBarButtonsComponent,
+ CoreDynamicComponent
]
})
export class CoreComponentsModule {}
diff --git a/src/components/dynamic-component/dynamic-component.html b/src/components/dynamic-component/dynamic-component.html
new file mode 100644
index 000000000..99c89fec9
--- /dev/null
+++ b/src/components/dynamic-component/dynamic-component.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/components/dynamic-component/dynamic-component.ts b/src/components/dynamic-component/dynamic-component.ts
new file mode 100644
index 000000000..01fa9532d
--- /dev/null
+++ b/src/components/dynamic-component/dynamic-component.ts
@@ -0,0 +1,168 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {
+ Component, Input, ViewChild, OnInit, OnChanges, DoCheck, ViewContainerRef, ComponentFactoryResolver,
+ KeyValueDiffers, SimpleChange
+} from '@angular/core';
+import { CoreLoggerProvider } from '../../providers/logger';
+
+/**
+ * Component to create another component dynamically.
+ *
+ * You need to pass the class of the component to this component (the class, not the name), along with the input data.
+ *
+ * So you should do something like:
+ *
+ * import { MyComponent } from './component';
+ *
+ * ...
+ *
+ * this.component = MyComponent;
+ *
+ * And in the template:
+ *
+ *
+ * Cannot render the data.
+ *
+ *
+ * Please notice that the component that you pass needs to be declared in entryComponents of the module to be created dynamically.
+ *
+ * The contents of this component will be displayed if no component is supplied or it cannot be created. In the example above,
+ * if no component is supplied then the template will show the message "Cannot render the data.".
+ */
+@Component({
+ selector: 'core-dynamic-component',
+ templateUrl: 'dynamic-component.html'
+})
+export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck {
+
+ @Input() component: any;
+ @Input() data: any;
+
+ // Get the container where to put the dynamic component.
+ @ViewChild('dynamicComponent', { read: ViewContainerRef }) set dynamicComponent(el: ViewContainerRef) {
+ this.container = el;
+ this.createComponent();
+ }
+
+ instance: any;
+ container: ViewContainerRef;
+ protected logger: any;
+ protected differ: any; // To detect changes in the data input.
+
+ constructor(logger: CoreLoggerProvider, private factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers) {
+ this.logger = logger.getInstance('CoreDynamicComponent');
+ this.differ = differs.find([]).create();
+ }
+
+ /**
+ * Component being initialized.
+ */
+ ngOnInit(): void {
+ this.createComponent();
+ }
+
+ /**
+ * Detect changes on input properties.
+ */
+ ngOnChanges(changes: { [name: string]: SimpleChange }): void {
+ if (!this.instance && changes.component) {
+ this.createComponent();
+ }
+ }
+
+ /**
+ * Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays).
+ */
+ ngDoCheck(): void {
+ if (this.instance) {
+ // Check if there's any change in the data object.
+ const changes = this.differ.diff(this.data);
+ if (changes) {
+ this.setInputData();
+ if (this.instance.ngOnChanges) {
+ this.instance.ngOnChanges(this.createChangesForComponent(changes));
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a component, add it to a container and set the input data.
+ *
+ * @return {boolean} Whether the component was successfully created.
+ */
+ protected createComponent(): boolean {
+ if (!this.component || !this.container) {
+ // No component to instantiate or container doesn't exist right now.
+ return false;
+ }
+
+ if (this.instance) {
+ // Component already instantiated.
+ return true;
+ }
+
+ try {
+ // Create the component and add it to the container.
+ const factory = this.factoryResolver.resolveComponentFactory(this.component),
+ componentRef = this.container.createComponent(factory);
+
+ this.instance = componentRef.instance;
+
+ this.setInputData();
+
+ return true;
+ } catch (ex) {
+ this.logger.error('Error creating component', ex);
+
+ return false;
+ }
+ }
+
+ /**
+ * Set the input data for the component.
+ */
+ protected setInputData(): void {
+ for (const name in this.data) {
+ this.instance[name] = this.data[name];
+ }
+ }
+
+ /**
+ * Given the changes on the data input, create the changes object for the component.
+ *
+ * @param {any} changes Changes in the data input (detected by KeyValueDiffer).
+ * @return {{[name: string]: SimpleChange}} List of changes for the component.
+ */
+ protected createChangesForComponent(changes: any): { [name: string]: SimpleChange } {
+ const newChanges: { [name: string]: SimpleChange } = {};
+
+ // Added items are considered first change.
+ changes.forEachAddedItem((item) => {
+ newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
+ });
+
+ // Changed or removed items aren't first change.
+ changes.forEachChangedItem((item) => {
+ newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, false);
+ });
+ changes.forEachRemovedItem((item) => {
+ newChanges[item.key] = new SimpleChange(item.previousValue, item.currentValue, true);
+ });
+
+ return newChanges;
+ }
+}
diff --git a/src/core/course/components/format/format.html b/src/core/course/components/format/format.html
index a0fbe654f..0b1e8dcc8 100644
--- a/src/core/course/components/format/format.html
+++ b/src/core/course/components/format/format.html
@@ -1,45 +1,45 @@
-
+
-
- = 0">
-
-
-
-
+
+
+ = 0">
+
+
+
+
-
-
-
- {{section.formattedName || section.name}}
-
-
-
-
-
+
+
+
+
+ {{section.formattedName || section.name}}
+
+
+
+
+
-
+
-
-
+
-
+
-
-
+
-
+
@@ -78,6 +78,3 @@
0 && section.count < section.total">{{section.count}} / {{section.total}}
-
-
-
\ No newline at end of file
diff --git a/src/core/course/components/format/format.ts b/src/core/course/components/format/format.ts
index 626218146..578f9fe0f 100644
--- a/src/core/course/components/format/format.ts
+++ b/src/core/course/components/format/format.ts
@@ -12,13 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {
- Component, Input, OnInit, OnChanges, OnDestroy, ViewContainerRef, ComponentFactoryResolver, ViewChild, ChangeDetectorRef,
- SimpleChange, Output, EventEmitter
-} from '@angular/core';
+import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChange, Output, EventEmitter } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '../../../../providers/events';
-import { CoreLoggerProvider } from '../../../../providers/logger';
import { CoreSitesProvider } from '../../../../providers/sites';
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
import { CoreCourseProvider } from '../../../course/providers/course';
@@ -48,31 +44,15 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
@Input() initialSectionNumber?: number; // The section to load first (by number).
@Output() completionChanged?: EventEmitter; // Will emit an event when any module completion changes.
- // Get the containers where to inject dynamic components. We use a setter because they might be inside a *ngIf.
- @ViewChild('courseFormat', { read: ViewContainerRef }) set courseFormat(el: ViewContainerRef) {
- if (this.course) {
- this.createComponent('courseFormat', this.cfDelegate.getCourseFormatComponent(this.course), el);
- } else {
- // The component hasn't been initialized yet. Store the container.
- this.componentContainers['courseFormat'] = el;
- }
- }
- @ViewChild('courseSummary', { read: ViewContainerRef }) set courseSummary(el: ViewContainerRef) {
- this.createComponent('courseSummary', this.cfDelegate.getCourseSummaryComponent(this.course), el);
- }
- @ViewChild('sectionSelector', { read: ViewContainerRef }) set sectionSelector(el: ViewContainerRef) {
- this.createComponent('sectionSelector', this.cfDelegate.getSectionSelectorComponent(this.course), el);
- }
- @ViewChild('singleSection', { read: ViewContainerRef }) set singleSection(el: ViewContainerRef) {
- this.createComponent('singleSection', this.cfDelegate.getSingleSectionComponent(this.course), el);
- }
- @ViewChild('allSections', { read: ViewContainerRef }) set allSections(el: ViewContainerRef) {
- this.createComponent('allSections', this.cfDelegate.getAllSectionsComponent(this.course), el);
- }
+ // All the possible component classes.
+ courseFormatComponent: any;
+ courseSummaryComponent: any;
+ sectionSelectorComponent: any;
+ singleSectionComponent: any;
+ allSectionsComponent: any;
- // Instances and containers of all the components that the handler could define.
- protected componentContainers: { [type: string]: ViewContainerRef } = {};
- componentInstances: { [type: string]: any } = {};
+ // Data to pass to the components.
+ data: any = {};
displaySectionSelector: boolean;
selectedSection: any;
@@ -80,23 +60,20 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
selectOptions: any = {};
loaded: boolean;
- protected logger;
protected sectionStatusObserver;
- constructor(logger: CoreLoggerProvider, private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService,
- private factoryResolver: ComponentFactoryResolver, private cdr: ChangeDetectorRef,
+ constructor(private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService,
private courseHelper: CoreCourseHelperProvider, private domUtils: CoreDomUtilsProvider,
eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider,
prefetchDelegate: CoreCourseModulePrefetchDelegate) {
- this.logger = logger.getInstance('CoreCourseFormatComponent');
this.selectOptions.title = translate.instant('core.course.sections');
this.completionChanged = new EventEmitter();
// Listen for section status changes.
this.sectionStatusObserver = eventsProvider.on(CoreEventsProvider.SECTION_STATUS_CHANGED, (data) => {
if (this.downloadEnabled && this.sections && this.sections.length && this.course && data.sectionId &&
- data.courseId == this.course.id) {
+ data.courseId == this.course.id) {
// Check if the affected section is being downloaded.
// If so, we don't update section status because it'll already be updated when the download finishes.
const downloadId = this.courseHelper.getSectionDownloadId({ id: data.sectionId });
@@ -135,15 +112,19 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
*/
ngOnInit(): void {
this.displaySectionSelector = this.cfDelegate.displaySectionSelector(this.course);
-
- this.createComponent(
- 'courseFormat', this.cfDelegate.getCourseFormatComponent(this.course), this.componentContainers['courseFormat']);
}
/**
* Detect changes on input properties.
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
+ this.setInputData();
+
+ if (changes.course) {
+ // Course has changed, try to get the components.
+ this.getComponents();
+ }
+
if (changes.sections && this.sections) {
if (!this.selectedSection) {
// There is no selected section yet, calculate which one to load.
@@ -186,62 +167,39 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
if (changes.downloadEnabled && this.downloadEnabled) {
this.calculateSectionsStatus(false);
}
-
- // Apply the changes to the components and call ngOnChanges if it exists.
- for (const type in this.componentInstances) {
- const instance = this.componentInstances[type];
-
- for (const name in changes) {
- instance[name] = changes[name].currentValue;
- }
-
- if (instance.ngOnChanges) {
- instance.ngOnChanges(changes);
- }
- }
}
/**
- * Create a component, add it to a container and set the input data.
- *
- * @param {string} type The "type" of the component.
- * @param {any} componentClass The class of the component to create.
- * @param {ViewContainerRef} container The container to add the component to.
- * @return {boolean} Whether the component was successfully created.
+ * Set the input data for components.
*/
- protected createComponent(type: string, componentClass: any, container: ViewContainerRef): boolean {
- if (!componentClass || !container) {
- // No component to instantiate or container doesn't exist right now.
- return false;
- }
+ protected setInputData(): void {
+ this.data.course = this.course;
+ this.data.sections = this.sections;
+ this.data.initialSectionId = this.initialSectionId;
+ this.data.initialSectionNumber = this.initialSectionNumber;
+ this.data.downloadEnabled = this.downloadEnabled;
+ }
- if (this.componentInstances[type] && container === this.componentContainers[type]) {
- // Component already instantiated and the component hasn't been destroyed, nothing to do.
- return true;
- }
-
- try {
- // Create the component and add it to the container.
- const factory = this.factoryResolver.resolveComponentFactory(componentClass),
- componentRef = container.createComponent(factory);
-
- this.componentContainers[type] = container;
- this.componentInstances[type] = componentRef.instance;
-
- // Set the Input data.
- this.componentInstances[type].course = this.course;
- this.componentInstances[type].sections = this.sections;
- this.componentInstances[type].initialSectionId = this.initialSectionId;
- this.componentInstances[type].initialSectionNumber = this.initialSectionNumber;
- this.componentInstances[type].downloadEnabled = this.downloadEnabled;
-
- this.cdr.detectChanges(); // The instances are used in ngIf, tell Angular that something has changed.
-
- return true;
- } catch (ex) {
- this.logger.error('Error creating component', type, ex);
-
- return false;
+ /**
+ * Get the components classes.
+ */
+ protected getComponents(): void {
+ if (this.course) {
+ if (!this.courseFormatComponent) {
+ this.courseFormatComponent = this.cfDelegate.getCourseFormatComponent(this.course);
+ }
+ if (!this.courseSummaryComponent) {
+ this.courseSummaryComponent = this.cfDelegate.getCourseSummaryComponent(this.course);
+ }
+ if (!this.sectionSelectorComponent) {
+ this.sectionSelectorComponent = this.cfDelegate.getSectionSelectorComponent(this.course);
+ }
+ if (!this.singleSectionComponent) {
+ this.singleSectionComponent = this.cfDelegate.getSingleSectionComponent(this.course);
+ }
+ if (!this.allSectionsComponent) {
+ this.allSectionsComponent = this.cfDelegate.getAllSectionsComponent(this.course);
+ }
}
}
@@ -253,16 +211,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
sectionChanged(newSection: any): void {
const previousValue = this.selectedSection;
this.selectedSection = newSection;
-
- // If there is a component to render the current section, update its section.
- if (this.componentInstances.singleSection) {
- this.componentInstances.singleSection.section = this.selectedSection;
- if (this.componentInstances.singleSection.ngOnChanges) {
- this.componentInstances.singleSection.ngOnChanges({
- section: new SimpleChange(previousValue, newSection, typeof previousValue != 'undefined')
- });
- }
- }
+ this.data.section = this.selectedSection;
}
/**
diff --git a/src/core/course/formats/singleactivity/components/format.ts b/src/core/course/formats/singleactivity/components/format.ts
deleted file mode 100644
index 001e0e692..000000000
--- a/src/core/course/formats/singleactivity/components/format.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-// (C) Copyright 2015 Martin Dougiamas
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import { Component, Input, OnChanges, ViewContainerRef, ComponentFactoryResolver, SimpleChange } from '@angular/core';
-import { CoreLoggerProvider } from '../../../../../providers/logger';
-import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
-import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
-
-/**
- * Component to display single activity format. It will determine the right component to use and instantiate it.
- *
- * The instantiated component will receive the course and the module as inputs.
- */
-@Component({
- selector: 'core-course-format-single-activity',
- template: ''
-})
-export class CoreCourseFormatSingleActivityComponent implements OnChanges {
- @Input() course: any; // The course to render.
- @Input() sections: any[]; // List of course sections.
- @Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
-
- protected logger: any;
- protected module: any;
- protected componentInstance: any;
-
- constructor(logger: CoreLoggerProvider, private viewRef: ViewContainerRef, private factoryResolver: ComponentFactoryResolver,
- private moduleDelegate: CoreCourseModuleDelegate) {
- this.logger = logger.getInstance('CoreCourseFormatSingleActivityComponent');
- }
-
- /**
- * Detect changes on input properties.
- */
- ngOnChanges(changes: { [name: string]: SimpleChange }): void {
- if (this.course && this.sections && this.sections.length) {
- // In single activity the module should only have 1 section and 1 module. Get the module.
- const module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
- if (module && !this.componentInstance) {
- // We haven't created the component yet. Create it now.
- this.createComponent(module);
- }
-
- if (this.componentInstance && this.componentInstance.ngOnChanges) {
- // Call ngOnChanges of the component.
- const newChanges: { [name: string]: SimpleChange } = {};
-
- // Check if course has changed.
- if (changes.course) {
- newChanges.course = changes.course;
- this.componentInstance.course = this.course;
- }
-
- // Check if module has changed.
- if (changes.sections && module != this.module) {
- newChanges.module = {
- currentValue: module,
- firstChange: changes.sections.firstChange,
- previousValue: this.module,
- isFirstChange: (): boolean => {
- return newChanges.module.firstChange;
- }
- };
- this.componentInstance.module = module;
- this.module = module;
- }
-
- if (Object.keys(newChanges).length) {
- this.componentInstance.ngOnChanges(newChanges);
- }
- }
- }
- }
-
- /**
- * Create the component, add it to the container and set the input data.
- *
- * @param {any} module The module.
- * @return {boolean} Whether the component was successfully created.
- */
- protected createComponent(module: any): boolean {
- const componentClass = this.moduleDelegate.getMainComponent(this.course, module) || CoreCourseUnsupportedModuleComponent;
- if (!componentClass) {
- // No component to instantiate.
- return false;
- }
-
- try {
- // Create the component and add it to the container.
- const factory = this.factoryResolver.resolveComponentFactory(componentClass),
- componentRef = this.viewRef.createComponent(factory);
-
- this.componentInstance = componentRef.instance;
-
- // Set the Input data.
- this.componentInstance.courseId = this.course.id;
- this.componentInstance.module = module;
-
- return true;
- } catch (ex) {
- this.logger.error('Error creating component', ex);
-
- return false;
- }
- }
-}
diff --git a/src/core/course/formats/singleactivity/components/singleactivity.html b/src/core/course/formats/singleactivity/components/singleactivity.html
new file mode 100644
index 000000000..1f3a37007
--- /dev/null
+++ b/src/core/course/formats/singleactivity/components/singleactivity.html
@@ -0,0 +1 @@
+
diff --git a/src/core/course/formats/singleactivity/components/singleactivity.ts b/src/core/course/formats/singleactivity/components/singleactivity.ts
new file mode 100644
index 000000000..cd5cae32c
--- /dev/null
+++ b/src/core/course/formats/singleactivity/components/singleactivity.ts
@@ -0,0 +1,55 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
+import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
+import { CoreCourseUnsupportedModuleComponent } from '../../../components/unsupported-module/unsupported-module';
+
+/**
+ * Component to display single activity format. It will determine the right component to use and instantiate it.
+ *
+ * The instantiated component will receive the course and the module as inputs.
+ */
+@Component({
+ selector: 'core-course-format-single-activity',
+ templateUrl: 'singleactivity.html'
+})
+export class CoreCourseFormatSingleActivityComponent implements OnChanges {
+ @Input() course: any; // The course to render.
+ @Input() sections: any[]; // List of course sections.
+ @Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
+
+ componentClass: any; // The class of the component to render.
+ data: any = {}; // Data to pass to the component.
+
+ constructor(private moduleDelegate: CoreCourseModuleDelegate) { }
+
+ /**
+ * Detect changes on input properties.
+ */
+ ngOnChanges(changes: { [name: string]: SimpleChange }): void {
+ if (this.course && this.sections && this.sections.length) {
+ // In single activity the module should only have 1 section and 1 module. Get the module.
+ const module = this.sections[0] && this.sections[0].modules && this.sections[0].modules[0];
+ if (module && !this.componentClass) {
+ // We haven't obtained the class yet. Get it now.
+ this.componentClass = this.moduleDelegate.getMainComponent(this.course, module) ||
+ CoreCourseUnsupportedModuleComponent;
+ }
+
+ this.data.courseId = this.course.id;
+ this.data.module = module;
+ }
+ }
+}
diff --git a/src/core/course/formats/singleactivity/providers/handler.ts b/src/core/course/formats/singleactivity/providers/handler.ts
index 1f232fe78..17f1a5734 100644
--- a/src/core/course/formats/singleactivity/providers/handler.ts
+++ b/src/core/course/formats/singleactivity/providers/handler.ts
@@ -14,7 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreCourseFormatHandler } from '../../../providers/format-delegate';
-import { CoreCourseFormatSingleActivityComponent } from '../components/format';
+import { CoreCourseFormatSingleActivityComponent } from '../components/singleactivity';
/**
* Handler to support singleactivity course format.
diff --git a/src/core/course/formats/singleactivity/singleactivity.module.ts b/src/core/course/formats/singleactivity/singleactivity.module.ts
index 0ccb98388..8899f01db 100644
--- a/src/core/course/formats/singleactivity/singleactivity.module.ts
+++ b/src/core/course/formats/singleactivity/singleactivity.module.ts
@@ -13,15 +13,17 @@
// limitations under the License.
import { NgModule } from '@angular/core';
-import { CoreCourseFormatSingleActivityComponent } from './components/format';
+import { CoreCourseFormatSingleActivityComponent } from './components/singleactivity';
import { CoreCourseFormatSingleActivityHandler } from './providers/handler';
import { CoreCourseFormatDelegate } from '../../providers/format-delegate';
+import { CoreComponentsModule } from '../../../../components/components.module';
@NgModule({
declarations: [
CoreCourseFormatSingleActivityComponent
],
imports: [
+ CoreComponentsModule
],
providers: [
CoreCourseFormatSingleActivityHandler
diff --git a/src/core/user/components/components.module.ts b/src/core/user/components/components.module.ts
index 13682bbe7..3fd47b41e 100644
--- a/src/core/user/components/components.module.ts
+++ b/src/core/user/components/components.module.ts
@@ -17,6 +17,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile-field';
+import { CoreComponentsModule } from '../../../components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { CoreUserProfileFieldComponent } from './user-profile-field/user-profile
CommonModule,
IonicModule,
TranslateModule.forChild(),
+ CoreComponentsModule
],
providers: [
],
diff --git a/src/core/user/components/user-profile-field/user-profile-field.html b/src/core/user/components/user-profile-field/user-profile-field.html
index 825590342..1f3a37007 100644
--- a/src/core/user/components/user-profile-field/user-profile-field.html
+++ b/src/core/user/components/user-profile-field/user-profile-field.html
@@ -1,2 +1 @@
-
-
\ No newline at end of file
+
diff --git a/src/core/user/components/user-profile-field/user-profile-field.ts b/src/core/user/components/user-profile-field/user-profile-field.ts
index 0058e9a9a..7cbd32d4f 100644
--- a/src/core/user/components/user-profile-field/user-profile-field.ts
+++ b/src/core/user/components/user-profile-field/user-profile-field.ts
@@ -12,8 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, OnInit } from '@angular/core';
-import { CoreLoggerProvider } from '../../../../providers/logger';
+import { Component, Input, OnInit } from '@angular/core';
import { CoreUserProfileFieldDelegate } from '../../providers/user-profile-field-delegate';
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
@@ -31,74 +30,23 @@ export class CoreUserProfileFieldComponent implements OnInit {
@Input() form?: any; // Form where to add the form control. Required if edit=true or signup=true.
@Input() registerAuth?: string; // Register auth method. E.g. 'email'.
- // Get the containers where to inject dynamic components. We use a setter because they might be inside a *ngIf.
- @ViewChild('userProfileField', { read: ViewContainerRef }) set userProfileField(el: ViewContainerRef) {
- if (this.field) {
- this.createComponent(this.ufDelegate.getComponent(this.field, this.signup), el);
- } else {
- // The component hasn't been initialized yet. Store the container.
- this.fieldContainer = el;
- }
- }
+ componentClass: any; // The class of the component to render.
+ data: any = {}; // Data to pass to the component.
- protected logger;
-
- // Instances and containers of all the components that the handler could define.
- protected fieldContainer: ViewContainerRef;
- protected fieldInstance: any;
-
- constructor(logger: CoreLoggerProvider, private factoryResolver: ComponentFactoryResolver,
- private ufDelegate: CoreUserProfileFieldDelegate, private utilsProvider: CoreUtilsProvider) {
- this.logger = logger.getInstance('CoreUserProfileFieldComponent');
- }
+ constructor(private ufDelegate: CoreUserProfileFieldDelegate, private utilsProvider: CoreUtilsProvider) { }
/**
* Component being initialized.
*/
ngOnInit(): void {
- this.createComponent(this.ufDelegate.getComponent(this.field, this.signup), this.fieldContainer);
- }
+ this.componentClass = this.ufDelegate.getComponent(this.field, this.signup);
- /**
- * Create a component, add it to a container and set the input data.
- *
- * @param {any} componentClass The class of the component to create.
- * @param {ViewContainerRef} container The container to add the component to.
- * @return {boolean} Whether the component was successfully created.
- */
- protected createComponent(componentClass: any, container: ViewContainerRef): boolean {
- if (!componentClass || !container) {
- // No component to instantiate or container doesn't exist right now.
- return false;
- }
-
- if (this.fieldInstance && container === this.fieldContainer) {
- // Component already instantiated and the component hasn't been destroyed, nothing to do.
- return true;
- }
-
- try {
- // Create the component and add it to the container.
- const factory = this.factoryResolver.resolveComponentFactory(componentClass),
- componentRef = container.createComponent(factory);
-
- this.fieldContainer = container;
- this.fieldInstance = componentRef.instance;
-
- // Set the Input data.
- this.fieldInstance.field = this.field;
- this.fieldInstance.edit = this.utilsProvider.isTrueOrOne(this.edit);
- if (this.edit) {
- this.fieldInstance.signup = this.utilsProvider.isTrueOrOne(this.signup);
- this.fieldInstance.disabled = this.utilsProvider.isTrueOrOne(this.field.locked);
- this.fieldInstance.form = this.form;
- }
-
- return true;
- } catch (ex) {
- this.logger.error('Error creating user field component', ex, componentClass);
-
- return false;
+ this.data.field = this.field;
+ this.data.edit = this.utilsProvider.isTrueOrOne(this.edit);
+ if (this.edit) {
+ this.data.signup = this.utilsProvider.isTrueOrOne(this.signup);
+ this.data.disabled = this.utilsProvider.isTrueOrOne(this.field.locked);
+ this.data.form = this.form;
}
}
}