Ionic Mobile Development: Good and Bad

Ionic Mobile Development: Good and Bad

Ionic is an open source, cross-platform framework used to develop hybrid mobile applications. Ionic is a mobile app development framework based on the HTML5 programming language. The HTML5 framework always works with the help of Cordova or PhoneGap.

Ionic is an open source, cross-platform framework used to develop hybrid mobile applications. Ionic is a mobile app development framework based on the HTML5 programming language. The HTML5 framework always works with the help of Cordova or PhoneGap.

So you are going to build a mobile application. Traditionally, you would develop an app for two main platforms, **Android **(using **Java **or Kotlin) and iOS (using **Swift **or Objective C), natively. Native development offers high performance, easy access to hardware controls, API integration, and full functionality. But a native app also means that the expenses are doubled (or even tripled), depending on how many platforms you to want to cover. Thus you will have two separate apps, two code bases, two development teams, and expenses for them.

Instead, you can create a cross-platform app with the help of tools like **Xamarin **and React Native. These tools are close to native in performance and allow for code-sharing between the platforms, reducing the overall expenses on development. But still, you will need to hire native developers to do specific tasks in each of the code-bases.

If you are interested in differences between cross-platform vs native application development, you may read our dedicated article. But in this post, we will focus on another tool for mobile application development, that utilizes web technologies. You will learn what is the Ionic framework, what are the pros and cons of it, and what advantages it proposes over native and hybrid technologies for mobile applications.

What is Ionic?

Ionic isn’t new to the market of mobile applications development. Created in 2013 as an open-source SDK for hybrid mobile applications, now Ionic has more than 5 million apps built with it in total. It’s known to provide platform-specific UI elements through a library of native components for iOS and Android. Ionic is basically an npm module, which requires **Node.js **installed to function, being a part of a large JavaScript ecosystem.

**Front-end technologies and webview. **Ionic uses front-end technologies like HTML, CSS, JavaScript, and Angular for application development. Using web technologies, Ionic helps to build cross-platform mobile applications with a single codebase. Basically, it allows web developers to create web pages, that are run inside a device’s browser instance called Webview. Webview may come as a plugin, and it’s essentially an application component that renders web pages and displays them as a native application.

Apache Cordova & Angular based. First versions of Ionic were based on Angular, which is a popular front-end framework used for building dynamic web pages and progressive web applications, **PWA **for short. Ionic can use Angular CLI (Command-Line Interface) and components to create fully functional mobile applications.

Another part of **Ionic **responsible for accessing native functionality is based on Apache Cordova plugins. **Cordova **is a tool for building mobile applications using web technologies, relying on its own **APIs **instead of platform-specific ones. As long as Ionic uses Webview, it doesn’t have access to the device’s hardware **APIs **by default. Cordova provides those APIs packed as plugins to gain access to functions like smartphone’s camera, gyroscope, or sensors. These sets of APIs are also known as Cordova Bridge. Apache Cordova provides Ionic apps with access to native APIs, serving as a bridge between the webview and the device’s operating system.

*Ionic application in a nutshell *

**Ionic Native. **When it comes to building an application, you want to reach every piece of the required functionality. For that purpose, Ionic Native was created. It’s a set of Cordova plugins, designed to support standard APIs and integration. Ionic Native is available as a free set called Community Edition, and a paid one, Enterprise Edition, which is an extended version curated by Ionic team.

Ionic v.4 and web components

Since its creation, **Ionic **had been always dependent on Angular framework components, as a tool for **Angular **users. The change has come with the latest, fourth version of Ionic, which has brought a lot of new things.

With the fourth version, Ionic became framework-agnostic, meaning its independence of Angular. It’s planned to add support for React and Vue.js as well, but for now, Ionic can be used without any frameworks at all. The change was made possible thanks to the utilization of web components and the promotion of Ionic’s CLI. CLI has been refactored since the previous version and tailored to work with Angular CLI. So, you always can work with Angular, if you like it, but also use other supported frameworks to widen a technology stack that can be used with Ionic.

Another big change is a shift to web components. Web components are sets of features that use standard APIs natively supported in nearly all mobile browsers today. Thus, those can be deployed on any mobile platform or used to create desktop apps with Electron framework, or PWAs. The usage of web components also allows for the utilization of any frameworks with Ionic.

Web components are basically encapsulated HTML elements that are interoperable between each other. Each of these elements contains custom iOS and material design (Android) theme support by default. This makes theme-identity across numerous apps a fairly easy task. It was announced that Ionic will be distributed as a set of more than 100 web components. To support this initiative, Ionic team launched Stencil — a vast library of web components and a tool to build new ones.

Ionic starter pack

There are a couple of things you need to start developing with Ionic. Thanks to Ionic team, it has precise documentation that covers various topics, including beginner guides. So, in this section we would supply some links or recap mentioned ones in the article:

General purpose documentation. The documentation covers CLI installation, platform launches, app development start, and other information.

Official migration guide. The most popular version of Ionic remains the third version for today. As there are a lot of apps written on it, Ionic team has a concise migration guide on the Ionic version 4 in their documentation.

Stencil library for building and downloading web components.

Cordova plugins repository. Apache Cordova provides a set of APIs to access native functionality.

Capacitor plugins repository. Capacitor is another platform for Ionic, that provides APIs to connect with devices hardware. Its plugins can be downloaded from npm.

Integrations page, which provides a list of tools, modules, and native plugins, that can be integrated into your application.

Ionic offers wide capabilities for developing mobile applications and spread them across various platforms. But, as any technologies, it has its advantages and limitations. We’ll start with the advantages.

The Pros of Ionic Mobile Development

Ionic offers a number of conveniences for mobile application development, covering over 3.2 percent of the whole mobile app market, according to Appbrain.

A single code base across various platforms

Ionic was built on top of Angular framework and Apache Cordova, as well as using HTML 5, CSS, and JavaScript as core technologies for app development. While the latest version of Ionic offers framework-agnostic capabilities for the first time, you can still use Angular with all its pros and cons.

That said, Ionic allows you to build mobile applications without hiring native developers. Any person acquainted with web technologies and Angular can use it, leveraging web skills to create fully functional applications. Forming just one code-base for all of your platforms, guarantees:

  • Reduced costs on development, hiring native devs, maintenance of the code base
  • Faster time-to-market on both platforms
  • Ease of maintenance via built-in browser instruments and debugging tools
  • Availability of transforming your Ionic application into a desktop app or PWA

