Category: JavaScript

Udacity Machine Learning Nano Degree Starbucks Capstone Challenge

Introduction

This blog post is part of the final project for the Udacity Machine Learning Engineer Nanodegree Program using AWS SageMaker

The project contains simulated data that mimics customer behavior on the Starbucks rewards mobile app. The goal of the project is to analyze this "historical" data in order to implement an algorithm that finds the most suiting offer type for each customer.

The data is contained in three files:

  • portfolio.json - containing offer ids and meta data about each offer (duration, type, etc.)
  • profile.json - demographic data for each customer
  • transcript.json - records for transactions, offers received, offers viewed, and offers completed

Here is the schema and explanation of each variable in the files:

portfolio.json

  • id (string) - offer id
  • offer_type (string) - type of offer ie BOGO, discount, informational
  • difficulty (int) - minimum required spend to complete an offer
  • reward (int) - reward given for completing an offer
  • duration (int) - time for offer to be open, in days
  • channels (list of strings)

profile.json

  • age (int) - age of the customer
  • became_member_on (int) - date when customer created an app account
  • gender (str) - gender of the customer (note some entries contain 'O' for other rather than M or F)
  • id (str) - customer id
  • income (float) - customer's income

transcript.json

  • event (str) - record description (ie transaction, offer received, offer viewed, etc.)
  • person (str) - customer id
  • time (int) - time in hours since start of test. The data begins at time t=0
  • value - (dict of strings) - either an offer id or transaction amount depending on the record

Solution Statement

This is a classification problem, my approach is going to be: create a Machine learning model to
predict the best offer for the user, for BOGO or discount (we are going to leave out the
informational offers, which have no real "conversion")
There are the steps to follow:

  • Fetching data
  • Data Cleaning
  • Data Preparation
  • Data visualization and analysis
  • Train Model
  • Evaluate the model

Evaluation Metrics

Since this is a classification problem we can use the following metrics to evaluate the model:

  • Precision The proportion of positive cases that were correctly identified.
  • Recall The proportion of actual positive cases which are correctly identified.
  • F1-score, that combines the two previous measures.
  • Roc_auc_score Area Under the ROC Curve (AUC), a measure that calculates the area
    under the Receiving Operating Characteristic Curve. This particular curve accounts that
    higher probabilities are associated with true positives and vice-versa.

Algorithms evaluated

We explored two algorithms Linear Learner and XGBoost to find the best models for for each offer, a Discount, a Buy One Get One (BOGO)
or Informational.

Project design

During the fetching data process, we have to join all the different pieces of information coming
from the 3 data sources, we need to fetch the data.

Data preparation. After analyzing the data, we transform the dataset through different stages
missing imputation, categories encoding, data standardization, etc.

Clean and Visualize the data to understand it's content and analyze it, to find possibles outliers
and remove them (if possible).

Data distribution visualization



Feature Engineering

Preprocessing with scikit-learn

  • Encode categorical variable gender (One Hot encoder)
  • Impute missing values
  • Normalize feature distributions

Things to notice:

  • There are 3 genre recorded in the dataset (F, M, O) which is going to be encoded during the feature engineering phase.
  • The scatterplot shows some odd structure but it should be because the data was simulated, also it doesn't look to be outliers.

Train the model

We used different ML models, one to predict the BOGO, the other to
predict the Discount and another to predict the informational offer. For each model, we try two algorithms, Linear Learner and Amazon Sage maker XG-Boost built in Algorithm.

For each algorithm, we tune the hyper-parameters to find the one with the best performance.
With the best two models, we can combine the results in order to obtain a single type of offer for
the user.

Evaluate the model we measure and compare the performances of the models with the
current benchmark, to learn if the proposed solution is viable for the offer attribution process.

Notebooks

The 3 notebooks and the data used for this project can be found in the following github repository:
https://github.com/jomendez/starbucks-captone-machine-learning.git

  • data-exploration.ipynb
  • feature_engineering.ipynb
  • training_the_model.ipynb

Results

CSS Box Model broken down

What is the CSS Box Model.

CSS Box Model

When a web page is rendered, the browser's rendering engine will display each HTML elements as a rectangular box.

Every rectangle is composed of a margin, border, padding and the element. If you open google chrome browser's console and inspect an element, go to the right column and scroll down until you see a box.

