Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Angular Shopping Cart for Affiliate Marketing - Angular 5

4.86/5 (55 votes)
22 Nov 2016CPOL19 min read 194.2K   7.1K  
Angular Shopping Cart for Affiliate Marketing in Angular 5 that Is Responsive with TV Commercials with Powerful Features that Drive Real Sales like Unlimited Distributor IDs for Commissions with Editor

Click Here to See A Working Demo of this Angular Shopping Cart

Click Here to See An Advanced Version of This Shopping Cart

Watch Video Demonstrating Shopping Cart Features

Image 1 Image 2 Image 3

Angular 5 Shopping Cart for Affiliate Marketing

I updated this article and the sample project to Angular 5. The original article and AngularJS Shopping Cart project can be found at:

http://www.software-rus.com/articles/articles.html?article=AngularResponsiveCart

Many people would like to sell products online but they don't have any prodcts to sell. And, many people would like to have other people sell the products they have but don't know how to find those people.  This Angular 5 Shopping Cart with Video for MLM & Affiliate Marketing does both.  You can give this cart to distributors filled with your products to put on their websites and it will pass the orders to you from any merchant account provider like PayApal with the Distributor ID of the distributor that the order came from so you can pay them commissions. In addition, you can also give distributors a link with their Distributor ID and those orders with the passed in Distributor ID will pass into PayPal or any designated merchant provider.

The Shopping Cart in this project includes the ability to play videos from servers all over the world. The reason for this is that pictures in shopping carts in today's world are not feective in delivery the benefits of why somebody should buy a product. A video is a TV commercial that studies have shown is thousands of times more effective in generating sales. For example, teh YOUKU server in China is now the largest television network in teh world and you can post your videos (TV commercials) for free on the YOUKU server and play them in this Shopping Cart in stead of a boring picture of a product.

There are a lot of people who are not computer or Internet savy but who need a simple shopping cart that doesn't require a database or a programmer to install it. I recall a customer calling me up once for tech support for one of my software programs and telling me "Your software doesn't work!" I asked what was the problem and he stated that he was stepping on the "foot pedal" and nothing was happening. It turned out that he had put the mouse on the floor and thought you had to pump it with your foot. Needles to say it was a challenge to help him. 

To start with I wanted to include a Pinterest Style Layout so I decided to use a common one that I have seen used often in shopping carts, namely, Codrops famous ViewModeSwitch, that you can find at: https://github.com/codrops/ViewModeSwitch.  ViewModeSwitch is a CSS Pinterest Style Layout that is used n many commercial shopping and it works well with AngularJS with minimal changes.

Here is a video demonstration of the shopping cart:

Angular 5 TV Shopping Cart Features

Here are some of the practical features I included:

  • Written with Angular CLI and Typescript.
  • Ability to GET PAID on Your Commissions and to Pay Commissions.  
  • Reading Config & Products Data BEFORE App Startup in Angular 5 Using APP_INITIALIZER
  • Added Easily Customized Shipping and Handling.
  • Expanded PayPal features Including Notify and Cancel Pages.
  • Must Include Bootstrap 3 without adding ui.bootstrap
  • Must be responsive so it will display and scroll perfectly on any mobile device.
    See example of mobile app using this cart at: www.SerGioApps.com
  • Must have a Cool-Looking, Responsive Bootstrap Menu. 
  • Allow Multiple Stores in our cart.
  • Must read the products and their descriptions from an internal JSON text file.
  • Must read the products and their descriptions from an external JSON text file using JSONP.
  • Must be able to play a Video (TV Commercial) about a product in addition to a picture of the product from hundreds of tube servers around the world. Must play videos posted on the YOUKU server in China which is now the largest television network in the world.
  • Must at least include merchant gateways for PayPal, Google Wallet, and Stripe.
  • Must be extensible so that adding new features like payment methods is easy.
  • Must allow FREE products that can't be added to the cart using a faux parameter
  • Must handle Google Analytics using Angular 5.
  • Must be able to include links to thrird-party websites like Google Play, etc.
  • Must have a directory structure that allows it to be "dropped" at the root level onto any existing website.
  • Must display selected text as HTML so it attracts the potential customer visually.
  • Must be able to display products in a Pinterest Style Layout or a Listview Layout
  • Must include Slide Button Pagination to control number of products displayed per page
  • Must include Filter & Sort Options
  • Must be able to create Distributor Links for non-Angular sites for Distributor Commissions