The economic purpose of utilizing Ionic is clear if you focus on the quick launch of the app in both application stores. Developing across Android, iOS, and maybe even Windows devices is a lot cheaper within a single code base, compared to native development.

Popular technologies and ease of learning

It’s not a secret that web technologies are the most widely spread, with JavaScript being the most popular programming language. According to Stack Overflow survey 2019, front-end developers are the third largest group of all developer types. Having Ionic as your mobile application development tool will ensure that you will have no problem hiring developers for your project.

Ionic is considered an easy-to-learn tool: front-end developers can quickly grasp the basics or choose between various web frameworks that Ionic supports.

Of course, having expertise in native development would only be a plus, as Ionic doesn’t compile the whole app into a native language. Instead, it compiles UI elements, using Cordova or Capacitor (a native bridge-platform for Ionic) plugins for the rest of the functionality. It’s easy to build and maintain an application just with the web technology stack. But if you will have to fix the plugin, or develop a custom one for some specific functionality, here you will need a native Android or iOS developer.

Wide range of integration capabilities and plugins

If you feel that you are not gaining enough of your Ionic application, you can always integrate it with numerous tools. The official list of technologies to integrate with can be found on Ionic’s website, providing easy access to analytical instruments, payment systems, security, and testing tools. It also contains a number of plugins which help integrate with device’s hardware. But, keep in mind, that some plugins are available as a part of the Enterprise version of Ionic, which requires payments to use Premier plugins and tools.

For more plugins, you can also check Cordova plugins list, which can be sorted by the platform availability. Or you can also use Capacitor plugins, downloading them from npm. A full procedure of using Capacitor plugins is described in the guide.

A vast choice of UI elements and quick prototyping

Older versions of Ionic have already proven to be efficient in mimicking the look and feel of native applications thanks to its UI components library. These components can be used as ready-made elements to construct your graphic user interface (GUI) or utilize those elements for customizations. In pair with web components, Ionic is capable of speeding up the process of developing UI logic and retain native look without additional costs.

UI components of Ionic consist of two parts, which can be broken in the actual graphic element of your GUI, and its functionality. Accessing the code of the UI component, you are capable of changing the way an element is working. You may add an animation to the button, modify the type of scrolling, reconstruct the order of items, and so on.

Another aspect that spices up the speed of Ionic development is prototyping capabilities. Using ready-made UI elements helps to create prototypes of your future applications in a comparably short-time period. For that purpose, you are free to use a prototyping tool called Ionic Creator. It’s maintained the by Ionic team, offering a drag & drop interface to construct interactive prototypes. Nevertheless, it can’t be used for constructing the whole app.

Ionic UI kit example

*Source: *Pinterest

Testing convenience

As long as Ionic apps work only via a Webview, the device’s browser can be used for testing the app. It is much more convenient because you don’t even have to use a testing device to ensure that everything runs smoothly. The same concept is applicable to the variety of mobile devices in the modern world.

Browsers offer built-in testing and debugging tools that made the whole testing process convenient. To test Angular components used in older versions, Angular CLI can be used, while Ionic CLI is suitable for web components testing. So, a testing device or emulator might be needed to test some native functionality only.

Concise documentation

What do we use the documentation for? Most often, when you have a question about the tool, you would research specific forums and communities to find the answer. In the case of Ionic, everything is grouped on their own website. The documentation is really exhaustive, covering every and each useful topic on what are the components of Ionic, how to use them, and how they interrelate. In the documentation, you also can find guides for various tasks on installing, configuring, launching, and fine-tuning various instruments used with Ionic.

Strong community

As long as creators of Ionic take care of accessibility of their tool for the users, the community is only growing. With more than 5 million developers and constant activity on the forum, you will be able to find the answer to any question, if it wasn’t covered in the documentation.

But, there is always a but. Like any technology, Ionic has its weaknesses.

The cons of Ionic to keep in mind

Performance is incomparable with native applications

When it comes to the performance of heavy applications, Ionic is barely a suitable option here. Using Webview to render the application, it shows good results for the common functionality of a mobile application. In case of heavy applications like Snapchat, that use augmented reality via smartphones camera, or graphics heavy apps (games, those rendering a lot of 3D models) will make your app crawl.

The reason is quite simple. Ionic renders its graphic elements via a browser, which takes several steps to start showing the image on the screen. The more we put in between, the more loading time will be. Add here Cordova callbacks and CSS animations loading.

Browser rendering broken by steps

*Source: *developers.google.com

In most cases, with a usual functionality, your performance will be good enough. Many community authorities like Josh Morony claim poor performance in Ionic apps to be the fault of bad code, not the framework itself. You might check hist exhaustive blog post discussing Ionic framework’s limitations in performance and ways to avoid them.

But in general, if performance is your primary goal, you would more likely choose another way to build your app. Xamarin and React show better results, as apps are compiled into native. Using languages that are close to machine code guarantees high performance of your application. In the case of Ionic, it’s possible to build high-performance apps, but you will have to study performance optimization techniques much deeper than it might be needed in React. If you want to know more of the differences between hybrid mobile development tools, you can check our comparison of Xamarin, React Native, Ionic, and NativeScript.

Plugin-dependent system

Every time you build an application with Ionic, you are bound to use plugins to access native functionality. With the overall number of ready-made plugins, it’s easy to find a package to implement the required functionality. However, there are cases when you would not find a plugin or module. In case you need some highly specific feature or access to a non-standard piece of hardware, you will have to develop the plugin on your own. The reason is that Ionic is not capable of implementing native plugins, without transforming it in JavaScript. That means you can go fully web, but if you want to use a bit of native code — it isn’t possible.

The case of plugin absence is very specific, and most often you can find a suitable module. If you need something that is not in store, you would probably have to create it with the help of a native developer.

Absence of hot reloading

There are a couple of techniques used to add changes to your code. In software engineering, hot reloading is considered a standard feature. Hot reloading allows you to apply changes without reloading the whole app. The file you are working on would refresh, allowing the app to continue working, and implement changes in a live mode.

Ionic takes time to get used to it, as it doesn’t provide hot reloading. Instead, it uses live reloading. Whenever you apply some changes, live reloading would refresh the whole app to make changes active. That means every time your developers want to apply changes, they would have their application restarted. This may sound okay, but when it comes to the speed of development, refreshing the app each time you update code may slow down the whole process. Developer-wise, it doesn’t provide much convenience when working on the app, so it is considered as a drawback.