css box model

How to calculate the size of the box?

width = content width + padding-left + padding-right + border-left + border-right 
height = content height + padding-top + padding-bottom + border-top + border-button

note: The margin doesn't affect the size of the box, but it affects other content interacting around the box.

You can control how the size of the box it calculated with box-sizing.
The box-sizing CSS property sets how the total width and height of an element is calculated.

syntax:

box-sizing: content-box | border-box

See full example below for a better understanding.

See the Pen
Example css model box
by Jose Mendez (@jomendez)
on CodePen.

From the MDN:

Box model content area.

The content area, bounded by the content edge, contains the "real" content of the element, such as text, an image, or a video player. Its dimensions are the content width (or content-box width) and the content height (or content-box height). It often has a background color or background image.

If the box-sizing property is set to content-box (default) and if the element is a block element, the content area's size can be explicitly defined with the width, min-width, max-width, height, min-height, and max-height properties.

Box model padding area.

The padding area, bounded by the padding edge, extends the content area to include the element's padding. Its dimensions are the padding-box width and the padding-box height.

The thickness of the padding is determined by the padding-top, padding-right, padding-bottom, padding-left, and shorthand padding properties.

Box model border area.

The border area, bounded by the border edge, extends the padding area to include the element's borders. Its dimensions are the border-box width and the border-box height.

The thickness of the borders are determined by the border-width and shorthand border properties. If the box-sizing property is set to border-box, the border area's size can be explicitly defined with the width, min-width, max-width, height, min-height, and max-height properties. When there is a background (background-color or background-image) set on a box, it extends to the outer edge of the border (i.e. extends underneath the border in z-ordering). This default behavior can be altered with the background-clip css property.

Box model margin area.

The margin area, bounded by the margin edge, extends the border area to include an empty area used to separate the element from its neighbors. Its dimensions are the margin-box width and the margin-box height.
he size of the margin area is determined by the margin-top, margin-right, margin-bottom, margin-left, and shorthand margin properties. When margin collapsing occurs, the margin area is not clearly defined since margins are shared between boxes.

What if these values are not declared?

If margin, padding or borders are undeclared, they are either zero or the browser's default value.

See the box model with your own eyes.

You can visualize the box model in your page by opening the chrome developer tool and inspect the body of your page, add temporarely the following code:

* {
border: 1px solid red !important;
}

visualizing the css box model

Simplistic CRUD ionic 5 firestore TODO app example

Simplistic CRUD ionic 5 firestore TODO app example

This is a very simplistic CRUD (Create, Read, Update, Delete) Created with ionic 5 and firestore (database).

You can download the source code here.

Note:
I used this design as inspiration: https://dribbble.com/shots/4782162-To-Do-App-Concept-Minimal.

The idea here is to illustrate how to create a simple CRUD with firestore.

 Simplistic CRUD ionic 5 firestore TODO app example

Installation.

My advice is that you install nvm (to manage your node versions), here is tutorial step by step.

After you install nvm run the following commands:

nvm install 12

If everything went well you'll have installed node 12.0.0 .

Now you'll need to install ionic cli:

npm install -g @ionic/cli

Now is time to download the project and install it's dependencies.

git clone https://github.com/jomendez/ionic-5-crud-todo-with-firestore.git
cd ionic-5-crud-todo-with-firestore
npm install

Next step it to create a config file that will contain your firebase config keys here:

src/app/config/firebase.ts

If you are on bash you can use the following command:

touch src/app/config/firebase.ts

Assuming that you are familiar with firebase and already have an account, paste your configuration info into the firebase.ts file, it should looks something like this (This is just and example), If you are not familiar with firebase or doesn't have an account, I'll provide more information on how to do it bellow.

Example of configuration:

export const firebaseConfig = {
  apiKey: "AIzaSwERfdilPYtcNDfvFR6x944EowerdfghfSDFsfg",
  authDomain: "crud-456657.firebaseapp.com",
  databaseURL: "https://crud-456657.firebaseio.com",
  projectId: "crud-456657",
  storageBucket: "crud-456657.appspot.com",
  messagingSenderId: "10130122343423",
  appId: "1:1013012342277:web:sd9f8sd8fs8dfs89df89s",
  measurementId: "G-3FGJ34GFGJK"
};