Installing Node.js To Get Started

If you are PC(Window) or OS X (Mac) user you can install the latest version of node at:
https://nodejs.org/en/download/ using one of the installers and follow the steps.

If you install the latest version on Windows you will probably get a variety of errors that will take you hours of searching the Internet to fix. One possible solution is to not allow the installer to set the Environment PATH which is the default setting in the setup and to set the Environment PATH manually.

At this point if you tried using npm some people will get the dreaded and now famous error:

npm ERR! Windows_NT 6.1.7601  

There are numberous working fixes for this error if you are behind a proxy but if you are'n't behind a proxy then trying to fix this error can make you crazy. To fix this error or if you just updated to the latest version of npm then run the the commands below in a CMD window launched as ADMINISTRATOR:

npm config delete http-proxy
npm config delete https-proxy
npm config delete proxy -g
npm config delete http-proxy -g

// THE REAL MAGIC TO FIXING THIS ERROR IS:
npm config set registry "http://registry.npmjs.org"
npm config set strict-ssl false

If you still get this error after installing npm: 

<code>events.js:72
        throw er; // Unhandled 'error' event</code>

It is most likely due to your not using the correct CodePage on Window 7 or higher. On Windows the Code Page should be set to 850, NOT 437, BUT be careful in setting the Code Page to 850 since if you do this incorrectly your Windows computer may NOT boot up again. Research the correct way to set Code Page to 850 before attempting this.

Let's Use Angular 5 CLI

Install Angular CLI which will also install Angular's "ng" command globally on your system as shown below.

At this time Angular 5 should install with the commands below. I won't go into installing Angular 5 at this time because you can find plenty of documentation on it on the Internet. I will keep the focus of this article on the source code for Angular 5 Mobile Apps.

Directions for installing Angular-CLI are at: https://github.com/angular/angular-cli#updating-angular-cli

We should start by understanding Webpack, System.js and angular-cli. System.js was heavily used in the beginning when Angular 2 was being built. Webpack evolved next and finally, the defacto standard now, Angular CLI evolved as a sort of wrapper for Webpack and to help scaffold new projects and create components. easily. Installing angular-cli which will also install Angular's "ng" command globally on your system: Directions for installing angular-cli are at: 

https://github.com/angular/angular-cli#updating-angular-cli

npm uninstall -g angular-cli
npm uninstall --save-dev angular-cli
npm uninstall --save-dev angular/cli
npm uninstall -g @angular/cli
npm cache clean
Delete the C:\Users\YOU\AppData\Roaming\npm\node_modules\@angular folder.
Reboot, then, finally, run:
npm install -g @angular/cli@latest
To verify whether your installation
completed successfully, you can run:

ng version

@angular/cli: 1.3.1
node: 7.4.0
os: win32 x64

Install Our Angular 5 Shopping Cart

Download and unzip the file "cart-app.zip" at the top of this article and place the unzipped folder 'cart-app' into whatever directory you use for your Angular projects.  On my computer I have a directory called "Angular." The name of this directory can be anything you want to call it. From inside that directory using the CMD prompt in administrator mode and run the following command in the cart-app folder as follows:

Select a folder - I used C:\Angular and put the unzipped 'cart-app' folder in there and run:

<a href="file:///C:/Angular%3Ec">C:\Angular>c</a>art-app>npm install 

This will install the node_modules folder which is very large so be patient. Next we will use Visual Studio Code IDE which works nicely on both Winows and Mac computers. and build the Angular 5 App in this editor.

Installing & Using Visual Studio Code IDE