Possible security issues

You should not consider that point as a con of Ionic on its own, rather a possible pitfall you can face while working with it. When building hybrid applications, security is a common issue, as long as your app can be reverse engineered. Since version 4, Ionic CLI does provide built-in code uglification — a common technique of making the code difficult to read by hackers. But you also need to know, that if you are using Angular CLI or older versions of Ionic, there is no code uglification going on. Your developers will have to uglify the code on their own.

There are a lot of ways to compromise what’s happening with your mobile app or PWA, like a man-in-the-middle attack. Why does it matter? Well, because basically, your Ionic application is a website, running on the device. The important thing you need to know is that Ionic communicates with the back-end using usual HTTP calls. So, you also want to use the usual security measures you use to protect your website applied to your Ionic application like using HTTPS instead of HTTP connection.

Application size

The issue may not seem as important as performance. But writing your app using HTML, CSS, and JavaScript means writing a lot of code and adding libraries, plugins, dependencies, etc. which make an app reasonably heavier than the native ones:

  • plugins (Cordova, Capacitor, Native Ionic plugins)
  • default libraries
  • dependencies (Angular, React, or Vue, depending on what framework you use)
  • CSS variables

The issue is completely true for Ionic version 3 apps, but in version 4, it was partially solved. Ionic CLI provides code uglification, which is one of the code minification techniques. You may also reduce the size of the icons, and delete unused styles, fonts, and images to minify the size of your app.

Which cross-platform tool to choose?

It’s important to understand in which cases you can different frameworks. Some of them are capable of solving the task without any difference in the final application. But the difference may be in effort, money, and time you spend developing it. So in which cases should you use Ionic?

Ionic over React Native/Xamarin/Native application

Ionic use is justified when you have strong expertise in using web technologies and Angular and experience in utilizing various JavaScript and Angular libraries. To get all the benefits from Ionic, it’s worth considering security and optimization measures first. This will help you avoid most of the downsides of the framework described above. Prototyping capabilities and short development time frames also serve a good reason to deliver an MVP, prototype, or a demo with Ionic. Obviously, in terms of performance, choosing Ionic for mobile games or other applications that require extensive use of phone hardware isn’t a good idea.

React Native over Ionic/Xamarin/Native application

Technology stack is a dominant factor that will determine your choice. Ionic and React Native both use JavaScript, but apply different approaches to render the application. Another factor to consider is that React Native doesn’t allow for developing two applications within a single code base. It uses React components instead of HTML that is rendered into native APIs. This results in higher performance but takes more time to develop an app. To see a more deep difference between those two, you can check our comparison of React and Angular.

Xamarin over Ionic/React Native/Native application

Xamarin is another popular cross-platform tool for developing mobile applications. It offers you performance much more close to native apps than Ionic and allows for code-sharing between the platforms, which is great. However, Xamarin is a product of Microsoft, so it requires expertise in Microsoft technology stack, namely .NET framework, and C# language. Xamarin.Forms is an additional tool commonly used for prototyping and active code sharing.

Native application over Ionic/React Native/Xamarin

If you heavily rely on the performance of your app and its stability, perhaps nothing can be better than a native application. Native code will integrate with all hardware APIs and leverage most of the platform’s capabilities in case your dev team has experience with Java/Kotlin (Android) and Swift/Objective-C (iOS). In the long run, maintaining two code bases may also be easier than a single one in an Ionic app.

Summing up

In terms of business, there are no bad or good tools. There are just tools tailored to solve specific tasks. In the case of Ionic, the task it solves is the development of applications across various platforms, utilizing well-known technologies. It helps teams to save budget, time, and effort in development.

If your development team has solid expertise in Angular framework and is well-acknowledged in using JavaScript, it’s possible to build a highly-performing application. But of course, nothing beats native application in terms of performance and user experience. So, the choice has to fall considering your priorities.

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

Run Your Ionic App on Android. Make sure you're using Java 8. Run ionic cordova prepare android. Open platforms/android in Android Studio, upgrade Gradle if prompted. Set launchMode to singleTask in AndroidManifest.xml. Start your app using Android Studio...

In this brief tutorial, I’ll show you to use Ionic for JHipster v4 with Spring Boot and JHipster 6.

To complete this tutorial, you’ll need to have Java 8+, Node.js 10+, and Docker installed. You’ll also need to create an Okta developer account.

Create a Spring Boot + Angular App with JHipster

You can install JHipster via Homebrew (brew install jhipster) or with npm.

npm i -g [email protected]

Once you have JHipster installed, you have two choices. There’s the quick way to generate an app (which I recommend), and there’s the tedious way of picking all your options. I don’t care which one you use, but you must select OAuth 2.0 / OIDCauthentication to complete this tutorial successfully.

Here’s the easy way:

mkdir app && cd app

echo "application { config { baseName oauth2, authenticationType oauth2, \
  buildTool gradle, testFrameworks [protractor] }}" >> app.jh

jhipster import-jdl app.jh

The hard way is you run jhipster and answer a number of questions. There are so many choices when you run this option that you might question your sanity. At last count, I remember reading that JHipster allows 26K+ combinations!

The project generation process will take a couple of minutes to complete if you’re on fast internet and have a bad-ass laptop. When it’s finished, you should see output like the following.

OIDC with Keycloak and Spring Security

JHipster has several authentication options: JWT, OAuth 2.0 / OIDC, and UAA. With JWT (the default), you store the access token on the client (in local storage). This works but isn’t the most secure. UAA involves using your own OAuth 2.0 authorization server (powered by Spring Security), and OAuth 2.0 / OIDC allows you to use Keycloak or Okta.

Spring Security makes Keycloak and Okta integration so incredibly easy it’s silly. Keycloak and Okta are called "identity providers" and if you have a similar solution that is OIDC-compliant, I’m confident it’ll work with Spring Security and JHipster.

Having Keycloak set by default is nice because you can use it without having an internet connection.

To log into the JHipster app you just created, you’ll need to have Keycloak up and running. When you create a JHipster project with OIDC for authentication, it creates a Docker container definition that has the default users and roles. Start Keycloak using the following command.

docker-compose -f src/main/docker/keycloak.yml up -d

Start your application with ./gradlew (or ./mvnw if you chose Maven) and you should be able to log in using "admin/admin" for your credentials.