How to get your firebase configuration.

Go to https://firebase.google.com/ and login with your account or create a new one.

Click on create a web app (This is the screen that you'll see the first time you create a projects):

image

Or add a new project (If you have already other projects created):

image

Enter the name of your project, accept the terms, and finish the other two steps on the wizard:

image

Next you'll see something like this, from here you can grab the configuration key.

image

If you missed the previous screen you can always go to the cog wheel on the left side panel, and click on project settings.

image

Now scroll down to the Your App section and click on config radio button, and copy the code highlighted on the image bellow, and paste it on the firebase.ts file.

image

Create web apps with Webpack

webpack banner

A simple but powerful project to rapid prototyping and development of front-end apps, with scss (optional), pug (optional), ES7, webpack (bundlefy, uglyfy, etc). Very useful to create static websites or apps, without having to worry about setting up the environment.

You can get the source code free on Github.

Features.

  • Modern Technologies: Full support for HTML5, PUG, JavaScript (Vanilla and ES7) and CSS (Sass, scss and PostCSS).
  • Built-in Server: Local development server with live reloading.
  • Performance Tuning: CSS and JavaScript transpilation, bundling, autoprefixing, and minification.
  • Image Optimization: Optimizes images for loading speed.
  • Favicon Generation: Automatically generates all favicons for Web, Apple and Android devices from one image file.
  • Code Linting: Full support for JavaScript (ESLint) and CSS (StyleLint) linting.
  • Setup Wizard: Optionally install helpful libraries and snippets .including:
    • jQuery.
    • Google Analytics.
    • FTP deployment process.
  • Cutting Edge: Uses Webpack for processing and bundling your code.
  • Deployment: Built-in support for deployment via FTP.

Requirements.

  • Node.js (developed with node 12).

Installation Steps.

Clone repo:

 git clone https://github.com/jomendez/simple-webpack-boilerplate &&
 cd simple-webpack-boilerplate &&
 rm -rf .git && git init
  1. Run npm install.
  2. Then run npm run setup to configure the app (include JQuery, etc).

In this step you'll be able to setup your google analytics, enable jquery, setup (optional) an FTP for deployments.

image

  1. Run npm run dev to open a browser and lunch a local web server with live-reload.
  2. Run npm run build build for production (./dist folder).
  3. Run npm run deploy to deploy your code to your FTP.

If everything went well (npm run dev)...

You browser should open a new tab and you should see something like this:

image

Quick example.

It is recommended to create a new page within the src folder or use the one that comes with the example page.pug to start adding your content.

image

Then you can go to src/js/app.js file and add the following lines:

const page = require("../page.pug");
document.querySelector('container').innerHTML = page();

The code above is going to transpile the pug file this particular case (but it can be an html file).
Then we will insert the content of the page into the container tag on the index.html.

My interactive portfolio

jose mendez portfolio

About the author

I describe myself as a passionate Front-end developer, focusing on create, test, and optimize full web apps with compelling user interfaces that runs in web browsers on any device, from desktop computer to tablets and cellphones, therefore, my principal allies are javascript, html, css, and the browser's event loop. That's why you will always find me learning and improving my skills to master those pillars and it's surrounding frameworks and technologies, such as angular, nodejs, ionic, react, etc.

Goals

Some times I find it a little bit hard to interpolate/transmit the description above to recruiters and hiring managers, just with my online presence (before any interview or conversation). That's why my intention is that they just get it by seeing and interacting with this portfolio.

Thus I decided to create a portfolio/profile/interactive resume as a complement for my actual resume and Linkedin profile, in addition to that, also for this two reasons:

  1. To challenge my skills with css animations and interaction.

  2. To create a showcase and challenge myself in a cool framework that I was recently immersing: Threejs which is used to create 3d environments, interactions, etc. on the web.

I wanted to do something different for this project, so I thought... why don't I create a 3d interactive version of myself. I did a research on the internet and I found this article, about how to create an interactive 3D character with Threejs, and I used it as a guide to create my own 3d interactive character:

https://tympanus.net/codrops/2019/10/14/how-to-create-an-interactive-3d-character-with-three-js/

About the (portfolio/profile/interactive resume)

Now, the portfolio/profile/interactive resume can be broken down into 2 main parts:

  1. The get to know the non-technical side of the person, the activities that he likes more (the 4 inner buttons) click on the buttons to know more about the author and see the interactions and animations of the character...

jose mendez portfolio inner menus

  1. The more technical part, more like a resume, showing the technical skills, places he worked, some of his recent work (games, Ionic starters, etc.), featured blog posts, certifications etc.That you can access by clicking on the outer buttons, (placed in the corners)

Portfolio

You can navigate to the portfolio/profile/interactive resume here:

http://www.jomendez.com/portfolio/

Javascript is weird

javascript is weird

I mean, javascript could be weird for developers that are just starting with the language and mostly for developers that comes from other languages like C++ or C# for example.

There are certain areas of the language that cam blow your mind 🤯🤯
In this article we are going to see 5 examples, and keep it simple withing the ~2 min reading time.

Numeric separators

Lets take for example the following code:

const number1 = 2_0_0_0;
const number2 = 6_0_0_0;

console.log(number1 + number2);

What you think the result is going to be?

You can copy and paste the code on a browser developer console or you can play with it yourself on codepen.

The result is 8000, but why?

The thing is that the underscore (_) is a numeric separator for numeric literal. It is used to group digits to make long numbers more readable, for example:

1234567

1_234_567 <-- Therefore, it is more readable with the separator.

More info in this article.

Some weird types.

Another example is when you run the code typeof null

typeof null;
// result object

which incorrectly suggests that null is an object (it isn't, it's a primitive value).

well in this case it is not just a weird thing, it is a bug in the language that can't be corrected because it will brake other parts of the code.

There is a more deep explanation in this article.

Meanwhile...

 typeof NaN;
 // result number.

Is it weird that NaN — “not a number” is actually a number or is just me? On the other hand, NaN is not equal to itself.

console.log(NaN === NaN);
//evaluates false.

Functions.

In javascript a function can self-invoke it self IIFE (Immediately Invoked Function Expression) , so you can do declaration and execution on the same statement.

(function() { console.log('hello'); })();
//display 'hello'

As far as I know this only exist in javascript. It is quite useful, can be used to avoid variable hoisting from within blocks, protect against polluting the global environment and simultaneously allow public access to methods while retaining privacy for variables defined within the function.

You can learn more on this article

Reset an array

And last but not least, the most weird way of resetting an array, you can set the length property to cero: arr.length = 0;.

const arr = [1,2,3,4,5,6];
console.log(arr);
// displays [1, 2, 3, 4, 5, 6]

arr.length = 0;
console.log(arr);
// displays []

I hope you like it, and if you know any other weird thing specific of the javascript language please feel free to share it with us. 😉

javascript proxy – Querying arrays with more readable methods

javascript

javascript Proxy.

This a new feature introduced in the ES6 standard. The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).