I used Microspoft's Visual Studio Code IDE which you can easily download and install from:  http://code.visualstudio.com/

Open Visual Studio Code and select the project folder "first-app" and open the Integrated Terminal Window as shown below. In the Integrated Terminal Window in Visual Studio Code run the command below which will create your "dist" directory for your finished project.

Image 4

Then run from the IDE the following commands:

C:\Angular>mobile-app>ng build
C:\Angular>mobile-app>ng serve

This will start our Node.js server running on port 4200 so if you open your Chrome Web Browser to http://localhost:4200 you will see the application running. This will run the default Angular App that comes with Angular CLI. 

What Can Go Wrong When You Run The App?

Many users will get the error:

Module build failed: TypeError: Cannot read property 'newLine' of undefined

When you get this error it is typically caused by either an incorrect version of Angular - CLI. One fix that works is to run:

npm uninstall-g @angular/cli
npm clean cache
npm install Last-g @angular/cli @
then remove the local node_modules folder and run:
install npm–Save-dev @angular/cli @ Last
npm install

You must stay current with the latest changes at: 
https://github.com/angular/angular-cli#updating-angular-cli

How to Compile Angular 5 Apps Using Ahead-of-Time Compilation (aot)

Why Ahead-of-Time (AOT) compilation Instead of Just-in-Time (JIT) compilation?

  • Much faster rendering, because a pre-compiled version of application downloads.
  • Much fewer asynch requests.
  • AOT ensures that everything is built into a single file (well atleast for your code).
  • Much smaller Angular framework size.
  • AOT will also ensure that your application is “well written” which can be a pain in the butt.

As of Janurary 2017 If you are using angular-cli, AOT compiling is now the default compilation method when running the following command ng build --prod with no code change requirements.

I will jump ahead here to explain how to build your "www" folder for mobile. The BIG SECRET to compiling an Angular 5 App for to run out of a folder isn't obvious. To build an Amgular 5 App so it will work is setting up the pathways correctly. Look at the index.html from the src folder you added to the project and you will notice that in the index.html file we replaced:

<base href="../" />

with

<script>document.write('<base href="' + document.location + '" />');<script>

When you refresh a page this will dynamically set the base href to your current document.location.

And if you look at app.routing.ts you will see that I added made sure we using Hash Tag Location in app.routing.ts:

@NgModule({ imports: [RouterModule.forRoot(routes, {useHash: true})], exports: [RouterModule] })

 Instead of:

@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] })

Our Angular 5 Shopping Cart is also an Angular 5 Moble App for importing into XCODE (iPhone) or Android Studio. Our default build folder, namely, projectFolder/dist/ Will NOT work for our production version if we also want it to function as a mobile app. To create our production build we need to use some extra commands.

We use the folder name "www" so I can use it as a mobile app as well as a web based app but you can change this to any name after you build it for production and then just paste it into your website.

Let's create a production build of our Angular 5 Shopping Cart using the following command.

// Run in command line when directory is projectFolder
// flag prod bundle for production & flag aot enables the
// ahead-of-time compilation also known as offline compilation.
// --prod is now the same as --prod --aot
ng build --prod --base-href /$ROOT/Angular/cart-app/www/

In the pathway above you will notice that I used the folder "Angular2" on my "C" drive and created my "cart-app" folder inside that directory. If you have your project in a different folder then adjust the pathway above accordingly. The contents of the generated "www" folder will go into our "www" folder in Android Studio or XCODE to use the Angular 5 Sopping Cart as a Mobile App and all the pathways will actually work. Viola!

Deployment to IIS7 & Other Servers

I still use IIS 7 and on IIS 7 and later versions you MUST be sure to set the MIME type for our json files. Our Angular 5 Shopping Cart uses config.json and products.json which require that the correct MIME Type is set on IIS 7 or any server. By default IIS 7 or any of the IIS are not configure to handle .json extension. So below is a very simple method to do that. You can apply the method on the root of IIS so .json can be handled by every site or virtual folder in the IIS or just to the specific site.

  1. Open IIS Manager
  2. Display properties for IIS Server
  3. Click MIME Types and then add JSON extension:
    • File name extension: .json
    • MIME type: application/json
  4. Go back to the properties for IIS Server
  5. Click on Handler Mappings
    • Add a script map
    • Request path: *.json
    • Executable: C:\WINDOWS\system32\inetsrv\asp.dll
    • Name: JSON