Open another terminal and prove all the end-to-end tests pass:

npm run e2e

If your environment is setup correctly, you’ll see output like the following:

> [email protected] e2e /Users/mraible/app
> protractor src/test/javascript/protractor.conf.js

[16:02:18] W/configParser - pattern ./e2e/entities/**/*.spec.ts did not match any files.
[16:02:18] I/launcher - Running 1 instances of WebDriver
[16:02:18] I/direct - Using ChromeDriver directly...


  account
    ✓ should fail to login with bad password
    ✓ should login successfully with admin account (1754ms)

  administration
    ✓ should load metrics
    ✓ should load health
    ✓ should load configuration
    ✓ should load audits
    ✓ should load logs


  7 passing (15s)

[16:02:36] I/launcher - 0 instance(s) of WebDriver still running
[16:02:36] I/launcher - chrome #01 passed
Execution time: 19 s.

OIDC with Okta and Spring Security

To switch to Okta, you’ll first need to create an OIDC app. If you don’t have an Okta Developer account, now is the time!

Log in to your Okta Developer account.

  • In the top menu, click on Applications
  • Click on Add Application
  • Select Web and click Next
  • Enter JHipster FTW! for the Name (this value doesn’t matter, so feel free to change it)
  • Change the Login redirect URI to be <a href="http://localhost:8080/login/oauth2/code/oidc" target="_blank">http://localhost:8080/login/oauth2/code/oidc</a>
  • Click Done, then Edit and add <a href="http://localhost:8080" target="_blank">http://localhost:8080</a> as a Logout redirect URI
  • Click Save

These are the steps you’ll need to complete for JHipster. Start your JHipster app using a command like the following:

SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI=https://{yourOktaDomain}/oauth2/default \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID=$clientId \
  SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET=$clientSecret ./gradlew

Create a Native App for Ionic

You’ll also need to create a Native app for Ionic. The reason for this is because Ionic for JHipster is configured to use PKCE(Proof Key for Code Exchange). The current Spring Security OIDC support in JHipster still requires a client secret. PKCE does not.

Go back to the Okta developer console and follow the steps below:

  • In the top menu, click on Applications
  • Click on Add Application
  • Select Native and click Next
  • Enter Ionic FTW! for the Name
  • Add Login redirect URIs: <a href="http://localhost:8100/implicit/callback" target="_blank">http://localhost:8100/implicit/callback</a> and dev.localhost.ionic:/callback
  • Click Done, then Edit and add Logout redirect URIs: <a href="http://localhost:8100/implicit/logout" target="_blank">http://localhost:8100/implicit/logout</a> and dev.localhost.ionic:/logout
  • Click Save

You’ll need the client ID from your Native app, so keep your browser tab open or copy/paste it somewhere.

Create Groups and Add Them as Claims to the ID Token

In order to login to your JHipster app, you’ll need to adjust your Okta authorization server to include a groups claim.

On Okta, navigate to Users > Groups. Create ROLE_ADMIN and ROLE_USER groups and add your account to them.

Navigate to API > Authorization Servers, click the Authorization Servers tab and edit the default one. Click the Claims tab and Add Claim. Name it "groups" or "roles" and include it in the ID Token. Set the value type to "Groups" and set the filter to be a Regex of .*. Click Create.

Navigate to <a href="http://localhost:8080" target="_blank">http://localhost:8080</a>, click sign in and you’ll be redirected to Okta to log in.

Enter the credentials you used to signup for your account, and you should be redirected back to your JHipster app.

Generate Entities for a Photo Gallery

Let’s enhance this example a bit and create a photo gallery that you can upload pictures to. Kinda like Flickr, but waaayyyy more primitive.

JHipster has a JDL (JHipster Domain Language) feature that allows you to model the data in your app, and generate entities from it. You can use its JDL Studio feature to do this online and save it locally once you’ve finished.

I created a data model for this app that has an Album, Photo, and Tag entities and set up relationships between them. Below is a screenshot of what it looks like in JDL Studio.

Copy the JDL below and save it in a photos.jdl file in the root directory of your project.

entity Album {
  title String required,
  description TextBlob,
  created Instant
}

entity Photo {
  title String required,
  description TextBlob,
  image ImageBlob required,
  taken Instant
}

entity Tag {
  name String required minlength(2)
}

relationship ManyToOne {
  Album{user(login)} to User,
  Photo{album(title)} to Album
}

relationship ManyToMany {
  Photo{tag(name)} to Tag{photo}
}

paginate Album with pagination
paginate Photo, Tag with infinite-scroll

You can generate entities and CRUD code (Java for Spring Boot; TypeScript and HTML for Angular) using the following command:

jhipster import-jdl photos.jdl

When prompted, type a to update existing files.

This process will create Liquibase changelog files (to create your database tables), entities, repositories, Spring MVC controllers, and all the Angular code that’s necessary to create, read, update, and delete your data objects. It’ll even generate Jest unit tests and Protractor end-to-end tests!

When the process completes, restart your app, and confirm that all your entities exist (and work) under the Entities menu.

You might notice that the entity list screen is pre-loaded with data. This is done by faker.js. To turn it off, edit src/main/resources/config/application-dev.yml, search for liquibase and set its contexts value to dev. I made this change in this example’s code and ran ./gradlew clean to clear the database.

liquibase:
  # Add 'faker' if you want the sample data to be loaded automatically
  contexts: dev

Develop a Mobile App with Ionic and Angular

Getting started with Ionic for JHipster is similar to JHipster. You simply have to install the Ionic CLI, Yeoman, the module itself, and run a command to create the app.

npm i -g [email protected] [email protected] yo
yo jhipster-ionic

If you have your app application at ~/app, you should run this command from your home directory (~). Ionic for JHipster will prompt you for the location of your backend application. Use mobile for your app’s name and app for the JHipster app’s location.

Type a when prompted to overwrite mobile/src/app/app.component.ts.

Open mobile/src/app/auth/auth.service.ts in an editor, search for data.clientId and replace it with the client ID from your Native app on Okta.

// try to get the oauth settings from the server
this.requestor.xhr({method: 'GET', url: AUTH_CONFIG_URI}).then(async (data: any) => {
  this.authConfig = {
    identity_client: '{yourClientId}',
    identity_server: data.issuer,
    redirect_url: redirectUri,
    end_session_redirect_url: logoutRedirectUri,
    scopes,
    usePkce: true
  };
  ...
}

When using Keycloak, this change is not necessary.### Add Claims to Access Token

In order to authentication successfully with your Ionic app, you have to do a bit more configuration in Okta. Since the Ionic client will only send an access token to JHipster, you need to 1) add a groups claim to the access token and 2) add a couple more claims so the user’s name will be available in JHipster.