The basics.

There are 3 key terms we need to define before we proceed:

  • handler — the placeholder object which contains the trap(s).
  • traps — the method(s) that provide property access.
  • target — object which the proxy virtualizes.

Here is a list of available Traps.

  • apply
  • construct
  • defineProperty
  • deleteProperty
  • get
  • getOwnPropertyDescriptor
  • getPrototypeOf
  • has
  • isExtensible
  • ownKeys
  • preventExtensions
  • set
  • setPrototypeOf

The list going on and on...

The syntax

let proxy = new Proxy( target, trapObject );

Quick example.

Let's see a quick example before we dive in into create our array query library.


class Student {
    constructor(first, last, scores) {
        this.firstName = first;
        this.lastName = last;
        this.testScores = scores;
    }
    get average() {
        let average = this.testScores.reduce( 
            (a,b) => a + b, 
            0 
        ) / this.testScores.length;
        return average;
    }
}

//instantiate the student class  
let john = new Student( 'John', 'Doe', [70, 80, 90] );

let johnProxy = new Proxy( john, {
   //we trap the get and print the property accessed 
    get: function( target, key, context ) {
        console.log( `john[${key}] was accessed.` );
        return john[key];
    } 
});

johnProxy.firstName;
//output.
//> john[firstName] was accessed.
//> <property content>

In this example we are just intercepting the properties called, for example johnProxy.firstName and printed it to the console, this could be used for debugging purpose in dev environments. We can do the same and intersect the 'set' and print a message to the console when we set the value on a property.

