forked from EVOgeek/Vmeda.Online
		
	MOBILE-2472 course: Fix spinner shown forever when changing format
This commit is contained in:
		
							parent
							
								
									e6c5607463
								
							
						
					
					
						commit
						9f327bd32f
					
				| @ -67,6 +67,7 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck { | |||||||
|     container: ViewContainerRef; |     container: ViewContainerRef; | ||||||
|     protected logger: any; |     protected logger: any; | ||||||
|     protected differ: any; // To detect changes in the data input.
 |     protected differ: any; // To detect changes in the data input.
 | ||||||
|  |     protected lastComponent: any; | ||||||
| 
 | 
 | ||||||
|     constructor(logger: CoreLoggerProvider, protected factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers, |     constructor(logger: CoreLoggerProvider, protected factoryResolver: ComponentFactoryResolver, differs: KeyValueDiffers, | ||||||
|             @Optional() protected navCtrl: NavController, protected cdr: ChangeDetectorRef, protected element: ElementRef, |             @Optional() protected navCtrl: NavController, protected cdr: ChangeDetectorRef, protected element: ElementRef, | ||||||
| @ -87,7 +88,13 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck { | |||||||
|      * Detect changes on input properties. |      * Detect changes on input properties. | ||||||
|      */ |      */ | ||||||
|     ngOnChanges(changes: { [name: string]: SimpleChange }): void { |     ngOnChanges(changes: { [name: string]: SimpleChange }): void { | ||||||
|         if (!this.instance && changes.component) { | 
 | ||||||
|  |         if (changes.component && !this.component) { | ||||||
|  |             // Component not set, destroy the instance if any.
 | ||||||
|  |             this.lastComponent = undefined; | ||||||
|  |             this.instance = undefined; | ||||||
|  |             this.container && this.container.clear(); | ||||||
|  |         } else if (changes.component && (!this.instance || this.component != this.lastComponent)) { | ||||||
|             this.createComponent(); |             this.createComponent(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -127,6 +134,8 @@ export class CoreDynamicComponent implements OnInit, OnChanges, DoCheck { | |||||||
|      * @return {boolean} Whether the component was successfully created. |      * @return {boolean} Whether the component was successfully created. | ||||||
|      */ |      */ | ||||||
|     protected createComponent(): boolean { |     protected createComponent(): boolean { | ||||||
|  |         this.lastComponent = this.component; | ||||||
|  | 
 | ||||||
|         if (!this.component || !this.container) { |         if (!this.component || !this.container) { | ||||||
|             // No component to instantiate or container doesn't exist right now.
 |             // No component to instantiate or container doesn't exist right now.
 | ||||||
|             return false; |             return false; | ||||||
|  | |||||||
| @ -50,8 +50,8 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR | |||||||
|     protected eventsProvider: CoreEventsProvider; |     protected eventsProvider: CoreEventsProvider; | ||||||
|     protected modulePrefetchDelegate: CoreCourseModulePrefetchDelegate; |     protected modulePrefetchDelegate: CoreCourseModulePrefetchDelegate; | ||||||
| 
 | 
 | ||||||
|     constructor(injector: Injector, protected content?: Content) { |     constructor(injector: Injector, protected content?: Content, loggerName: string = 'CoreCourseModuleMainResourceComponent') { | ||||||
|         super(injector); |         super(injector, loggerName); | ||||||
| 
 | 
 | ||||||
|         this.sitesProvider = injector.get(CoreSitesProvider); |         this.sitesProvider = injector.get(CoreSitesProvider); | ||||||
|         this.courseProvider = injector.get(CoreCourseProvider); |         this.courseProvider = injector.get(CoreCourseProvider); | ||||||
| @ -120,10 +120,28 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR | |||||||
|      * @return {Promise<any>} Resolved when done. |      * @return {Promise<any>} Resolved when done. | ||||||
|      */ |      */ | ||||||
|     protected refreshContent(sync: boolean = false, showErrors: boolean = false): Promise<any> { |     protected refreshContent(sync: boolean = false, showErrors: boolean = false): Promise<any> { | ||||||
|  |         if (!this.module) { | ||||||
|  |             // This can happen if course format changes from single activity to weekly/topics.
 | ||||||
|  |             return Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         this.refreshIcon = 'spinner'; |         this.refreshIcon = 'spinner'; | ||||||
|         this.syncIcon = 'spinner'; |         this.syncIcon = 'spinner'; | ||||||
| 
 | 
 | ||||||
|         return this.invalidateContent().catch(() => { |         // Wrap the call in a try/catch so the workflow isn't interrupted if an error occurs.
 | ||||||
|  |         // E.g. when changing course format we cannot know when will this.module become undefined, so it could cause errors.
 | ||||||
|  |         let promise; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             promise = this.invalidateContent(); | ||||||
|  |         } catch (ex) { | ||||||
|  |             // An error ocurred in the function, log the error and just resolve the promise so the workflow continues.
 | ||||||
|  |             this.logger.error(ex); | ||||||
|  | 
 | ||||||
|  |             promise = Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return promise.catch(() => { | ||||||
|             // Ignore errors.
 |             // Ignore errors.
 | ||||||
|         }).then(() => { |         }).then(() => { | ||||||
|             return this.loadContent(true, sync, showErrors); |             return this.loadContent(true, sync, showErrors); | ||||||
| @ -191,7 +209,25 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR | |||||||
|     protected loadContent(refresh?: boolean, sync: boolean = false, showErrors: boolean = false): Promise<any> { |     protected loadContent(refresh?: boolean, sync: boolean = false, showErrors: boolean = false): Promise<any> { | ||||||
|         this.isOnline = this.appProvider.isOnline(); |         this.isOnline = this.appProvider.isOnline(); | ||||||
| 
 | 
 | ||||||
|         return this.fetchContent(refresh, sync, showErrors).catch((error) => { |         if (!this.module) { | ||||||
|  |             // This can happen if course format changes from single activity to weekly/topics.
 | ||||||
|  |             return Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Wrap the call in a try/catch so the workflow isn't interrupted if an error occurs.
 | ||||||
|  |         // E.g. when changing course format we cannot know when will this.module become undefined, so it could cause errors.
 | ||||||
|  |         let promise; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             promise = this.fetchContent(refresh, sync, showErrors); | ||||||
|  |         } catch (ex) { | ||||||
|  |             // An error ocurred in the function, log the error and just resolve the promise so the workflow continues.
 | ||||||
|  |             this.logger.error(ex); | ||||||
|  | 
 | ||||||
|  |             promise = Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return promise.catch((error) => { | ||||||
|             if (!refresh) { |             if (!refresh) { | ||||||
|                 // Some call failed, retry without using cache since it might be a new activity.
 |                 // Some call failed, retry without using cache since it might be a new activity.
 | ||||||
|                 return this.refreshContent(sync); |                 return this.refreshContent(sync); | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| 
 | 
 | ||||||
| import { OnInit, OnDestroy, Input, Output, EventEmitter, Injector } from '@angular/core'; | import { OnInit, OnDestroy, Input, Output, EventEmitter, Injector } from '@angular/core'; | ||||||
| import { TranslateService } from '@ngx-translate/core'; | import { TranslateService } from '@ngx-translate/core'; | ||||||
|  | import { CoreLoggerProvider } from '@providers/logger'; | ||||||
| import { CoreDomUtilsProvider } from '@providers/utils/dom'; | import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||||
| import { CoreCourseHelperProvider } from '@core/course/providers/helper'; | import { CoreCourseHelperProvider } from '@core/course/providers/helper'; | ||||||
| @ -54,7 +55,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|     protected moduleDelegate: CoreCourseModuleDelegate; |     protected moduleDelegate: CoreCourseModuleDelegate; | ||||||
|     protected courseSectionPage: CoreCourseSectionPage; |     protected courseSectionPage: CoreCourseSectionPage; | ||||||
| 
 | 
 | ||||||
|     constructor(injector: Injector) { |     protected logger; | ||||||
|  | 
 | ||||||
|  |     constructor(injector: Injector, loggerName: string = 'CoreCourseModuleMainResourceComponent') { | ||||||
|         this.textUtils = injector.get(CoreTextUtilsProvider); |         this.textUtils = injector.get(CoreTextUtilsProvider); | ||||||
|         this.courseHelper = injector.get(CoreCourseHelperProvider); |         this.courseHelper = injector.get(CoreCourseHelperProvider); | ||||||
|         this.translate = injector.get(TranslateService); |         this.translate = injector.get(TranslateService); | ||||||
| @ -62,6 +65,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|         this.moduleDelegate = injector.get(CoreCourseModuleDelegate); |         this.moduleDelegate = injector.get(CoreCourseModuleDelegate); | ||||||
|         this.courseSectionPage = injector.get(CoreCourseSectionPage, null); |         this.courseSectionPage = injector.get(CoreCourseSectionPage, null); | ||||||
|         this.dataRetrieved = new EventEmitter(); |         this.dataRetrieved = new EventEmitter(); | ||||||
|  | 
 | ||||||
|  |         const loggerProvider = injector.get(CoreLoggerProvider); | ||||||
|  |         this.logger = loggerProvider.getInstance(loggerName); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -84,7 +90,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|      * @return {Promise<any>} Promise resolved when done. |      * @return {Promise<any>} Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise<any> { |     doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise<any> { | ||||||
|         if (this.loaded) { |         if (this.loaded && this.module) { | ||||||
|             /* If it's a single activity course and the refresher is displayed within the component, |             /* If it's a single activity course and the refresher is displayed within the component, | ||||||
|                call doRefresh on the section page to refresh the course data. */ |                call doRefresh on the section page to refresh the course data. */ | ||||||
|             let promise; |             let promise; | ||||||
| @ -113,9 +119,27 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|      * @return {Promise<any>} Resolved when done. |      * @return {Promise<any>} Resolved when done. | ||||||
|      */ |      */ | ||||||
|      protected refreshContent(sync: boolean = false, showErrors: boolean = false): Promise<any> { |      protected refreshContent(sync: boolean = false, showErrors: boolean = false): Promise<any> { | ||||||
|  |         if (!this.module) { | ||||||
|  |             // This can happen if course format changes from single activity to weekly/topics.
 | ||||||
|  |             return Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         this.refreshIcon = 'spinner'; |         this.refreshIcon = 'spinner'; | ||||||
| 
 | 
 | ||||||
|         return this.invalidateContent().catch(() => { |         // Wrap the call in a try/catch so the workflow isn't interrupted if an error occurs.
 | ||||||
|  |         // E.g. when changing course format we cannot know when will this.module become undefined, so it could cause errors.
 | ||||||
|  |         let promise; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             promise = this.invalidateContent(); | ||||||
|  |         } catch (ex) { | ||||||
|  |             // An error ocurred in the function, log the error and just resolve the promise so the workflow continues.
 | ||||||
|  |             this.logger.error(ex); | ||||||
|  | 
 | ||||||
|  |             promise = Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return promise.catch(() => { | ||||||
|             // Ignore errors.
 |             // Ignore errors.
 | ||||||
|         }).then(() => { |         }).then(() => { | ||||||
|             return this.loadContent(true); |             return this.loadContent(true); | ||||||
| @ -150,6 +174,24 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|      * @return {Promise<any>} Promise resolved when done. |      * @return {Promise<any>} Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     protected loadContent(refresh?: boolean): Promise<any> { |     protected loadContent(refresh?: boolean): Promise<any> { | ||||||
|  |         if (!this.module) { | ||||||
|  |             // This can happen if course format changes from single activity to weekly/topics.
 | ||||||
|  |             return Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Wrap the call in a try/catch so the workflow isn't interrupted if an error occurs.
 | ||||||
|  |         // E.g. when changing course format we cannot know when will this.module become undefined, so it could cause errors.
 | ||||||
|  |         let promise; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             promise = this.fetchContent(refresh); | ||||||
|  |         } catch (ex) { | ||||||
|  |             // An error ocurred in the function, log the error and just resolve the promise so the workflow continues.
 | ||||||
|  |             this.logger.error(ex); | ||||||
|  | 
 | ||||||
|  |             promise = Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return this.fetchContent(refresh).catch((error) => { |         return this.fetchContent(refresh).catch((error) => { | ||||||
|             // Error getting data, fail.
 |             // Error getting data, fail.
 | ||||||
|             this.domUtils.showErrorModalDefault(error, this.fetchContentDefaultError, true); |             this.domUtils.showErrorModalDefault(error, this.fetchContentDefaultError, true); | ||||||
|  | |||||||
| @ -68,6 +68,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     loaded: boolean; |     loaded: boolean; | ||||||
| 
 | 
 | ||||||
|     protected sectionStatusObserver; |     protected sectionStatusObserver; | ||||||
|  |     protected lastCourseFormat: string; | ||||||
| 
 | 
 | ||||||
|     constructor(private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService, private injector: Injector, |     constructor(private cfDelegate: CoreCourseFormatDelegate, translate: TranslateService, private injector: Injector, | ||||||
|             private courseHelper: CoreCourseHelperProvider, private domUtils: CoreDomUtilsProvider, |             private courseHelper: CoreCourseHelperProvider, private domUtils: CoreDomUtilsProvider, | ||||||
| @ -192,32 +193,29 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|      * Get the components classes. |      * Get the components classes. | ||||||
|      */ |      */ | ||||||
|     protected getComponents(): void { |     protected getComponents(): void { | ||||||
|         if (this.course) { |         if (this.course && this.course.format != this.lastCourseFormat) { | ||||||
|             if (!this.courseFormatComponent) { |             this.lastCourseFormat = this.course.format; | ||||||
|                 this.cfDelegate.getCourseFormatComponent(this.injector, this.course).then((component) => { | 
 | ||||||
|                     this.courseFormatComponent = component; |             // Format has changed or it's the first time, load all the components.
 | ||||||
|                 }); |             this.cfDelegate.getCourseFormatComponent(this.injector, this.course).then((component) => { | ||||||
|             } |                 this.courseFormatComponent = component; | ||||||
|             if (!this.courseSummaryComponent) { |             }); | ||||||
|                 this.cfDelegate.getCourseSummaryComponent(this.injector, this.course).then((component) => { | 
 | ||||||
|                     this.courseSummaryComponent = component; |             this.cfDelegate.getCourseSummaryComponent(this.injector, this.course).then((component) => { | ||||||
|                 }); |                 this.courseSummaryComponent = component; | ||||||
|             } |             }); | ||||||
|             if (!this.sectionSelectorComponent) { | 
 | ||||||
|                 this.cfDelegate.getSectionSelectorComponent(this.injector, this.course).then((component) => { |             this.cfDelegate.getSectionSelectorComponent(this.injector, this.course).then((component) => { | ||||||
|                     this.sectionSelectorComponent = component; |                 this.sectionSelectorComponent = component; | ||||||
|                 }); |             }); | ||||||
|             } | 
 | ||||||
|             if (!this.singleSectionComponent) { |             this.cfDelegate.getSingleSectionComponent(this.injector, this.course).then((component) => { | ||||||
|                 this.cfDelegate.getSingleSectionComponent(this.injector, this.course).then((component) => { |                 this.singleSectionComponent = component; | ||||||
|                     this.singleSectionComponent = component; |             }); | ||||||
|                 }); | 
 | ||||||
|             } |             this.cfDelegate.getAllSectionsComponent(this.injector, this.course).then((component) => { | ||||||
|             if (!this.allSectionsComponent) { |                 this.allSectionsComponent = component; | ||||||
|                 this.cfDelegate.getAllSectionsComponent(this.injector, this.course).then((component) => { |             }); | ||||||
|                     this.allSectionsComponent = component; |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| <div padding> | <div padding> | ||||||
|     <core-course-module-description [description]="module.description"></core-course-module-description> |     <core-course-module-description [description]="module && module.description"></core-course-module-description> | ||||||
|     <h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2> |     <h2 *ngIf="!isDisabledInSite && isSupportedByTheApp">{{ 'core.whoops' | translate }}</h2> | ||||||
|     <h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2> |     <h2 *ngIf="isDisabledInSite || !isSupportedByTheApp">{{ 'core.uhoh' | translate }}</h2> | ||||||
| 
 | 
 | ||||||
| @ -8,7 +8,7 @@ | |||||||
|     <p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}</p> |     <p class="core-big" *ngIf="!isDisabledInSite && !isSupportedByTheApp">{{ 'core.course.activitynotyetviewableremoteaddon' | translate }}</p> | ||||||
|     <p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p> |     <p *ngIf="isDisabledInSite || !isSupportedByTheApp"><strong>{{ 'core.course.askadmintosupport' | translate }}</strong></p> | ||||||
| 
 | 
 | ||||||
|     <div *ngIf="module.url"> |     <div *ngIf="module && module.url"> | ||||||
|         <p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p> |         <p><strong>{{ 'core.course.useactivityonbrowser' | translate }}</strong></p> | ||||||
|         <a ion-button block icon-end [href]="module.url" core-link> |         <a ion-button block icon-end [href]="module.url" core-link> | ||||||
|             {{ 'core.openinbrowser' | translate }} |             {{ 'core.openinbrowser' | translate }} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user