Routing in Our Angular 5 TV Shopping Cart

We have only a few simple views in our app, namely, store, product, checkout, and blank. You can easily add more views like Legal Notices, Terms of service, Refund Policy, Cordova or PhoneGap if you use as a mobile app, etc. BlankComponent is used as a fudge for certain route calls.

const routes: Routes = [
    { path: '', component: StoreComponent },
    { path: 'store', component: StoreComponent },
    { path: 'cart', component: CartComponent },
    { path: 'product/:id', component: ProductComponent },
    { path: 'blank', component: BlankComponent }
];

Reading Data BEFORE App Startup in Angular 5 Using APP_INITIALIZER

We want all of our views to have easy access to our Configuration & Products Data since once loaded this data does NOT change. To accomplish this we add the following in our app.module.ts file as follows.

JavaScript
// IN OUR APP.MODDULE.TS FILE...

import { NgModule } from '@angular/core';
import { APP_INITIALIZER } from '@angular/core';
// Other imports for our Modules...
import { Injectable } from '@angular/core';
import { Http, Jsonp } from "@angular/http";
// Too many files inside Rx folder causes delay in loading 
// so we don't load all of them to improve loading time.
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { ConfigService} from './services/config.service';

// We are Using AOT, So useFactory Can't be a Dynamic Function. 
// We MUST Use An EXPORTED function as shown below. 
export function initConfig(config: ConfigService){
    return () => config.load();
}

