Posts about Ionic 2/3
Support for custom transitions between pages in Ionic framework (e.g. when opening a modal page) has never been well documented. Fortunately, there are blog posts for both Ionic 3 and Ionic 4 which provide more information and can serve as a good starting point for creating your own custom transitions. But even with all that, it can be tricky to convert existing custom Ionic 3 transitions to Ionic 4 when upgrading an application.
Including a hyperlink in a checkbox label is a common way to provide more information about the choice the user is making. Unfortunately, in Ionic such a hyperlink doesn't work out of the box because the whole label acts as toggle for the checkbox. There's an easy way to make it work, though.
Many JavaScript developers are used to inspecting the web page and the state of JavaScript variables using the browser developer tools. The browser console window can even be used for executing arbitrary JavaScript code to affect the web page/application at runtime. However, when using a SPA framework like Angular instead of vanilla JavaScript it's not as easy anymore to access the JavaScript objects of interest such as components and services. Fortunately, Angular provides means to access them, although they aren't documented well.
I've written about TypeScript imports on my blog before, but as I recently learned, I haven't covered all the cases. The type definitions for the Google Maps JavaScript API contain no modules, only a namespace. Therefore, they can't be imported using the standard import directive. I was stuck until I found an excellent resource on Stack Overflow.
There are lots of components included with Ionic framework, but not many of them can be used inside a Navbar. Fortunately, with some resourcefulness, it's easy enough to create a solution of your own by combining together multiple built-in components.
If you're developing applications for Ionic or Angular, you have probably already encountered static forRoot() and forChild() methods which you need to call when importing other modules, such as ngx-translate. You might not be fully aware of their significance, but when developing your own shared modules, you'll likely need to learn more about them.
Surprisingly, there's no easy to use functionality built into Ionic to find a specific page in the navigation stack by its name and pop as many pages as necessary to reach it. Fortunately it's not too difficult to implement this on our own, thanks to the undocumented popTo method in NavController.
In the previous blogpost, I created a wrapper function for creating an alert in Ionic which returned a promise with user's input. Although alerts in Ionic are quite flexible, you'll eventually need to use a modal page instead of an alert. There's no reason why modals couldn't be wrapped into a function in a similar manner.
Alerts are a great way for collecting simple inputs from the user with minimum effort. The examples in the official documentation contain business logic directly in button handlers. Wouldn't it be more convenient if the code for displaying the alert could be wrapped in a separate function returning the value entered by the user?
In a previous blogpost, I've described how to intercept console log output when the application is running on the device, so that it can later be exported using the standard sharing functionality. Although this is usually the most convenient approach for testers, it's an overkill during development. In such a scenario, it's more effective to look at the console output from the debugger.
Quick switching between tabs in Ionic can cause issues when one of the tabs requires a long initialization process every time it is displayed, as for example native Google Maps do. Before the initialization is completed, the user might already leave the tab and then navigate back to it, triggering another initialization in parallel to the first one. One way to avoid the issue is by disabling the switching between tabs until the page initialization is complete.
Ionic Generate command is a handy tool for creating new pages, components, providers and other file types in Ionic applications. It strongly relies on the standard Ionic project structure. Since the recommended project structure has changed quite a lot since the initial release of Ionic 2, the command might not work as expected on older projects if their structure has not been kept up-to-date.
Lazy loading was introduced in Ionic 3 to reduce application startup time. It started out as an experimental feature, but has since then become the default way for building Ionic applications. However, even with lazy loading enabled, application performance can be tweaked further with different configurations options.
In one of my previous posts, I've written about changing the config.xml file when building an app for different environments. However, sometimes that's not enough. You might want to make other changes in the application which are only possible in code, e.g. have a different tracking ID for Google Analytics or allow sharing the console log.
Modal and regular pages are very similar in Ionic. When using lazy loading their name must be passed to the controller instead of their type, otherwise they will fail to open. However, with module preloading enabled, this issue might sometimes not manifest itself.
After we upgraded the Cordova version on our build server from 6.5.0 to 7.1.0, we noticed a large increase in build time for our project. By looking at detailed build times, we could attribute all of it to a single command: cordova prepare.
During development, Ionic replaces the default Angular error handler with its own implementation which displays the error details in a page overlay instead of just printing them out to console. If you want to automatically report these unhandled errors to your analytics service, you can replace that error handler with your own custom one.
Angular comes with built-in Cross Site Scripting (XSS) protection, which prevents you from using unverified dynamic values in certain contexts inside your generated page. Most of the time you shouldn't even notice this. But when you do, it's good to know how you can work around the restrictions set by this protection.
Flexbox greatly simplifies many HTML layout scenarios. Although it is already broadly supported in browsers, sometimes incomplete implementations can still make your life difficult. For example, in version 10 of iOS Safari, height of flexbox children isn't treated as explicitly set when defined by the parent flex container.
Slides is a highly configurable Ionic component, even without accessing the underlying Swiper API directly. In this post I will make it show a small part of the neighboring slide on both sides.
There are two functions for dismissing a loading indicator instance in Ionic: dismiss and dismissAll. The former will only close the specific instance, while the latter will close all currently opened instances. However, it's better to avoid dismissAll unless you really need it, because it could leave an instance open which would be closed correctly if dismiss was used instead.
Logging to browser console can be a useful tool for troubleshooting Ionic applications during development. Although all the logging is still done in test builds, the process of getting the log from the device is not tester-friendly. Without too much effort this experience can be improved a lot by adding an option to export the log directly from the application.
RxJS used to encourage monkey patching of operators and helper functions onto the Observable object. However, this has an unfortunate side effect of making the imports available everywhere. Removing an import from one file can inadvertently break code in other files. To alleviate this problem, alternative imports in the form of lettable operators are available since RxJS 5.5.
Ionic 3.5 introduced the concept of multiple root navigation elements to fully support SplitPane, for example. This required API changes, among others making App.getRootNav() function deprecated. However, there's still no good answer to what the value of the required parameter for the replacement function should be.
Ionic serve can be a very useful tool for tweaking the design of pages in Ionic applications. However, if your application is using native plugins, some of them might fail with Ionic serve.
Cordova config.xml file contains some information that might be different between the test and the production builds of your application, e.g. preference values or even the application id. This could be solved by having a separate branch in source control with these changes, but you could also modify the values just before you start the build on the build server.
Ionic framework (as well as Cordova, which it is based on) do a great job at abstracting away the details about the platform that the application is currently running on. There are ways to get that information from Cordova, but it's important to understand what exactly the values returned mean.
To reference DOM elements in the component template from the component code, ViewChild and ViewChildren decorators can be used. Similarly, ContentChild and ContentChildren decorators will provide access to DOM elements in the component content. Still, I had a hard time coming up with a way to support a scenario where the component consumer should be able to tag some of the DOM elements that need to be processed by the component.
Angular directives are a great way to extend behavior of Angular components and HTML elements. As long as you only need a reference to the host HTML element to implement your functionality, Angular dependency injection will easily inject it as an ElementRef, along with a Renderer to modify it. If you also require a reference to the host component, it gets a little more complicated.
Slides is a very flexible Ionic component for presenting multiple slides to the user who can swipe between them. However, not all its customization options are exposed as Angular Inputs and Outputs or even fully documented. To see all supported options, one can peek into the source code. The only way to learn more about them is to check the Swiper API reference, which the Slides component is based on.
Ionic applications have built-in support for Android's hardware back button. For the root page it closes the application by default. There are ways to change that behavior, though.
Although the official Ionic templates aren't preconfigured for unit testing, there is no lack of guidance in this field. It's not all that difficult to get started with unit testing any more. However, as the number of tests in the project will start to increase, it will soon become obvious that the test are quite slow.
Ionic Native makes it very convenient to use Cordova plugins from Ionic applications. Although Ionic Native provides an impressive collection of wrappers for many Cordova plugins, there are still Cordova plugins out there without a corresponding plugin. In such cases you will need to either use them directly without a wrapper or write your own wrapper. The latter option is much simpler than you might think.
If you want to use Google Analytics as the analytics tool for your Ionic mobile application or progressive web application (PWA), there's an Ionic Native wrapper available for the Cordova plugin with support for mobile platforms as well as the browser (web) platform. Unfortunately, it consistently threw errors for me, when I tried to send a screenview event for the entry page.
When implementing 3D Secure with Braintree for a web page, the bank's verification page is passed into the JavaScript function as an iframe element to embed into the web page. Unfortunately, the bank pages have fixed 400px width, therefore they don't fully fit on narrower mobile screens.
By default, all text in Ionic 2 uses Roboto font, which is also bundled with the framework and automatically distributed with every created application. This all sounded great, until I noticed that some characters are rendered with a different font.
Ionic has no built-in support for Firebase Cloud Messaging (FCM), which is now also Google's official push notification infrastructure for Android. However, since Ionic is based on Cordova, it's still easy to make it work with one of the available Cordova plugins.
I have finally updated Android SDK to the latest version, because I wanted Android Studio to stop informing me about available updates on every startup. Unfortunately several breaking changes have been introduced since the version I was using before, which altogether broke my regular flow of work.
I've been doing a lot of Ionic 2 development lately in Visual Studio Code lately. The editor has great out-of-the-box support for TypeScript, HTML and CSS editing. There's also a lively ecosystem for extensions, which can improve the development experience even further. I'm going to describe my current configuration and the selection of extensions that I'm using.
The biggest advantage of having a formal description for a RESTful API is the ability to programmatically generate client-side code for calling the service. Unfortunately, it turned out that Swagger tooling still leaves much to be desired, at least for generating TypeScript Angular code.
Recently, I was troubleshooting a curious bug that only happened on one page in my Ionic 2 application: new values from an HTTP request only showed on the page after a click instead of immediately. Wrapping the update code in NgZone.run() helped. However, it bothered me why this was only necessary in this single instance.
Let's create an Ionic 2 page that auto-refreshes at regular intervals with a twist: there's also a button for manual refresh which triggers an immediate refresh. We'll implement it in two different ways: with standard JavaScript functions and with RxJS.
I keep getting impressed by how feature-rich dependency injection in Angular is. This time I needed it to inject the appropriate implementation of a dependency based on runtime information. Of course, the scenario is well supported.
Angular has an impressive dependency injection system, however some aspects could be documented better. Old blog posts explaining how things worked before the final release don't help either. Hence, it took me a while to successfully intercept HTTP requests and inject a common parameter.
When using tabs in Ionic 2, each one of them contains a page that doesn't know anything about the other pages nor their common parent page hosting the tabs. This makes it challenging to switch tabs or pass data between them.
Angular has great support for validating data in forms, both template-driven and and reactive ones, built imperatively with FormGroup. It is also easy to create own custom validators. However, I did not find it obvious, how to use injected dependencies in non-directive validators for reactive forms.
As a part of setting up the Ionic 2 project I am currently working on, I decided to also configure end-to-end testing using Protractor. I based it on the excellent Clicker demo project. It worked great for running tests during development, but lacks support for headless test execution on a build server.
Ionic 2 includes many components and native wrappers out of the box. However, you will probably want to share some of your own code between projects if you are working on more than one of them and they are at least remotely similar. Since Ionic 2 builds on top of Angular, shared modules are the right tool for the job.
Although there's a lot of talk about Ionic 2 being suitable for creating progressive web applications (PWA), there's little guidance on how to actually configure a project to achieve this. In this post I am listing everything I changed in my project, to build a mobile web application (not yet progressive).
Many Angular 2 and Ionic 2 APIs return RxJS observables. To unit test your code that's consuming them, you will need to create your own observable streams with test data. With this approach I wrote tests for code reacting to user's current geolocation.
By default, Ionic 2 produces unminified development builds. To force an optimized production build, you need to add --prod switch to ionic build or ionic run command. Since development build doesn't include Angular AoT (Ahead of Time) compilation, your production build might turn out broken even if development build of the application worked just fine.
The official Android emulator has a big disadvantage for regular users of Hyper-V: you cannot run the emulator accelerated when Hyper-V is enabled. Fortunately, there is an alternative: Visual Studio Emulator for Android, which uses Hyper-V for hardware acceleration.
Ionic 2 is the successor to the quite popular hybrid mobile framework. It is based upon Angular 2, but unlike it, it hasn't yet reached the final release; the latest version is Release Candidate 3. This makes it still a bit rough around the edges and lacking in documentation. Debugging with source maps is one of the features, which still pose a challenge to set up for many developers.