Reputation: 11
I have two UI component,
Tab3Page: Save the data
Tab2Page: Load the data
Tab2Page is injected to Tab3Page
I am trying to load data in Tab2Page automatically when, data is saved through Tabd3Page.
Currently, when i save the data in tab3, tab2 is not automatically updated until I refresh the page browser manually. Is there a way to force render a page like in react as setSate()
Following is component Tab3Page
@Component({
selector: 'app-tab3',
templateUrl: 'tab3.page.html',
styleUrls: ['tab3.page.scss']
})
export class Tab3Page implements OnInit {
pics: Picture[] = [];
constructor(public fileservice: FileService, private tab2: Tab2Page) {}
ngOnInit() {
console.log('ng init');
this.pics = PICS;
}
saveContent(pic: Picture) {
this.fileservice.savefile(pic);
this.tab2.updatePics();
this.tab2.refreshComponent();
}
}
Following is component Tab2Page
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page implements
OnInit,
OnChanges {
@Input() pics: Picture[];
constructor(public fileservice:FileService, private cdr: ChangeDetectorRef) { }
// constructor(public fileservice: FileService) { }
ngOnInit() {
console.log('ng init');
this.updatePics();
}
ngOnChanges(changes: SimpleChanges) {
// changes.prop contains the old and the new value...
console.log('changes', changes);
}
async updatePics() {
this.pics = await this.fileservice.getSavedPics();
}
refreshComponent() {
this.cdr.detectChanges();
console.log('component refresh triggred');
}
}
The data is binded in Html as following through pics variable in component Tab2Page
<ion-list *ngFor="let pic of pics">
<ion-item-sliding>
<ion-item>
<ion-grid>
<ion-row>
<ion-col size="3">
<ion-thumbnail>
<img [src]="(pic.url | safeurl)">
</ion-thumbnail>
</ion-col>
<ion-col size="9">
<ion-label>{{pic.name}}</ion-label>
</ion-col>
</ion-row>
</ion-grid>
</ion-item>
<ion-item-options side="end">
<ion-item-option>Delete</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</ion-list>
** UPDATE Tried to apply the suggested solution using ChangeDetectorRef However I got following error in the browser event though the compile was success.
core.js:9110 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[IonItemOption -> ChangeDetectorRef]:
StaticInjectorError(Platform: core)[IonItemOption -> ChangeDetectorRef]:
NullInjectorError: No provider for ChangeDetectorRef!
NullInjectorError: StaticInjectorError(AppModule)[IonItemOption -> ChangeDetectorRef]:
StaticInjectorError(Platform: core)[IonItemOption -> ChangeDetectorRef]:
NullInjectorError: No provider for ChangeDetectorRef!
at NullInjector.get (core.js:778)
at resolveToken (core.js:2564)
at tryResolveToken (core.js:2490)
at StaticInjector.get (core.js:2353)
at resolveToken (core.js:2564)
at tryResolveToken (core.js:2490)
at StaticInjector.get (core.js:2353)
at resolveNgModuleDep (core.js:26403)
at NgModuleRef_.get (core.js:27491)
at resolveNgModuleDep (core.js:26403)
at resolvePromise (zone-evergreen.js:797)
at resolvePromise (zone-evergreen.js:754)
at zone-evergreen.js:858
at ZoneDelegate.invokeTask (zone-evergreen.js:391)
at Object.onInvokeTask (core.js:34182)
at ZoneDelegate.invokeTask (zone-evergreen.js:390)
at Zone.runTask (zone-evergreen.js:168)
at drainMicroTaskQueue (zone-evergreen.js:559)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:469)
at invokeTask (zone-evergreen.js:1603)
As the above error suggest to add ChangeDetectorRef as provider, tried to do it in the module file. But got error again in the compile as the ChangeDetectorRef is not supported provider type.
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
RouterModule.forChild([{ path: '', component: Tab2Page }])
],
declarations: [Tab2Page, SafeurlPipe],
providers: [ChangeDetectorRef]
})
export class Tab2PageModule {}
[ng] ℹ 「wdm」: Compiling...
[ng]
[ng] ERROR in src/app/tab2/tab2.module.ts(17,15): error TS2322: Type 'typeof ChangeDetectorRef' is not assignable to type 'Provider'.
[ng] Type 'typeof ChangeDetectorRef' is not assignable to type 'TypeProvider'.
[ng] Cannot assign an abstract constructor type to a non-abstract constructor type.
[ng]
[ng] Date: 2019-08-12T04:20:20.951Z - Hash: 99468e1aeee0ce99f6f1
[ng] 105 unchanged chunks
** UPDATE (FIX) Could not get it done using the component dependency injection. However, was able to achieve same desired result using a shared data service between the component and using rxjs "Subjects" and subscribe. The process of doing it can be found on Angular documentation below. Its takes a bit to wrap head around it but is very powerful for dynamic UI rendering stuff.
https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
I am still a bit bugged by why I was not able to use ChangeDetectorRef in the ionic app incase I might need it in future.
Upvotes: 0
Views: 1368
Reputation: 8680
You do not need to use changeDetectorRef
for your problem. Your issue here is that in your Tab3Page
, you are trying to inject Tab2Page
and use it to call functions in Tab2Page
. You cannot inject components directly in other components and use them. See the docs to see how components can interact with each other. You can use ViewChild to call updatePics()
In Tab3Page
, remove Tab2Page
from the contructor and add ViewChild (import it from @angular/core
)
tab3.page.ts
export class Tab3Page implements OnInit {
pics: Picture[] = [];
@ViewChild('tab2') tab2: Tab2Page;
constructor(public fileservice: FileService) {}
ngOnInit() {
console.log('ng init');
this.pics = PICS;
}
saveContent(pic: Picture) {
this.fileservice.savefile(pic);
this.tab2.updatePics();
}
}
Add a template variable in your html so that ViewChild
can access the component.
tab3.page.html
<app-tab2 #tab2 [pics]="pics"></app-tab2>
There is one more way you can update the data. Since pics
is an Input
passed from Tab3Page
, simply move updatePics
from Tab2Page
to Tab3Page
and call it.
tab3.page.ts
export class Tab3Page implements OnInit {
pics: Picture[] = [];
constructor(public fileservice: FileService) {}
ngOnInit() {
console.log('ng init');
this.pics = PICS;
}
saveContent(pic: Picture) {
this.fileservice.savefile(pic);
this.updatePics();
}
async updatePics() {
this.pics = await this.fileservice.getSavedPics();
}
}
Upvotes: 1
Reputation: 19222
Inject ChangeDetectorRef
:
constructor(
private cdr: ChangeDetectorRef,
) {}
Then fire a change an event:
async updatePics() {
//do something
this.cdr.detectChanges();
}
Upvotes: 0