@NgModule({
  declarations: [
    AppComponent,
    NavbarComponent,
    BlankComponent,
    StoreComponent,
    CartComponent,
    ProductComponent,
    CapitalizePipe,
    UniquePipe,
    OrderByPipe,
    SafeHtmlPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    FormsModule,
    JsonpModule,
    AppRoutingModule
  ],
  providers: [
    LocalStorageService, 
    DataObservableService, 
    PagerService, 
    OrderByPipe, 
    SafeHtmlPipe,
    ConfigService,
    {
        provide: APP_INITIALIZER,
        useFactory: initConfig,
        deps: [ConfigService],
        // If you use Jsop then also pass in Http & Jsonp 
        // deps: [ConfigService, Http, Jsonp],
        multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

In our config.service.ts file we will retriev our JSON Config data and our Paroducts Data. We will use a combination of both Promise and Observable for best results.

Promise - A Promise handles a single event when an async operation completes or fails.

Observable - An Observable is like a Stream that allows you to pass zero or more events where the callback is called for each event. Observable is preferred over Promise because it provides the features of Promise and more. With Observable it doesn't matter if you want to handle no event, one event or multiple events. You can utilize the same API in each case.

As shown below is our config.service file in which we will load our Config.json file using a Promise and then we will read DATA_SOURCE to see what method to use to load our Products.json file.

JavaScript
// THIS IS OUR CONFIG.SERVICE.TS FILE
import { Inject, Injectable } from '@angular/core';
import { Http, Jsonp, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { DomSanitizer, SafeResourceUrl, SafeHtml, SafeUrl, SafeStyle} from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
// Too many files inside Rx folder. So I did this to improve loading time.
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Config } from '../services/config.static';

@Injectable()
export class ConfigService {

    // Load configuration data so they will be available to all views
    private static _config: Object = null;
    // Load products so they will be available to all views
    // We can read from _promise value of DATA_SOURCE to determine 
    // what method to use, local or remote, to get Products Data.
    private static _products: Object = null;
    private static _promise: Promise = null;
    private retryCount = 2;
    headers: Headers;
    options: RequestOptions;

    constructor(private http: Http,
                private _jsonp: Jsonp,
                private sanitizer: DomSanitizer) {
        this.headers = new Headers(
            {
                'Content-Type': 'application/json',
                'Accept': 'q=0.8;application/json;q=0.9',
                'async': true,
                'dataType': 'jsonp'
            }); 
        this.options = new RequestOptions({ headers: this.headers });
        ConfigService._promise = this.load();
    }

    public config(): any { return ConfigService._config; }
    public getProducts(): any { return ConfigService._products; }
    public configKey(key: any) { return ConfigService._config[key] }
    getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }

    load() {
        let local_base = './assets/data/' + 'config' + '.json?';  
        // we add a random value to prevent caching - this trick works nicely!
        let local_rnd = 'rnd=' + this.getRandomInt(1, 500);
        let local_url = local_base + local_rnd;
        return new Promise((resolve, reject) => {
            this.http.get(local_url)
                .map((response: Response) => response.json())
                .catch((error: any) => {
                    console.error(error);
                    return Observable.throw(error.json().error || 'Server error');
                })
                .subscribe((data) => {
                    ConfigService._config = data;
                    // resolve(true); // UNSLASH THIS IF YOU DON'T GET PRODUCTS HERE !!!
                    // INCLUDE THIS IF YOU WANT TO RETRIEVE PRODUCTS HERE ////
                    let request: any = null;
                    switch (data.DATA_SOURCE) {
                        case 'local': {
                            local_base = './assets/data/' + 'products' + '.json?'; 
                            local_rnd = 'rnd=' + this.getRandomInt(1, 500);
                            local_url = local_base + local_rnd;
                            request = this.http.get(local_url);
                        } break;
                        case 'remote': {
                            // THIS IS AN EXAMPLE OF HOW TO USE A JSONP SERVER
                            let _store = '';
                            let _userid = '';
                            const jsonp_base = data.JSONP_DOMAIN1;
                            let jsonp_param = 'store=' + _store +  '&userid=' + _userid;
                            jsonp_param = jsonp_param + '&methodName=Feeds&jsonp=JSONP_CALLBACK';
                            let jsonp_rnd = '&rnd=' + this.getRandomInt(1, 500);
                            let jsonp_url = jsonp_base + jsonp_param + jsonp_rnd;
                            request = this._jsonp.get(jsonp_url, this.options);
                        } break;
                        case 'default': {
                            console.error('Environment file is not set or invalid');
                            resolve(true);
                        } break;
                    }
                    if (request) {
                        request
                            // .retry(this.retryCount) Deprecated in Angular 5
                            .map( (res) => {
                                let products = res.json();
                                this.checkProducts(products);
                                return products;
                            })
                            .catch((error: any) => {
                                console.error('Error reading ' + data.DATA_SOURCE + ' configuration file');
                            })
                            .subscribe((responseData) => {
                                ConfigService._products = responseData;
                                resolve(true);
                            });
                    } else {
                        console.error('Env config file "env.json" is not valid');
                        resolve(true);
                    }
                });
        });
    }

    checkProducts(prods: any) {
        if (prods) {
            prods.forEach((data) => {
                // Get embed format for given tube servers like youtube, vimeo, youku, etc.
                data.link  = this.getVideoEmbed(data.tube, data.videoid);
                data.videopage = this.sanitizer.bypassSecurityTrustResourceUrl(data.link);
            });
        };
    }
    // ... ETC.
}

Some people may have trouble getting JSONP to work so I will explain some of the things you need to know. You can run a JSONP server easily on your server with a few lines of PHP code or you can use C# .NET etc.  The design concept I used for my JSONP server was that instead of having multiple generic handlers or a single handler with lots of switch/if statement I decided to use a single generic handler with Factory Design Pattern. The Factory returns a class based upon the methodName that is passed which is used to only handle that request. The Factory reads the methodName and its class from the web.config file and instantiates the handler. The generic handler requests the Factory for the handler and performs some pre/post processing. Here is a link to an article I wrote on creating a JSONP Videos & TV Commercials server using C# .NET which is what I used in testing the JSONP code in this Angular 5 Shopping Cart App.

You can DOWNLOAD my JSONP Server to Stream Videos. Movies, TV Shows, Tube Channels, and TV Ads from Hunndreds of Tube Servers:

C# .NET JSONP Server

Most people have problems getting this one part of the url correct:

&methodName=Feeds&jsonp=JSONP_CALLBACK'

Look at the "jsonp" in the line above - the letters is determined by your JSONP sever and will vary from server to server. In my C# JSONP Server I used "jsonp" but you will also see in other servers "callback", or just "c" but its value is based on the server. In other words, don't just use what you commonly see in articles like "callback" but check to see what the JSONP server you are connecting to requires.

Using Our Pre-Loaded Config & Products Data

Retrieving our Config and Products Data is now easy to do in any of our views as follows.

this.config = this.configService.config();
// alert('Configurations: '+ JSON.stringify(this.config));


this.products = this.configService.getProducts();
// alert('Configurations: '+ JSON.stringify(this.products));

I added a file called config.static to illustrate another approach and perhaps better approach you can use for global configuration files. Using this approach is illustrated below.

import { Config } from 'app/services/config.static';
alert(Config.CONFIG.STORE_BG_IMAGES[0]);

Our Angular 5 Slide Button Pager

You can see our PagerService buttons shown below.

Image 5

Our pager is actually fairly simple and the code for it is as follows.

<table style="float:right;">
    <tr><td>
        <!-- slide button pager -->
        <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
            <li [ngClass]="{disabled:pager.currentPage === 1}">
                <a (click)="setPage(1)">First</a>
            </li>
            <li [ngClass]="{disabled:pager.currentPage === 1}">
                <a (click)="setPage(pager.currentPage - 1)">Previous{{page}}</a>
            </<li>
            <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                <a (click)="setPage(pager.currentPage + 1)">Next</a>
            </<li>
            <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
                <a (click)="setPage(pager.totalPages)">Last</a>
            </<li>
        </<ul>
    </<td></<tr>
</table>

Playing Embed Videos in Angular 5

In our app we retrieve videos from the hundreds of tube servers that allow embedding in web pages. In addition to displaying millions of movies and all kinds of videos this code will also display YOUR monetized videos from these Tube Servers like YouTube among movies and other videos. In our ConfigService we apply in checkProducts the embed format for various tube servers as follows.

checkProducts(prods: Product[]) {
    if (prods) {
        prods.forEach((data) => {
            // Get embed format for tube servers like youtube, vimeo, youku, etc.
            data.link  = this.getVideoEmbed(data.tube, data.videoid);
            data.videopage = this.sanitizer.bypassSecurityTrustResourceUrl(data.link);
        });
    };
}

The Angular 5 Product View

This view shows more details about a product and also allows users to add or remove the product in/from the shopping cart and shows how many of the product are added to the cart. You can display a video of the product or an image. If an image of the product is displayed then clicking on the image will popup a dialog showing a larger view of the image. You can see below what the Product View looks like with an image displayed.

The Products Module uses the ConfigService to get the products data and then selects whatever "id" was passed by the router.

// private route: ActivatedRoute 
// get URL parameters via Route
this.sub = this.route
    .params
    .subscribe(params => {
    this.params = params['id'];
    this.getProducts();
});

getProducts() {
    this.prods = (this.configService.getProducts()).filter(prods => 
        ((prods.sku === this.params) || (this.params === '')) );
    window.scrollTo(0, 0);
}

Image 6

The Angular 5 Cart View

Our CartModule View calls CartService in cart.service.ts which uses Observable on localStorage as follows.

loadItems(): Observable {
    let items = localStorage != null ? localStorage[this.cartName + '_items'] : null;
    if (items != null && JSON != null) {
        try {
            items = JSON.parse(items);
            for (let i = 0; i < items.length; i++) {
                let item = items[i];
                if (item.sku != null && item.productname != null && item.unitprice != null 
                    && item.saleprice != null && item.showsale != null 
                    && item.quantity != null && item.sh != null && item.faux != null) {
                    item = new this.cartItem(item.sku, item.productname, item.unitprice, 
                        item.saleprice, item.showsale, item.quantity, item.sh, item.faux);
                    this.items.push(item);
                }
            }
        }
        catch (err) {
            // ignore errors while loading...
        }
    }
    return items;
}

Users can edit the cart and checkout using PayPal, Google Wallet, and Stripe. Below is what the Cart View looks like on a laptop.

Image 7

  1. PayPal. This payment method specifies the merchant account or BuyNow account(not a merchant account) to use for payment. To use PayPal, you have to create either a BuyNow Account or a merchant account with PayPal. You can do that here: https://www.paypal.com/webapps/mpp/merchantaypal.com/webapps/mpp/merchant
  2. Google Wallet. This payment method requires that you create a merchant account with Google. You can do that here: https://developers.google.com/commerce/wallet/digital/training/getting-started/merchant-setup
  3. Stripe. This payment method allows you to embed their API on a websites to accept payments, without the need of getting a merchant account. Stripe has no setup fees, monthly fees, minimum charges, validation fees, card storage fees, or charges for failed payments. Stripe has a 7-day waiting period for transactions to be completed so that Stripe can profile the businesses involved and detect fraud. https://stripe.com
Image 8

As I explained earlier you can use the compiled files as a Mobile Shopping Cart that you can install on any Mobile Device or as a web based Angular 5 Shopping Cart on your website.

Shown on the left I am using it on a Mobile Phone for my comic book collection.

The best feature is that I can set a DISTRIBUTER_ID in my Config.json file and give a link or the folder with this app to someone who wants to sell my products and get paid a commission.

Very Cool GUI & Hover Effects

To start with I wanted to include a Pinterest Style Layout so I decided to use a common one that I have seen used often in shopping carts, namely, Codrops famous ViewModeSwitch, that you can find at: https://github.com/codrops/ViewModeSwitch.  ViewModeSwitch is a CSS Pinterest Style Layout that is used n many commercial shopping and it works well with AngularJS with minimal changes.

I decided to add a collection of hover animations and I wrote an animation editor that is in the menu to select and apply different hover animations to different objects in the cart. I loooked at a number of hover libraries and picked one called Hover that I really liked by Ian Lunn which you can explore on his GitHub at: https://github.com/IanLunn   

To apply an effect you simply select the Effects tab in the menu and then selct one of the green radio buttons, namely: storeimg, store pill, carousel img, or carosel pill. Note that the carousel options are only avaiable if you have added the JavaScript for the Super Slick Carousel.  After selecting the object you want to apply the hover effect to simply click on the effect you want in the list belwo. You can easily define new objects to apply these effects to in the views.

Image 9

The hover effects from the Hover library are applied as follows:

changeAnimation(effect_name) {
  event.preventDefault();
  this.isOpenNavbarAnimation = !this.isOpenNavbarAnimation;
  let e = '';
  if (this.myModel === 'carousel_img_video') {
      e = '.carousel_img_video';
  } else if (this.myModel === 'carousel_pill') {
      e = '.carousel_pill';
  } else if (this.myModel === 'store_img_video') {
      e = '.store_img_video';
  } else if (this.myModel === 'store_pill') {
      //e = '.nav-pills li';
      e = '.store_pill';
  }
  if (e.length > 0) {
      $(e).removeClass(function (index, css) {
          return (css.match(/(^|\s)hvr-\S+/g) || []).join(' ');
      });
      $(e).addClass(effect_name);
  }
  if (effect_name.length > 0) {
      $(e).removeClass(function (index, css) {
          return (css.match(/(^|\s)hvr-\S+/g) || []).join(' ');
      });
      $(e).addClass(effect_name);
  }
};

The controls below set the effects above::
Image 10

// create a radioButtonGroup for our apply effects options
public myOptions = [
    { id: 'store_img_video', name: 'store img', disabled: false, showinfo: '' },
    { id: 'store_pill', name: 'store pill', disabled: false, showinfo: '' },
    { id: 'carousel_img_video', name: 'carousel img', disabled: false, showinfo: '' },
    { id: 'carousel_pill', name: 'carousel pill', disabled: false, showinfo: '' }
];

Bootstrap 3 Navbars

I used Bootstrap 3 but NOT ui.bootstrap because ui.bootstrap gives me headaches trying to keep up with their changes. Bootstrap 3 has navbars where it easy to change the look-and-feel of the navbars from in side your app using AngularJS as demonstrated below in the shopping cart. To create the gradient in these navbars I used the gradient editor at: http://www.colorzilla.com/gradient-editor/.​ 

Image 11

For the Navbars I applied Color Coordination with the Navbars so that each navbar would have its own Hover Effect when hovering over the pills created by Codrops famous ViewModeSwitch,  The code that changes the background color and enlarges the image as well as dozens of other cool hover effects are applied using the Hover library.  A few other transition effects are from the project on Codrops related to ViewModeSwitch called ResponsiveIconGrid at: 

http://tympanus.net/Blueprints/ResponsiveIconGrid/#

In each Navbar style sheet we have that hover gradient css for the pills as follows.

Which produces the different hover effects for each navbar. However, we need to turn off many of these effects when the shopping cart is on a mobile device and the CSS in this project does that to achieve a nicer display on mobile devices. Dozens of samples of all kinds of animation effects for Codrops famous ViewModeSwitch are available on Codrops.  However remember that animation effects are distracting and take a reader's attention away from the ad copy for your products so use them sparingly.  Below you can see there are a large number of effects you can apply to any object in any view. The red button in the tab menu dropdown allows you remove any hover effect you have applied.

For additional glyphicons check out:

http://glyphicons.bootstrapcheatsheets.com/

One of the things you have to decide is how to handle closing of expanded dropdowns when there is an off menu click. I tried several approaches to this and finally decided on the following approach to handle off menu clicks to close any expanded dropdowns in our NavbarComponent as shown below.

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
  host: {
    '(document:click)': 'offNavClick($event)',
  },
  providers: [WindowService, DataObservableService, LocalStorageService, CartService]
})

  constructor(private _eref: ElementRef) { }

  offNavClick(event) {
    // Off menu code to close dropdowns
    if (!this._eref.nativeElement.contains(event.target)) {
      this.isOpenNavbarTheme = false;
      this.isOpenNavbarAnimation = false;
      this.isOpenNavbarVideoSites = false;
    }
  }

Bootstrap 3 Gradient Buttons

I don't like the look of Bootstrap 3 buttons so I decided to give them some depth as shown below. To do this I used a really cool Bootstrap 3 Editor that creates buttons with a gradient and mouse over and mousedown eeffects with a single block of CSS code at: http://charliepark.org/bootstrap_buttons/

Image 12

Adding Features to Your Angular 5 TV Shopping Cart Application

You can use the ng generate command to add features to the app by going to the directory you want to add the module, service, etc. to using one of the commands below:

  • ng generate class my-new: adds a class to your application
  • ng generate component my-new: adds a component to your application
  • ng generate directive my-new: adds a directive to your application
  • ng generate enum my-new: adds an enum to your application
  • ng generate module my-new: adds a module to your application
  • ng generate pipe my-new: adds a pipe to your application
  • ng generate service my-new: adds a service to your application

For example to add a Cart Service you would go to the directory you want to add it to and type:

C:\Angular2\cart-app\cd src\app\services
C:\Angular2\cart-app\src\app\services>ng generate service cart

Conclusion

I also like Bootstrap, because it makes it easy to create attractive, responsive HTML layouts. In addition to a nice set of styles and icons, Bootstrap also provides some JavaScript components that you can use to enhance your UIs with things like tooltips, pop-overs, menus, etc. You can learn about Bootstrap here: http://twitter.github.io/bootstrap/.

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)