Let's create our query library.

It would be similar to write an assertion library, where you can use the name of the field you want to query withing the method's call instead of passing it as a parameter.

First let's create the assertion object.

Here we are going to define the assertion operations, our proxy object will return the objects based on this conditions:

let assertions = {
  Equals: (object, value) => object === value,
  IsNull: (object, value) => object === null,
  IsUndefined: (object, value) => object === undefined,
  IsEmpty: (object, value) => object.length === 0,
  Includes: (object, value) => object.includes(value),
  IsLowerThan: (object, value) => object < value,
  IsGreaterThan: (object, value) => object > value,
  EndsWith: (object, value) => object.endsWith(value),
  StartsWith: (object, value) => object.startsWith(value),
}

The proxy object.

Here we going to trap the get, of the target object to read the name of the property and make sure it starts with findWhere then we use the object field name we want to query, then the assertion (from the assertions above), So the syntax will looks something like this arr.findWhereNameStartsWith('Jo')

let wrap = arr => {
  const prefix = 'findWhere';
  let assertionNames = Object.keys(assertions);
  return new Proxy(arr, {
    get(target, propKey) {
      if (propKey in target) return target[propKey];
      var assertionName = assertionNames.find(assertion =>
        propKey.endsWith(assertion));
      if (propKey.startsWith(prefix)) {
        var field = propKey.substring(prefix.length,
          propKey.length - assertionName.length).toLowerCase();

        var assertion = assertions[assertionName];
        return value => {
          return target.filter(item => assertion(item[field], value));
        }
      }
    }
  })
}

Declare the object.

Next step is to declare the object and wrap it up with the proxy.

let arr = wrap([
  { name: 'John', age: 23, skills: ['mongodb', 'javascript'] },
  { name: 'Lily', age: 20, skills: ['redis'] },
  { name: 'Iris', age: 43, skills: ['python', 'javascript'] }
]);

Calling the methods

console.log(arr.findWhereNameEquals('Lily')) // finds Lily.
console.log(arr.findWhereSkillsIncludes('javascript')) // finds Iris.

The code above the first line will return the object where Property Name is equal to Lily and print it to the console, and the second line will return the object(s) where skills property includes javascript within the array.

Full source code.

Use the following code to play more with javascript proxy.

Things to notice.

Notice how we call the a method in the array that we didn't declared before arr.findWhereAgeIsLowerThan(30) we use the proxy to read this method, the expected syntax is findWhere + <array_field_name> + <assertion> this allow us to create custom queries using the array field name we want to query within the method name:

  • arr.findWhereAgeIsLowerThan(27);
  • arr.findWhereNameEquals('Lily');
  • arr.findWhereSkillsIncludes('javascript');

Wrapping up

With JavaScript proxy, you can wrap up an existing object and intercept any access to its attributes or methods. Even if they don't exist!

There are many real-world applications for Proxies:

  • Create SDK for an API.
  • validation.
  • value correction.
  • Revoke access to an object property/method.
  • Querying arrays with more readable methods (the main topic of this post).
  • property lookup extensions.
  • tracing property accesses.
  • Monitoring async functions.

Conclusions.

Javascript proxy enables a lot of possibilities to create more readable APIs where you can combine field names, assertions and create dynamics methods on the fly, however as you can see in the link below IE doesn't support it and this can be a downside to create code that needs to be supported by all major browsers. Unfortunately, it’s not possible to polyfill or transpile ES6 proxy code using tools such as Babel, because proxies have no ES5 equivalent.

For more info about javascript proxy and browser compatibility you can Learn more here

Add to Home Screen your ionic PWA

Add to Home Screen your ionic PWA

add-to-home-screen

One of the feature of Progressive Web Apps is the ability to add to home screen your application, in a mobile phone or on a desktop computer, if using Chrome (recommended) it handles most of the heavy lifting for you, and on Android, Chrome will generate a WebAPK creating an even more integrated experience for your users.

Starting on Chrome 68 (beta in early June 2018), Chrome will not automatically show the Add to Home Screen banner, instead, you must show it by calling prompt() on the beforeinstallprompt event.

Criteria to fire the "beforeinstallprompt" event