Navigate to API > Authorization Servers, click the Authorization Servers tab and edit the default one. Click the Claims tab and Add Claim. Name it "groups" and include it in the Access Token. Set the value type to "Groups" and set the filter to be a Regex of .*. Click Create.

Add another claim, name it given_name, include it in the access token, use Expression in the value type, and set the value to user.firstName. Optionally, include it in the profile scope. Perform the same actions to create a family_name claim and use expression user.lastName.

When you are finished, your claims should look as follows.

Run the following commands to start your Ionic app.

cd mobile
ionic serve

You’ll see a screen with a sign-in button. Click on it, and you’ll be redirected to Okta to authenticate.

Now that you having log in working, you can use the entity generator to generate Ionic pages for your data model. Run the following commands (in your ~/mobile directory) to generate screens for your entities.

yo jhipster-ionic:entity album

When prompted to generate this entity from an existing one, type Y. Enter ../app as the path to your existing application. When prompted to regenerate entities and overwrite files, type Y. Enter a when asked about conflicting files.

Go back to your browser where your Ionic app is running (or restart it if you stopped it). Click on Entities on the bottom, then Albums. Click the blue + icon in the bottom corner, and add a new album.

Click the ✔️ in the top right corner to save your album. You’ll see a success message and it listed on the next screen.

Refresh your JHipster app’s album list and you’ll see it there too!

Generate code for the other entities using the following commands and the same answers as above.

yo jhipster-ionic:entity photo
yo jhipster-ionic:entity tag

Run Your Ionic App on iOS

To generate an iOS project for your Ionic application, run the following command:

ionic cordova prepare ios

When prompted to install the ios platform, type Y. When the process completes, open your project in Xcode:

open platforms/ios/MyApp.xcworkspace

You’ll need to configure code signing in the General tab, then you should be able to run your app in Simulator.

Log in to your Ionic app, tap Entities and view the list of photos.

Add a photo in the JHipster app at <a href="http://localhost:8080" target="_blank">http://localhost:8080</a>.

To see this new album in your Ionic app, pull down with your mouse to simulate the pull-to-refresh gesture on a phone. Looky there - it works!

There are some gestures you should know about on this screen. Clicking on the row will take you to a view screen where you can see the photo’s details. You can also swipe left to expose edit and delete buttons.

Run Your Ionic App on Android

Deploying your app on Android is very similar to iOS. In short:

  1. Make sure you’re using Java 8
  2. Run ionic cordova prepare android
  3. Open platforms/android in Android Studio, upgrade Gradle if prompted
  4. Set launchMode to singleTask in AndroidManifest.xml
  5. Start your app using Android Studio
  6. While your app is starting, run adb reverse tcp:8080 tcp:8080 so the emulator can talk to JHipster
Learn More About Ionic 4 and JHipster 6

Ionic is a nice way to leverage your web development skills to build mobile apps. You can do most of your development in the browser, and deploy to your device when you’re ready to test it. You can also just deploy your app as a PWA and not both to deploy it to an app store.

JHipster supports PWAs too, but I think Ionic apps look like native apps, which is a nice effect. There’s a lot more I could cover about JHipster and Ionic, but this should be enough to get you started.

You can find the source code for the application developed in this post on GitHub at @oktadeveloper/okta-ionic4-jhipster-example.

Thank you for reading!

Building CRUD Mobile App using Ionic 4, Angular 8

Building CRUD Mobile App using Ionic 4, Angular 8

A comprehensive Ionic 4 Angular 8 tutorial, learn to build CRUD (Create, Read, Update, Delete) Mobile Apps (Android/iOS)

A comprehensive Ionic 4 Angular 8 tutorial, learn to build CRUD (Create, Read, Update, Delete) Mobile Apps (Android/iOS)

The Angular 8 just released a few weeks ago, but Ionic 4 still using Angular 7. As usual, we will start this tutorial using Ionic CLI with the new version 5.

The Ionic 4 Angular 8 application flow will look like this. It just a regular CRUD (Create, Read, Update, Delete) function.

In this tutorial, we will use more Angular 8 than Ionic 4 components itself. So, if you are new to Hybrid Mobile Apps development using Ionic and familiar with Angular then this is your easy way to implement your Angular skill for Mobile App development.

The following tools, frameworks, and modules are required for this tutorial:

Remember always use the latest Ionic 4 and Angular 8 CLI to decrease compatibility issues

Before going to the main steps, we assume that you have to install Node.js. Next, upgrade or install new Ionic 4 CLI by open the terminal or Node command line then type this command.

sudo npm install -g ionic

You will get the latest Ionic 4 CLI in your terminal or command line. Check the version by type this command.

ionic -v
5.1.0

To update the Angular CLI, type this command.

sudo npm install -g @angular/cli

Now, the Angular version should be like this.

ng version
Angular CLI: 7.3.9
Create Ionic 4 Application and Update to Angular 8

We will be using Ionic CLI to create a new Ionic 4 application. Type this command to create it.

ionic start ionic4-angular8-crud --type=angular

The created Ionic 4 application still using Angular 7.2.2, for that we have to upgrade the Angular 7 to Angular 8. Go to the newly created folder then type this command using Angular CLI.

ng update @angular/cli @angular/core

If you get dependency incompatibility like below.

Package "@ionic/angular" has an incompatible peer dependency to "zone.js" (requires "^0.8.26", would install "0.9.1").
Incompatible peer dependencies found. See above.

Uninstall then install again the required dependency version.

npm uninstall --save zone.js
npm install --save zone.js

Then run again the Angular 8 update command. Next, run the Ionic 4 and Angular 7 app for the first time, but before run as lab mode, type this command to install @ionic/lab.

npm install --save-dev @ionic/lab
ionic serve -l

Now, open the browser and you will the Ionic 4 and Angular 8 app with the iOS, Android, or Windows view. If you see a normal Ionic 4 blank application, that's mean you ready to go to the next steps.

Install Angular 8 Material and CDK

For UI, we will use Angular 8 Material and CDK. To install Angular 8 Material and CDK, simply run this command.

ng add @angular/material

