• Home
  • AngularJS
  • Create Native Mobile and Web App With Single Codebase Using Angular2 and Nativescript

Create Native Mobile and Web App With Single Codebase Using Angular2 and Nativescript

Creating a performant application for all three platforms Android, iOS and Web with single codebase is an amazing thing that we can do nowadays. I am going to show you how we can create such single codebase cross platform application by combining power of Angular 2 and Nativescript frameworks. Angular2 is a framework which can run on multiple platforms and Nativescript is a framework using which we can write truly native mobile apps for Android and iOS using web technologies. Nativescript provides a very good support of Angular framework. That means we can combine the power of both the great frameworks and create amazing cross-platform apps with single codebase.

If you want to create your own web and native mobile applications with single codebase, I have created a very simple nativescript-angular-web-starter for that. Just clone the repository and you are ready to create your awesome application. Check this preview video of the starter:

Have you noticed how changes in one file is getting reflected in both native mobile app and a web app?

I know in the preview above, it is a very simple application. So if you want to see a bigger application than this, check this Open Source Cross Platform Quotes Application.

You can find the complete source code of this Quotes Application from https://github.com/shripalsoni04/ngxp-quotes-app. This Quotes Application is made up with same architecture as that of the starter mentioned above.

Now, let’s dig into details of how to create such applications.

You may have question, if we are creating truly native mobile app with Nativescript, how can the code of the view layer be the same as web. Well, you are right. Nativescript do not have HTML tags like div, span, h1 etc. and it has its own template tags like Label, GridLayout, ListView etc.. It is very necessary first to understand what all the things can be shared between mobile & web platforms and what can/should not be shared.

What can/should be shared between mobile and web platforms?


Services generally contains core business logic, code related to fetching data from api/web-services, utility functions etc. As all such code do not change based on the view layer, it should be shared among platforms.


Data Models or any Business Entity Models also do not depend on view layer. So such models can also be shared.


Assets like logo image, images related to business domain, icons can be shared between platforms. Since nativescript has great support of font icons, we can use any font icon library like Font Awesome, Material Icons or your own font icon very easily on both mobile and web platforms.

Style Variables, Functions or Mixins

Nativescript has support of CSS Preprocessors like SASS and LESS. So we can share style variables, common functions etc. across the platforms. This makes changing the brand colors across the platforms very easy.


ViewModels contains logic related to view layer. As nativescript has angular support, we can use template syntax of angular in nativescript templates. So even if rendering engine for mobile and web platforms are different, we can share some code which will be same for the platforms. We will see this later in this tutorial.

Unit Test Cases

As we can share services, models and viewModels among the platforms, we can share their unit test cases also.

What can/should not be shared between mobile and web platforms?

Component Classes, Templates and Styles

As we know, an angular application is made up of a component hierarchy. This components are nothing but a simple ES6 class with some metadata attached to it. This metadata contains mapping of template or styles for a component. As we have different rendering engines for different platforms, it is obvious that we need to create different template and style files for mobile and web platforms.

Component class generally contains logic related to view like DOM/View manipulations, event handlers, event driven animations, view data loading etc. So, some code of the component will be same for all the platforms and some code which is related to animations, DOM/View manipulation etc. will not be the same. Now you may have question, if our component don’t do much view layer manipulation or animations, can’t we use the same component across all the platforms. The answer is yes there are ways to do that but that approach can have two limitations as mentioned below:

  1. As explained above, even if we keep the component class same, we need to have different template and style mappings in metadata of component for mobile and web platforms. That means at runtime we need to switch the metadata based on the platform in which the code is running. This can be accomplished by using CustomComponent decorator instead of using angular’s Component decorator. Unfortunately currently AOT do not work if any CustomComponent decorator is used as mentioned at this issue.

  2. We cannot use any platform specific APIs directly inside the component class because that will not be available when code runs on other platforms. Also, we need to wrap platform specific code inside conditional statements. This may create maintenance issues and complex test cases in long run.

You may have a question now, how can we share some of the component code without the limitations mentioned above? The answer is very simple. We just need to take all the code of a component which can be common across the platforms and put it inside an angular service and use that service inside the components of different platforms. We can call this service a viewModel because it contains code related to view of the component. We will see an example of such viewModel later in this tutorial.

Now, let’s look at implementation part of such application.

Application folder structure to share data between mobile and web app

Now we know what we can and cannot share between mobile and web platforms. Let’s understand what can be the application folder structure which enables us to share data between different platforms.


As shown above, the folder structure is very easy to understand.

nativescript folder contains a valid nativescript project created using nativescript-cli. You can execute any valid command of nativescript-cli in this folder.

web folder contains a valid web project created using angular-cli. You can execute any valid command of angular-cli in this folder.

tools folder contains scripts which are useful during development of the application.