- The web app is not already installed
- Meets a user engagement heuristic (currently, the user has interacted with the domain for at least 30 seconds)
- Includes a web app manifest that includes:
   short_name or name
   icons must include a 192px and a 512px sized icons
   start_url
   display must be one of: fullscreen, standalone, or minimal-ui
- Served over HTTPS (required for service workers)
- Has registered a service worker with a fetch event handler

Note: Other browsers may have different criteria to trigger the beforeinstallprompt event, check their respective sites for full details: Edge, Firefox, Opera.

Show the add to home screen prompt

In order to prompt to the users the Add to Home Screen prompt, you need to:

1- Listen for the beforeinstallprompt event
2- Notify the user your app can be installed with a button or other element that will generate a user gesture event.
3- Show the prompt by calling prompt() on the saved beforeinstallprompt event.

let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  // Prevent Chrome 67 and earlier from automatically showing the prompt
  e.preventDefault();
  // Stash the event so it can be triggered later on the button event.
  deferredPrompt = e;
// Update UI by showing a button to notify the user they can add to home screen
  btn.style.display = 'block';
});

//button click event to show the promt
btn.addEventListener('click', (e) => {
  // hide our user interface that shows our button
  btn.style.display = 'none';
  // Show the prompt
  deferredPrompt.prompt();
  // Wait for the user to respond to the prompt
  deferredPrompt.userChoice
    .then((choiceResult) => {
      if (choiceResult.outcome === 'accepted') {
        console.log('User accepted the prompt');
      } else {
        console.log('User dismissed the prompt');
      }
      deferredPrompt = null;
    });
});

You can only call deferredPrompt.prompt() on the deferred event once, if the user dismissed it, you'll need to wait until the beforeinstallprompt event is fired on the next page navigation.

How to determine if the app was installed

To determine if the application was successfully added to the user's home screen once they accepted the prompt, you need to listen for the appinstalled event.

window.addEventListener('appinstalled', (event) => {
 console.log('installed');
});

Detecting with JavaScript if you app is launched from the home screen

if (window.matchMedia('(display-mode: standalone)').matches) {
  console.log('display-mode is standalone');
}

Safari

if (window.navigator.standalone === true) {
  console.log('display-mode is standalone');
}

Easiest way to test if the beforeinstallprompt event will be fired

Easiest way is to use Lighthouse to audit your app, and check the results of the User Can Be Prompted To Install The Web App test.

Practical example with ionic

For this example I going to use ionic, we are going to generate a PWA with ionic, for this example I assume you are familiar with ionic and you have installed it on your computer, if not, then you can read the here

Lets generate our ionic app:

After you create the ionic blank app, lets run ionic serve:

cd pwa
ionic serve

You should see something like this on your browser:

Open your application using google chrome, open the dev tool, go to audit and run the Progressive web app audit:

You'll notice that the app is only 45% PWA out of the box, we should make some changes first to comply with the requirements to trigger the beforeinstallprompt event:

Registering the service worker

Open the ionic app on your preferred IDE (I'll use Microsoft code) and go to ./src/index.html and uncomment this line:

<!-- un-comment this code to enable service worker
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('service-worker.js')
        .then(() => console.log('service worker installed'))
        .catch(err => console.error('Error', err));
    }
  </script>-->

The another requirement is to have a manifest.json, fortunately ionic generates one for us:

{
  "name": "Ionic",
  "short_name": "Ionic",
  "start_url": "index.html",
  "display": "standalone",
  "icons": [{
    "src": "assets/imgs/logo.png",
    "sizes": "512x512",
    "type": "image/png"
  }],
  "background_color": "#4e8ef7",
  "theme_color": "#4e8ef7"
}

Now lets provide a fallback when JavaScript is not available by just adding a < noscript > tag on the index:

<noscript>
This application needs JavaScript to work, please enable JavaScript on your browser
</noscript>

With just that, we were able to go from 45 to 82:

Now we need to deploy our app to firebase hosting to be able to have HTTPS, and a 100 score on the lighthouse.

Install firebase tools

npm install -g firebase-tools

Initialize your site

$ firebase init

To deploy your site, run the following command from your project's root directory:

$ firebase deploy

For more info go to https://firebase.google.com/docs/hosting/deploying

