NavParams Alternatives in Ionic 4
Ionic 3 provided a unified way for passing parameters to newly opened pages - the NavParams
object. In the target page constructor, it could be used to get any parameters passed to that page:
constructor(private navParams: NavParams) {
this.item = this.navParams.get("item");
}
For regular pages pushed onto the navigation stack, the parameters were passed as an argument to the NavController::push
method:
this.navCtrl.push("RegularPage", { item: this.item });
For modal pages, they were a part of the options passed to the ModalController::create
method:
this.modalCtrl.create(ModalPage, { item: this.item }).present();
Ionic 4 doesn't have a universal NavParams
object anymore. Navigation is based on Angular routing. Hence the preferred way for passing parameters to a page are route parameters. Since this makes them a part of the URL, they can't be structured objects anymore. Instead only IDs should be passed around and the target page should be responsible for retrieving the corresponding full object.
When writing a new application from scratch this isn't too much of an issue. However, when upgrading an existing Ionic 3 application, it's best if you can avoid such code changes. Even without them, there's enough to go wrong in the process. Fortunately, Angular also supports passing of custom state as part of the navigation (I'm using Ionic's NavController
wrapper instead of Angular router directly):
this.navCtrl.navigateForward("/regular", { state: { item: this.item } });
This information must be retrieved in the target page constructor. It's not available anymore later in the page lifecycle:
constructor(private router: Router) {
if (this.router.getCurrentNavigation().extras.state) {
this.item = this.router.getCurrentNavigation().extras.state.item;
}
}
The approach mostly worked well, but not in all cases. When I tried to pass across a Moment
instance, the navigation failed with a DataCloneError
:
DataCloneError: Failed to execute 'pushState' on 'History': function (number) {
var b = number % 10,
output = (toInt(number % 100 / 10) === 1) ...<omitted>... } could not be cloned.
This worked just fine in Ionic 3. Fortunately, the target page didn't really need the full Moment
instance. It immediately converted it to a JavaScript Date
anyway, so I resolved the issue by converting the value before passing it as a parameter.
For modal pages, a different approach must be used. Parameters are passed as part of the options passed to the ModalController::create
method, similar as Ionic 3:
(await this.modalCtrl.create({
component: ModalPage,
componentProps: { item: this.item }
})).present();
These parameters are now injected into the target page as input properties:
export class ModalPage {
@Input()
item: Item;
}
Using the above-described approaches, I could upgrade the passing of navigation parameters in a rather large Ionic 3 application to Ionic 4 without too many related code changes.