Type enter or yes for every question that showed up.

? Choose a prebuilt theme name, or "custom" for a custom theme: Deep Purple/Amber  [ Preview: h
ttps://material.angular.io?theme=deeppurple-amber ]
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes

Next, register all required Angular Material CDK components or modules to app.module.ts. Open and edit that file then add this imports.

import { DragDropModule } from '@angular/cdk/drag-drop';
import { ScrollingModule } from '@angular/cdk/scrolling';

For Angular 8 Material, we will not import here but in each Ionic 4 Page Modules. Also, modify FormsModule import to add ReactiveFormsModule.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

Register the above modules to @NgModule imports.

imports: [
  BrowserModule,
  FormsModule,
  ReactiveFormsModule,
  IonicModule.forRoot(),
  AppRoutingModule,
  BrowserAnimationsModule,
  DragDropModule,
  ScrollingModule
],
Use Dynamic Imports for Angular 8 Route Configuration

Before change the Angular 8 Route configuration, we have to add the required Ionic 4 Page Module first. Type these commands to create them.

ionic g page product-detail
ionic g page product-add
ionic g page product-edit

We just added detail, add, and edit pages because the Product list will display in the Home Page Module. Next, open src/app/app-routing.module.ts then you will see the route modified and includes the page navigation. Next, we will modify this to match the new Angular 8 feature. Replace all route constant with this constant.

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomePageModule)},
  { path: 'product-detail/:id', loadChildren: () => import('./product-detail/product-detail.module').then(m => m.ProductDetailPageModule)},
  { path: 'product-add', loadChildren: () => import('./product-add/product-add.module').then(m => m.ProductAddPageModule)},
  { path: 'product-edit/:id', loadChildren: () => import('./product-edit/product-edit.module').then(m => m.ProductEditPageModule)},
];

Next, modify tsconfig.json to change module and target.