Now you can sun the lighthouse tool and obtain a 100 score:

Capturing the event

Go back to the ionic app code, locate the pages folder on src/pages/home and edit the home.html and home.ts as follow:

home.html

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  The world is your oyster.
  <p>
    If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will be your guide.
  </p>
  <button class="btn" ion-button full (click)="add_to_home(event)" *ngIf="showBtn" >Install</button>
</ion-content>

home.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  showBtn: boolean = false;
  deferredPrompt;
  constructor(public navCtrl: NavController) {
    
  }

  ionViewWillEnter(){
    window.addEventListener('beforeinstallprompt', (e) => {
      // Prevent Chrome 67 and earlier from automatically showing the prompt
      e.preventDefault();
      // Stash the event so it can be triggered later on the button event.
      this.deferredPrompt = e;
      
    // Update UI by showing a button to notify the user they can add to home screen
      this.showBtn = true;
    });
    
    //button click event to show the promt
            
    window.addEventListener('appinstalled', (event) => {
     alert('installed');
    });
    
    
    if (window.matchMedia('(display-mode: standalone)').matches) {
      alert('display-mode is standalone');
    }
  }

  add_to_home(e){
    debugger
    // hide our user interface that shows our button
    // Show the prompt
    this.deferredPrompt.prompt();
    // Wait for the user to respond to the prompt
    this.deferredPrompt.userChoice
      .then((choiceResult) => {
        if (choiceResult.outcome === 'accepted') {
          alert('User accepted the prompt');
        } else {
          alert('User dismissed the prompt');
        }
        this.deferredPrompt = null;
      });
  };

}

Test in your browser