x-shared folder contains all the code which can be shared across all the platforms. This folder contains only platform independent code. Just for information, here in folder name x-shared, x refers to Cross. So you can read x-shared as Cross Platform Shared.

This x-shared folder is symlinked in nativescript and web folders as shown below:



As x-shared is symlinked, changes done in any file of this folder from any of the three places, will be reflected in other two places. So this provide convenience of editing cross platform shared code from within folder of mobile/web platforms.

Now, let’s examine what should be within x-shared folder.


The above x-shared folder structure is of Cross Platform Quotes App made with the same architecture.


app folder contains services, models, viewModels and unit test cases of various modules of the application.

assets folder contains images like logo or any business domain images or any other non-editable things.

styles folder contains style variables, functions or mixins of SASS/LESS.

typings folder contains shared type definitions of any business entity.

How to create and use shared code?

Now, we know the folder structure of such application, let’s see how to create and use such shared code across platform.

In this section, I will use code snippets from Quotes Application as mentioned above. Let’s see how to implement functionality of showing authors’ list in mobile and web applications.

Service and Models

To show authors’ list we need to have a service which fetches data from some remote service. Code of such AuthorService is as shown below.


import { Injectable } from '@angular/core';
import { FirebaseService } from '../core/firebase.service';
import { Pagination } from '../shared/models';

export class AuthorService {
  private path: string = 'authors';

  private lstAuthors: any[];