{
  "compilerOptions": {
  …
  "module": "esnext",
  "moduleResolution": "node",
  …
  "target": "es2015",
  …
},
Create Ionic 4 Angular 8 RESTful API Service

To call RESTful API we will use Ionic 4 Angular Service using HttpClientModule. So, all CRUD call handle by Ionic 4 Angular 8 service that emitted the response by Observable and RXJS. Next, open and edit src/app/app.module.ts then add these imports to register HttpClientModule and FormsModule.

import { HttpClientModule } from '@angular/common/http';

Add it to @NgModule imports after BrowserModule.

imports: [
  BrowserModule,
  FormsModule,
  HttpClientModule,
  AppRoutingModule
  ...
],

We will use type specifier to get a typed result object. For that, create a new Typescript file src/app/product.ts then add these lines of Typescript codes.

export class Product {
  _id: number;
  prod_name: string;
  prod_desc: string;
  prod_price: number;
  updated_at: Date;
}

Next, generate an Ionic 4 Angular 8 service by typing this command.

ionic g service api

Next, open and edit src/app/api.service.ts then add these imports.

import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { catchError, tap, map } from 'rxjs/operators';
import { Product } from './product';

Add these constants before the @Injectable.

const httpOptions = {
  headers: new HttpHeaders({'Content-Type': 'application/json'})
};
const apiUrl = 'http://localhost:3000/api/v1/products';

Inject HttpClient module to the constructor.

constructor(private http: HttpClient) { }

Add the error handler function.

private handleError(operation = 'operation', result?: T) {
  return (error: any): Observable => {
    console.error(error); // log to console instead
    return of(result as T);
  };
}

Add all CRUD (create, read, update, delete) functions of products data.

getProducts(): Observable {
  return this.http.get(apiUrl)
    .pipe(
      tap(product => console.log('fetched products')),
      catchError(this.handleError('getProducts', []))
    );
}

getProduct(id: any): Observable {
  const url = `${apiUrl}/${id}`;
  return this.http.get(url).pipe(
    tap(_ => console.log(`fetched product id=${id}`)),
    catchError(this.handleError(`getProduct id=${id}`))
  );
}

addProduct(product: Product): Observable {
  return this.http.post(apiUrl, product, httpOptions).pipe(
    tap((prod: Product) => console.log(`added product w/ id=${prod._id}`)),
    catchError(this.handleError('addProduct'))
  );
}

updateProduct(id: any, product: any): Observable {
  const url = `${apiUrl}/${id}`;
  return this.http.put(url, product, httpOptions).pipe(
    tap(_ => console.log(`updated product id=${id}`)),
    catchError(this.handleError('updateProduct'))
  );
}

deleteProduct(id: any): Observable {
  const url = `${apiUrl}/${id}`;

  return this.http.delete(url, httpOptions).pipe(
    tap(_ => console.log(`deleted product id=${id}`)),
    catchError(this.handleError('deleteProduct'))
  );
}
View List of Data

As we mention in the begining of this article, we will use existing Ionic 4 Home Page Module to display list of data. For that, open and edit src/app/home/home.page.ts then add/replace these imports.

import { Component, OnInit } from '@angular/core';
import { LoadingController } from '@ionic/angular';
import { ActivatedRoute, Router } from '@angular/router';
import { ApiService } from '../api.service';
import { Product } from '../product';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';

Next, add Angular 8 OnInit implementation to the HomePage Class name.

export class HomePage implements OnInit

Next, add the constructor then inject those modules to the constructor.

constructor(
  public api: ApiService,
  public loadingController: LoadingController,
  public router: Router,
  public route: ActivatedRoute) { }

Remove all default generated variable, function and constructor body if exists then add this variable before the constructor for hold classroom data that get from the service.

products: Product[] = [];

Add function for getting Product list from API.

async getProducts() {
  const loading = await this.loadingController.create({
    message: 'Loading...'
  });
  await loading.present();
  await this.api.getProducts()
    .subscribe(res => {
      this.products = res;
      console.log(this.products);
      loading.dismiss();
    }, err => {
      console.log(err);
      loading.dismiss();
    });
}

Add Angular 8 init function after the constructor for call above function.

ngOnInit() {
  this.getProducts();
}

Add function for the new Angular 8 CDK Drag&Drop.

drop(event: CdkDragDrop) {
  moveItemInArray(this.products, event.previousIndex, event.currentIndex);
}

Next, because we will use the new Angular 8 CDK features. We should add modules for it to src/app/home/home.module.ts then add these imports.

import { ScrollingModule } from '@angular/cdk/scrolling';
import { DragDropModule } from '@angular/cdk/drag-drop';

Register to @NgModule imports array.

imports: [
  IonicModule,
  CommonModule,
  FormsModule,
  ScrollingModule,
  DragDropModule,
  RouterModule.forChild([{ path: '', component: HomePage }])
],

Next, open and edit src/app/home/home.page.html then replace all HTML tags with this.


  
    Home
  



  
    
      
      {{p.prod_name}}
      
        {{p.prod_price | currency}}
      
    
  

Finally, give this page a style by open and edit src/app/home/home.page.scss then replace all SCSS codes with these.

.example-viewport {
  height: 100%;
  width: 100%;
  border: none;
}

.example-item {
  min-height: 50px;
}
View Data Details and Add Delete Function

Every time you click the list item in the List of data, you will be redirected to Details tab including the ID of the selected data. Open and edit src/app/product-detail/product-detail.page.ts then add/replace this imports.

import { Component, OnInit } from '@angular/core';
import { AlertController } from '@ionic/angular';
import { ApiService } from '../api.service';
import { ActivatedRoute, Router } from '@angular/router';
import { Product } from '../product';

Inject above modules to the constructor.

constructor(
  public api: ApiService,
  public alertController: AlertController,
  public route: ActivatedRoute,
  public router: Router) {}

Add the variables before the constructor for hold Product data and Angular 8 Loading Spinner.

product: Product = { _id: null, prod_name: '', prod_desc: '', prod_price: null, updated_at: null };
isLoadingResults = false;

Add an asynchronous function to getting Product detail from API.

async getProduct() {
  if (this.route.snapshot.paramMap.get('id') === 'null') {
    this.presentAlertConfirm('You are not choosing an item from the list');
  } else {
    this.isLoadingResults = true;
    await this.api.getProduct(this.route.snapshot.paramMap.get('id'))
      .subscribe(res => {
        console.log(res);
        this.product = res;
        this.isLoadingResults = false;
      }, err => {
        console.log(err);
        this.isLoadingResults = false;
      });
  }
}

Add an asynchronous function for display an alert.

async presentAlertConfirm(msg: string) {
  const alert = await this.alertController.create({
    header: 'Warning!',
    message: msg,
    buttons: [
      {
        text: 'Okay',
        handler: () => {
          this.router.navigate(['']);
        }
      }
    ]
  });

  await alert.present();
}

Call get product function from Angular 8 init function.

ngOnInit() {
  this.getProduct();
}

Add the functions to delete the data.

async deleteProduct(id: any) {
  this.isLoadingResults = true;
  await this.api.deleteProduct(id)
    .subscribe(res => {
      this.isLoadingResults = false;
      this.router.navigate([ '/home' ]);
    }, err => {
      console.log(err);
      this.isLoadingResults = false;
    });
}

Add a function to navigate to the Edit Product page.

editProduct(id: any) {
  this.router.navigate([ '/product-edit', id ]);
}

Next, open and edit src/app/details/details.page.html then replace all HTML tags with this.


  
    
      
    
    Product Details
  



  
    <div class="example-loading-shade"
          *ngIf="isLoadingResults">
      
    
    
      
        ## {{product.prod_name}}

        {{product.prod_desc}}
      
      
        
          Product Price:
          {{product.prod_price}}
          Updated At:
          {{product.updated_at | date}}
        
      
      
        edit
        delete
      
    
  

Finally, give this page a style by open and edit src/app/product-detail/product-detail.page.scss then replace all SCSS codes with these.

.example-container {
  position: relative;
  padding: 5px;
  height: 100%;
  background-color: aqua;
}

.example-loading-shade {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 56px;
  right: 0;
  background: rgba(0, 0, 0, 0.15);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mat-flat-button {
  margin: 5px;
}
Create a Form to Add Data using Angular 8 Material

To create a form for adding a Product Data using Angular 8 Material, open and edit src/app/product-add/product-add.page.ts then add these imports.

import { Router } from '@angular/router';
import { ApiService } from '../api.service';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';

Inject above modules to the constructor.

constructor(
  private router: Router,
  private api: ApiService,
  private formBuilder: FormBuilder) { }

Declare variables for the Form Group and all of the required fields inside the form before the constructor.

productForm: FormGroup;
prod_name = '';
prod_desc = '';
prod_price: number = null;
isLoadingResults = false;

Add initial validation for each field in the ngOnInit function.

this.productForm = this.formBuilder.group({
  'prod_name' : [null, Validators.required],
  'prod_desc' : [null, Validators.required],
  'prod_price' : [null, Validators.required]
});

Create a function for submitting or POST product form.

onFormSubmit() {
  this.isLoadingResults = true;
  this.api.addProduct(this.productForm.value)
    .subscribe((res: any) => {
        const id = res._id;
        this.isLoadingResults = false;
        this.router.navigate(['/product-details', id]);
      }, (err: any) => {
        console.log(err);
        this.isLoadingResults = false;
      });
}

Next, add this import for implementing ErrorStateMatcher.

import { ErrorStateMatcher } from '@angular/material/core';

Create a new class before the main class @Components.

/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}

Instantiate that MyErrorStateMatcher as a variable in the main class.

matcher = new MyErrorStateMatcher();

Before modifying the HTML file, we have to register all Angular 8 Material files by open and edit src/app/product-add/product-add.module.ts then add these imports.

import {
  MatInputModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatSortModule,
  MatTableModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule } from '@angular/material';

Declare that imported modules to then @NgModule imports array.

imports: [
  ...
  MatInputModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatSortModule,
  MatTableModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule
],

Next, open and edit src/app/product-add/product-add.component.html then replace all HTML tags with this.


  
    
      
    
    Product Add
  



  
    <div class="example-loading-shade"
         *ngIf="isLoadingResults">
      
    
    
      
        
          <input matInput placeholder="Product Name" formControlName="prod_name"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Name
          
        
        
          <input matInput placeholder="Product Desc" formControlName="prod_desc"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Description
          
        
        
          <input matInput placeholder="Product Price" formControlName="prod_price"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Price
          
        
        
          save
        
      
    
  

Finally, open and edit src/app/product-add/product-add.component.scss then add this SCSS codes.

.example-container {
  position: relative;
  padding: 5px;
  height: 100%;
  background-color: aqua;
}

.example-form {
  min-width: 150px;
  max-width: 500px;
  width: 100%;
}

.example-full-width {
  width: 100%;
}

.example-full-width:nth-last-child(0) {
  margin-bottom: 10px;
}

.button-row {
  margin: 10px 0;
}

.mat-flat-button {
  margin: 5px;
}

.example-card {
  margin: 5px;
}
Create a Form to Edit Data using Angular 8 Material

To create a Form of Edit Product Data using Angular 8 Material, open and edit src/app/product-edit/product-edit.page.ts then add these lines of imports.

import { Router, ActivatedRoute } from '@angular/router';
import { ApiService } from '../api.service';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';

Add a new Class before the @Component that handles the error message in the HTML form.

/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}