To test the functionality, we could make some changes on chrome to force to trigger the event (taken from here https://stackoverflow.com/a/50626433/4320602)

For security reasons, as others have written as well, browsers don't allow you to manually trigger the install event.

However, there is a way you can test it yourself. Go to chrome://flags and enable "Bypass user engagement checks"

This will kick off the prompt so you can test.

now run your app and click on the install button, you should see something like this:

Now the app will run as standalone app:

Happy coding,
Cheers

Ionic 2 google signin Error 10 with firebase

Ionic 2 google signin Error 10 with firebase

The mysterious Error 10

I hope this article helps to clarify and find a solution quickly to the Error 10 using ionic 2 framewrok with firebase sign in and cordova-plugin-googleplus. I was developing an Ionic 2 application "quiz dev" to create a playful platform for developers to practice and improve their skill through quizzes, based on the spaced repetition approach. I wanted to provide the user the ability to sing in into the application using their google account.

error 10

The issue

The point is, that I've spend 2 or 3 days trying to figure out the error 10 I was receiving once I deployed to the Android Play Store. I followed the official documentation of Ionic https://ionicframework.com/docs/native/google-plus/

I installed the cordova-plugin-googleplus and implemented the plugin (I going to skip high level details, for more information refer to the documentation provided here)
 

  this.googlePlus.login({
        'webClientId':'#############-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
        'offline': true
      })
          .then(res => {
             //logged in
              ...
          })
          .catch(err => {
              alert("There is an error " + JSON.stringify(err));
          });

 

After that, I signed my debug.apk following the steps here, this is the google official documentation, then I get the SHA-1 fingerprint certificate that is going to be needed to setup the firebase project, you can do it via cmd following these steps. The result is going to be something like this:
sha-1 fingerprint certificate

I had set up a Firebase project, following the steps here https://chriztalk.com/ionic-2-firebase-google-authentication/

The headache

At this point installing the application in my device in release or debug mode, everything was working properly. Then I decided to deploy it to the google android app store. When installing the app from the android app store I wasn't unable to login with my google accounts, the previous code to handle the google sign in was entering in the catch section and showing an alert with error 10
 

 
          .catch(err => {
              alert("There is an error " + JSON.stringify(err));
          });

The solution

After spending hours and hours trying to figure out what the issue was, I realize that there is an option when you are setting up your application in the google app store that ask you if you want to sign your apk in the store. After you say yes it shows you a message like this:
google app store apk sign
 

the real solution is to go to Release Management/App signing section and get the SHA-1 fingerprint certificate and include it in your Firebase project
 
app signing google android app store

Go to your Firebase project configuration and add you SHA-1 fingerprint and it will do it
 
firebase add sha-1 fingerprint

Final thought

I really hoe this save you a lot of time of banging your head against the wall.

Here is a demo of the app, you can from android to ios here. The is the application in the android app store in case you are interested https://play.google.com/store/apps/details?id=com.evolutionsys.quiz&hl=en

Quick Introduction to VueJS

vuejs

What is Vuejs?

What makes VueJs special is the fact that was designed to be incrementally adoptable, the core is dedicated to the view layer only but you can combine it with other libraries in order to create great single pages apps. Is very versatile and flexible yet lightweight, there is also components that allows you to handle routes and AJAX requests, hence is able to provide high quality results from a little gadget to a more complex SPA.

Why chose Vue.js?

  • The documentation is so good that it is the only tutorial you will need to understand and be able to dominate Vue.js efficiently.
  • The Vue.js community is growing.
  • Solutions through libraries and plugins well supported.
  • The way Vue.js do the things allows you to produce great code, efficient as well as readable.

Comparison with other frameworks

Vue.js vs React

Similarities:

  • Uses a Virtual DOM
  • Reactive and composable view components
  • Focused on the core library, so global state management and routing are delegated to third libraries

Differences:

  • Vue.js offers better performance than React, As you can see here.
  • In React all the UI components are represented rendering functions using JSX. In the other hand Vue.js provides render functions, provides support for JSX and also as default offers declarative templates (very readable by the way).
  • The ecosystem around custom renders makes React a winner in this aspect.
  • In matters of CLI Vuejs got leverage because of the limitations of React in this area, related with the lack of configurations.
  • Before to start working with React you should be familiar with JSX and ECMAScript 6, because most of the examples out there uses It, in the other hand Vuejs is more simple, to get it running you just need a single script on your page.

Vue.js vs Angular 1
Similarities:

  • Vue.js in an early stage of development inspire in the Angular syntax (e.g. v-if vs ng-if).

Differences:

  • Vue.js is way much simpler than Angular 1. A newbie is able to write functional code in a day with Vue.js, with angular, the learning curve is more higher.
  • Angular 1 ‘forces’ you to build the app under a specific and non-so flexible structure. Vue.js in the other hand is more flexible and modular.
  • Vue.js enforces a one-way data flow between components while Angular 1 uses two-way binding between scopes.
  • Vue.js offers better performance than Angular 1 because Angular one uses dirty checking with a cycle digests this can affect the performance.

Vue.js vs Angular 2:

Similarities:

  • Performance is equal because both are very fast.
  • Both are well suited for Enterprise environments.

Differences:

  • Vue.js is more flexible than Angular 2 in terms of the app architecture. Angular has a well defined architecture, Vue.js is more simple.
  • In terms of learning curve, Vue.js is extremely low while Angular 2 is too steeper.

To see more comparison of VueJs and other frameworks, you can go here:
https://vuejs.org/v2/guide/comparison.html

Simple app example with Vue.js.

Let's create an simple object in javascript

 
var example = {
message: ‘Hi Vue’
}

This is going to be the template

 
<div id="container">
{{message}}
</div>

Vue in action, binding the template with the object:

 
new Vue({
el: '#container',
data: example
})

Here is a working example

 
Let’s see an example making use of a Vue.js directive: v-for:

This is the html template:

 
<html>
 <head>
<script src="./vue/dist/vue.js"></script>
 </head>
<body>
 <div id="app-example">
 <p v-for="human in people">                        
 {{ human.name }}
 </p>
 </div>
</body>
<script src="./app/myapp.js"></script>
</html>

Binding the template with the data

 
var app = new Vue({
  el: '#app-example',
  data: {
    people: [
     {name: 'albert'}, 
     {name: 'john'}, 
     {name: 'justin'}
     ]
  }
});

Here is a working example:
 

More examples can be found here: https://vuejs.org/v2/guide/, the introduction guide to Vue.js is one of the best tutorials you'll find.

Let's see another example, this time we are going to create a custom filter to reverse the text:
 

Here is an example where I use more concepts like, filters, methods, computed, the code is commented but if you don't understand the concepts and how it works you can visit the Vue official documentation, or see this video from Egghead:
https://egghead.io/courses/develop-web-apps-with-vue-js