  constructor(private firebaseService: FirebaseService) {


   * Returns promise of authors from cache if available in memory else fetches list from firebase.
  get(pagination?: Pagination) {
    return new Promise((resolve, reject) => {
      if (this.lstAuthors && this.lstAuthors.length) {
      } else {
        this.firebaseService.getListOnce(this.path, pagination).then((lstAuthors) => {
          this.lstAuthors = lstAuthors;
        }, (error) => {


Here, notice that even though firebase implementation for both web and mobile platforms are different, we have injected a common FirebaaseService. So let’s understand how we can abstract different firebase implementation using a common service.

Angular has a very flexible dependency injection framework. In angular, we can provide different implementation with the same token. So in above example, FirebaseService is token of type abstract class. And its value will be either WebFirebaseService or NativeFirebaseService depending on the platform in which it is requested.

This different implementation is registered in module of the respective platform as shown below:


import { NgModule } from '@angular/core';
import { NativeScriptModule } from 'nativescript-angular/platform';

import { FirebaseService } from '../../x-shared/app/core';
import { NativeFirebaseService } from './native-firebase.service';

  imports: [NativeScriptModule],
  providers: [
    { provide: FirebaseService, useExisting: NativeFirebaseService },
export class CoreModule { }


import { NgModule } from '@angular/core';

import { FirebaseService } from '../../x-shared/app/core';
import { WebFirebaseService } from './web-firebase.service';

  providers: [
    { provide: FirebaseService, useExisting: WebFirebaseService },
export class CoreModule { }

Now, let’s take a quick look at what is the content of token class FirebaseService and its implementation classes WebFirebaseService, NativeFirebaseService.

The token class FirebaseService is nothing but an abstract class which lists methods which needs to be implemented by both the platforms as shown below:


import { Pagination } from '../shared/models';

export abstract class FirebaseService {
  abstract getOnce(path: string);
  abstract getListOnce(path: string, pagination?: Pagination);
  abstract filterOnce(path: string, filterBy: string, filterValue: any);
  abstract initializeFirebase(config: any): void;

Now, let’s see the NativeFirebaseService which contains implementation of methods defined in abstract FirebaseService class for mobile platform:


import { Injectable } from '@angular/core';

import * as firebase from 'nativescript-plugin-firebase';

import { Pagination } from '../../x-shared/app/shared';
import { FirebaseService } from '../../x-shared/app/core';

export class NativeFirebaseService extends FirebaseService {
  constructor() {
      persist: false


  getListOnce(path: string, pagination?: Pagination) {
    let options: firebase.QueryOptions = {

    return new Promise((resolve, reject) => {
        (result: any) => {
          if (result.error) {
          } else {

  initializeFirebase(config?: any) {


You can see that in nativescript project we have used nativescript-plugin-firebase plugin, which calls firebase APIs of native mobile platforms (Android, iOS) for querying data.

Similarly for web there is a different implementation of FirebaseService which uses firebase npm package for querying data as shown below:


import { Injectable } from '@angular/core';
import * as firebase from 'firebase';

import { Pagination } from '../../x-shared/app/shared';
import { FirebaseService } from '../../x-shared/app/core';

export class WebFirebaseService extends FirebaseService {
  constructor() {

    const config = {
      authDomain: 'ngxp-quotes-app-a975f.firebaseapp.com',
      databaseURL: 'https://ngxp-quotes-app-a975f.firebaseio.com'


  getListOnce(path: string, pagination?: Pagination) {
    let query: firebase.database.Query;

    query = firebase.database().ref(path).orderByKey()

    return query.once('value').then((snapshot) => {
      return this.prepareResultListFromSnapshot(snapshot);

  initializeFirebase(config: any) {


So, now you know how we can abstract the different implementation using a common abstract class token and use it in shared code across the platforms.


As discussed before in this tutorial, we can create viewModels which contains common code related to particular view. Let’s understand how it is used for author-list screen.

In author-list screen, it is obvious that we need to call AuthorService to fetch data and then we need to set the returned author list into some variable. As we can use angular template syntax in both nativescript and web templates, we can create a common code for this as shown below:


import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { AuthorService } from './author.service';

export class AuthorsListCommonVM {

  lstAuthors: any[] = [];

  authors$: BehaviorSubject<any[]> = new BehaviorSubject<any[]>(this.lstAuthors);

  constructor(protected authorService: AuthorService) {}

  loadAuthorList() {
    this.authorService.get().then((lstAuthors) => {
      this.lstAuthors.length = 0;
      Array.prototype.push.apply(this.lstAuthors, lstAuthors);
    return this.authors$;

As shown in above code, the viewModel is nothing but an angular service. Notice that we have injected the AuthorService in this common viewModel so that we don’t need to inject the AuthorService in components of different platforms and we just need to inject and use this viewModel inside component as shown below:


import { Component, ChangeDetectionStrategy } from '@angular/core';

import { AuthorsListCommonVM } from '../../x-shared/app/authors';

  selector: 'authors-list',
  templateUrl: 'modules/authors/authors-list.component.html',
  providers: [AuthorsListCommonVM],
  changeDetection: ChangeDetectionStrategy.OnPush
export class AuthorsListComponent {

    public cvm: AuthorsListCommonVM
  ) {

In template of mobile platform, we can use this cvm member to access any cross-platform shared code for this authors-list component as shown below:


    [items]="cvm.authors$ | async">
  <template let-item="item">

Similarly, in web also we just need to inject the AuthorsListCommonVM viewModel and use inside component and template. You can refer the code of component and template for web platform.

This way of separating common view related code inside shared view-model also helps in testing by clearly separating test cases of DOM/View manipulation from the actual logic related code of the view. And in future if we want to create our application for any other platform, we just need to write template and DOM/View manipulation code for that platform and rest of the code will be ready to use with us.


So, now you have got an overview of how you can create cross-platform applications with single shared code base using angular and nativescript. You can quickly start creating such application by using nativescript-angular-web-starter. You can also refer to the Quotes Application for reference. Hope this guide will help you in creating your amazing web and native mobile applications with single codebase.

  • Alberto

    Thanks for the guide and also for the nativescript-angular-web-starter!!! It helped me a lot!

    • Olumide Omolayo

      Hi Alberto, Please how did you get it to run. I have not been able to run both the Quote App and the Web Starter. They are both throwing error: The “@angular/compiler-cli” package was not properly installed..

      • Alberto

        Hi @olumide_omolayo:disqus, I used this guide most for understand the nativescript’s logic. But I tried this solution four months ago and then I moved in just nativescritp apps. My suggestion is to use google and follow the error and the people that have the same situation or open an issue in the example linked above. sorry

        • Olumide Omolayo

          Were u able to make the nativescript-angular-web-starter run? your comment shows that it helped you.

          • Alberto

            As I wrote it helped me to understand some stuff about nativescritp. I was able to launch the project without errors four months ago but then I removed it, because it’s not what I am looking now (I am more focused on nativescript part).

  • Roman

    Thank you for the quotes app. There so few tutorials on Nativescript. And almost none on how to create mobile+web apps. All of them are basic examples.
    It would be great if you could make another blogpost explaining other aspects of the app. This helps immensely novices like me. I was reading quotes app source code. But kinda hard to grasp concepts. Your post helps a lot.
    Thank you again.

  • Aure

    Hi Shripal, thanks a lot for the tutorial. I have a question. I am trying to figure out which tool I should choose between Ionic 2 and Nativescript (I am new to both). For the project, we want to build a mobile App with a web-based Admin Dashboard. Would you recommend Nativescript or Ionic for such a scenario? Would the methods you describe in this article also work with Ionic 2? Thanks in advance.

  • Olumide Omolayo

    Hi Shripal, thanks a lot for your tutorial on develop for both web and native mobile within a single code base. I have since downloaded the source code (both nativescript-angular-web-starter and Quote app) and I have followed the steps to run them. They are throwing errors which I cannot resolve. Error is The “@angular/compiler-cli” package was not properly installed. Please assist. Thanks

  • Mahendra Thennakoon

    Was anyone able to get this working with a service that makes HTTP calls inside the x-shared directory?
    I’m getting the error “No provider for Http!”.