Next, add these lines of variables to the main Class before the constructor.

productForm: FormGroup;
_id = '';
prod_name = '';
prod_desc = '';
prod_price: number = null;
isLoadingResults = false;
matcher = new MyErrorStateMatcher();

Inject the constructor params with these modules.

constructor(
  private router: Router,
  private route: ActivatedRoute,
  private api: ApiService,
  private formBuilder: FormBuilder) { }

Initialize the form group with the form controls of the product form and call the product detail data in the Angular 8 ngOnInit function.

ngOnInit() {
  this.getProduct(this.route.snapshot.params['id']);
  this.productForm = this.formBuilder.group({
    'prod_name' : [null, Validators.required],
    'prod_desc' : [null, Validators.required],
    'prod_price' : [null, Validators.required]
  });
}

Create a new Angular 8 function to call the product data by ID.

getProduct(id: any) {
  this.api.getProduct(id).subscribe((data: any) => {
    this._id = data._id;
    this.productForm.setValue({
      prod_name: data.prod_name,
      prod_desc: data.prod_desc,
      prod_price: data.prod_price
    });
  });
}

Create a new Angular 8 function that handles the form submission to save data to the REST API.

onFormSubmit() {
  this.isLoadingResults = true;
  this.api.updateProduct(this._id, this.productForm.value)
    .subscribe((res: any) => {
        const id = res._id;
        this.isLoadingResults = false;
        this.router.navigate(['/product-details', id]);
      }, (err: any) => {
        console.log(err);
        this.isLoadingResults = false;
      }
    );
}

Add a function to navigate to the Product Detail page.

productDetails() {
  this.router.navigate(['/product-details', this._id]);
}

Before modifying the HTML file, we have to register all Angular 8 Material files by open and edit src/app/product-edit/product-edit.module.ts then add these imports.

import {
  MatInputModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatSortModule,
  MatTableModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule } from '@angular/material';

Declare that imported modules to then @NgModule imports array.

imports: [
  ...
  MatInputModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatSortModule,
  MatTableModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule
],

Next, open and edit src/app/product-edit/product-edit.page.html then replace all HTML tags with these.


  
    
      
    
    Product Edit
  



  
    <div class="example-loading-shade"
         *ngIf="isLoadingResults">
      
    
    
      
        
          <input matInput placeholder="Product Name" formControlName="prod_name"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Name
          
        
        
          <input matInput placeholder="Product Desc" formControlName="prod_desc"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Description
          
        
        
          <input matInput placeholder="Product Price" formControlName="prod_price"
                 [errorStateMatcher]="matcher">
          
            Please enter Product Price
          
        
        
          save
        
      
    
  

Finally, add some styles for this page by open and edit src/app/product-edit/product-edit.page.scss then replace all SCSS codes with these.

.example-container {
  position: relative;
  padding: 5px;
  height: 100%;
  background-color: aqua;
}

.example-form {
  min-width: 150px;
  max-width: 500px;
  width: 100%;
}

.example-full-width {
  width: 100%;
}

.example-full-width:nth-last-child(0) {
  margin-bottom: 10px;
}

.button-row {
  margin: 10px 0;
}

.mat-flat-button {
  margin: 5px;
}

.example-card {
  margin: 5px;
}
Run and Test the Whole Ionic 4 Angular 8 Mobile Apps

Before running Ionic 4 Angular 8 Mobile Apps we have to start the MongoDB server and Node/Express.js REST API server. Type these commands in the separate Terminal/CMD tabs.

mongod
nodemon

Now, we have to run the Ionic 4 Angular 8 Mobile Apps in the browser using this command.

ionic serve -l

And here we go, the full Ionic 4 Angular 8 Mobile Apps CRUD functions.

That it's, the comprehensive step by step tutorial of Ionic 4 Angular 8 CRUD Mobile Apps. You can find the full source code from our GitHub.

Free Ionic UI-UX Starter Mobile App Open Source - Download

Free Ionic UI-UX Starter Mobile App Open Source - Download

Check out our Ionic Starter App open-source that build based on enterprise standards. So now build an app with Ionic that meets industries standard with free open-source. #HappyCoding

Are you application development looking for open-source to build an application as per industry standard then you may check out Ionic Starter Mobile Application open-source that build as per industry standard. We developed that application while keeping all perspective of Industries standard. Now we keep this as an open-source so anyone can learn how to develop an application that meets our industries or enterprise level.

Check out our open-source that build based on enterprise standards. So now build an app with Ionic that meets industries standard with free open-source. #HappyCoding 

Download Ionic Starter Application

To download our open source check out at https://www.ionicfirebaseapp.com/products/ionic-starter-ui-ux-kit

Installation and Setup of Application

To installation Ionic and Ionic Starter Application check out our documentation at https://ionicfirebaseapp.gitbooks.io/starterapp/

Or you can download from GitHub repository at  https://github.com/ionicfirebaseapp/Ionic3-starterapp

About IONIC UI-UX STARTER

Ionic UI/UX Multipurpose Theme/Template develop for developer to start quickly on any type of application development quickly. It has more than 50 Different screen UI Layout that can use in any apps easily. It’s Multipurpose app with E-Commerce , Social , News , Event , Article , Layout , Notification app UI. It has Integration of More than 20 ionic Native Features. It comes with Firestore authentication Login / Registration and Profile Feature.

What is Ionic?

Ionic is the app development platform for web developers. Build amazing cross platform mobile, web, and desktop apps all with one shared code base and open-source.

Ionic is a complete open-source SDK for hybrid mobile app development created by Max Lynch, Ben Sperry, and Adam Bradley of Drifty Co. in 2013. The original version was released in 2013 and built on top of AngularJS and Apache Cordova.

For more about Ionic Framework, you can visit their official website ionicframework.com.