2/28/17

Building Stretching to the bottom Layout With Flex-Box

Layout

Everybody knows that to build the layout is complicate thing, especially when we talking about layout which should stretch to page bottom. In other words - with footer sticking to page bottom.

I'm sure there is a lot of ways around how to build this layout, but in this article i will try to show how to build it using flex-box CSS3 feature

Dividing to sections

First lets decide to how to divide our layouts to sections:
I decided that two main sections will be displayed one besides other like to columns - nav and main elements
Inside main element will be 3 other sections positioned one above the other:header,article and footer


    <div class="wrap">
      <nav>
        <ul>
          <li><a href>1 link</a></li>
          <li><a href>2 link</a></li>
          <li><a href>3 link</a></li>
        </ul>
      </nav>
      <main>
         <header>Hello Plunker!</header>
         <article>
           HellHePlunkllo Plunker! Plunk
           Hello Plunker!Hello P Plunk
           lunker Plunk!o PHello Plunker Plunk
           !lunker! Hello Plunker! Plunk
         </article>
         <footer>footer</footer>
      </main>
    </div>

VH Trick

One css feature i found very useful is VH unit. This vh represents percents of view height (e.g. browser window height) ,and thus given some element height set to 100vh makes it to stretch over the whole window from its top to its bottom


.wrap{/* root container */
  height:100vh;
  background:green;
  display:flex;
}

Nav & Main sections flow

Since we want those sections to be stick one near other (like two cells in the row) all we have to do is set the display property of their container to flex
By default flex-direction property is "row"
Since nav section has fixed width of 234px - all that left to do is to make the main section to catch all the remaining space:


nav{
  width:234px;
  background:orange;
}
main{
  flex:1   100%;/*will make it stretch over remaining space*/
}

Header Article and Footer

First thing is to set flow of main container to be column


main{
  display:flex;
  flex:1   100%;
  flex-direction:column;
}

Now the only thing left is to arrange the header above the article and make article to catch all available space between header and footer.

article{
  flex:1   100%;
  background:red;
}

See this plunker for running code

2/22/17

Building Drop Down Menu Using Angular1 Component

Challenge

To build drop down menu like angular-ui-bootstrap with angularjs using "component":

Behaviors

  1. Menu toggle button Should open hidden menu when clicked, and to hide the menu if it open
  2. Menu Should Close itself when users clicks on some other place
  3. If disabled - should not show anything when clicked

Step 1 - CSS & HTML

For sake of simplicity i will copied styles from bootstrap framework:


.open > .dropdown-menu {
    display: block;
}
.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    display: none;
    float: left;
    min-width: 160px;
    padding: 5px 0;
    margin: 2px 0 0;
    font-size: 14px;
    text-align: left;
    list-style: none;
    background-color: #fff;
    -webkit-background-clip: padding-box;
    background-clip: padding-box;
    border: 1px solid #ccc;
    border: 1px solid rgba(0, 0, 0, .15);
    border-radius: 4px;
    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
    box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
}

and the html will be following:

    <dropdown>
        <dropdown-toggle>
        <a href="">Dropdown <span class="caret"></span>
        </a>
        </dropdown-toggle>
        <dropdown-menu>
        <li>
            <a href="" ng-click="$ctrl.sayHi()">Action</a>
        </li>
        <li>
            <a href="">Another action</a>
        </li>
        <li>
            <a href="">Something else here</a>
        </li>
        <li role="separator" class="divider"></li>
        <li>
            <a href="">Separated link</a>
        </li>
        </dropdown-menu>
    </dropdown>

inside 'dropdown-toggle' container user should be able to place html of 'a' tag or button (according to his needs)
inside 'dropdown-menu' container user should be able to place html of menu items - there he should be able to attach methods from controller - like sayHi

dividing to components

I decided to divide this component to three different components:
The dropdown Parent component and dropdownToggle and dropdownMenu child components
That way logic will be splitted to its specific component

dropdown component

Should contain close and open methods


angular.module('drop',[])
.component('dropdown',{ 
  controller:function($element,$document) {
    $element.addClass('dropdown');//
    this.close=() => {
      $element.removeClass('open');
      this.isOpen = false;
    }
    this.open=() => {
      $element.addClass('open');
      this.isOpen = true;
    }    
  }
})

The mechanic here is that menu is visible when the main container (dropdown element) have "dropdown" and "open" classes, that why close and open are adding and removing 'open' classes accordingly

dropdownToggle component

Is the element that must handle the clicks and activate its parent 'open' and 'close' methods;
For be able to access its parent methods i'm using require option inside component definition:


.component('dropdownToggle',{
  require: {//<--USING REQUIRE OPTION
    parent: '^^dropdown' 
  },
  controller:function($element) {
    $element.addClass('dropdown-toggle');
    
    $element.on('click',($event)=>{
       this.parent.isOpen ? this.parent.close() : this.parent.open();
    })     
  }
})

click outside behavior

For be able to close the menu when user clicks somewhere else on the screen i'm taking advantage of $document service:
dropdown.js



 ...
  $document.on('click',(evt)=>{
    if(!$element.find('dropdown-toggle')[0].contains(evt.target)){
      this.close() 
    }
  })
...

You can see running code on this punker

2/9/17

Lazy loading - Is it possible in Angular1

What Is Lazy Loading?

Single page application, as you can see from its name - is built with one single page. In this single page javascript loads (when needed) various views. Each view may have its won modules, components, and other javascript logic inside them. Since it may happen that site user will not access some views at all - it is good practice to avoid load then every time the app accessed, istead - the ideal tactic is to load those javascript parts only when this specific view was called. But is there some way to do it in angular1?

The Answer is Yes

Actually there is a way to implement lazy loading with angularjs, for example by using ocLazyLoad angular module. You can read here how to load entire module or only some directive or service or how to load some state from a script!

Experiment

As usual lets show how to use lazy loading on some of our old good projects - the angular phonecat.
Lets start with download or clone the project to some local directory.

git clone https://github.com/angular/angular-phonecat.git


After installing dependencies (npm i) lets register the ocLazyLoad module to bower.json:

bower i oclazyload -D

After install and place reference on index.html file, we must register lazy load module in root application module:


'use strict';

// Define the `phonecatApp` module
angular.module('phonecatApp', [
  'ngAnimate',
  'ngRoute',
  'core',
  'phoneDetail',
  'phoneList',
  'oc.lazyLoad'
]);

Create About Page

For testing lazy load feature lets create "about" module which will contain "component","config","module" and "template" files

we will rester only "config" and "module" references on the index.html
Lets add about module to our root "phonecatApp" module:

angular.module('phonecatApp', [
  'ngAnimate',
  'ngRoute',
  'core',
  'phoneDetail',
  'phoneList',
  'oc.lazyLoad',
  'about' 
]);

We didn't put the reference to about.component fie on the index.html on the purpose.
The "component" file will load with lazy load module after user will access "about" route.


angular.module('about').
    config(['$locationProvider', '$routeProvider',
        function config($locationProvider, $routeProvider) {
            $routeProvider.
                when('/about', {
                    template: '<about-comp></about-comp>',
                    resolve: ['$ocLazyLoad', function ($ocLazyLoad) {
                        return $ocLazyLoad.load([{
                            files: ['about/about.component.js']
                        }])
                    }]
                });
        }
    ]);

Lets try to navigate to /about url
Wow! Now you can see the about component is loaded!
Thanks for reading

2/2/17

Using Angular2 Components Inside Angular1 Project

Dreaming About Upgrade

If you working on project that built with angular1 for historical reasons and dreaming about move to angular2 - this article is for you.
Yes, it is possible to move to angular2 make little changes step by step, without breaking the running code of your application. In this article i will take this angular-seed repo and try to make it run with some angular2 component included.

Step 1 - Bootstrap Angular Different Way

Usually the angular is attached to HTML using ng-app directive but there is another way to bootstrap angular to your application - using angular.bootstrap utility:


angular.bootstrap(document.body, ['myApp'], {strictDi: true});

You can view source at this branch

Step 2 - Migrating to Typescript

To move project to typescript you need :
1. rename all the files to end with ts instead of js (meanwhile leave files finishing with 'test' and not rename them to ts)
2. install typescript compiler:

npm i typescript -D
3.create tsconfig.json file at root directory

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "suppressImplicitAnyIndexErrors": true
  }
}

4. install type definitions for angular and other dependencies
npm install @types/angular -D
If all the installations succeed - after running
tsc -p .
command all ts files should have their ".js" and "map.js" copies - appear near them.


You can view source at this branch

Step 3 - Move application to load dependencies from node modules

Why? Mostly from reason that angular2 recommend to load dependencies this way instead of using bower. So, since node_modules directory located at project root we need to modify index.html so all the urls will stay correct:
Insert base tag inside head tag of your index.html


<base href="/app/">

Also you will need to change "start" script inside package.json:

"start": "http-server -a localhost -p 8000 -c-1 ./",

Now you can install all the dependencies like angular through NPM:

    "angular": "^1.6.1",
    "angular-route":"^1.6.1",

Don't forget to change the paths inside the index.html:

  <script src="/node_modules/angular/angular.js"></script>
  <script src="/node_modules/angular-route/angular-route.js"></script>

Now make sure that after you run
tsc -p ./
and then:
npm start
command you can see the project running:

You can view the full code on this branch

Step 4 - Install Systemjs Module Loader

Module Loader - a way to make javascript to import or export different javascript types (like classes) from one file to other. There are several javascript module loaders such as Webpack, Browserify, Systemjs - for our tutorial we will use systemjs.

npm install systemjs -D
After installation lets try to include the systems script to "index" page:

  <script src="/node_modules/systemjs/dist/system.src.js"></script>

Important: systemsjs uses its own configuration file - systems.config You may place it in the "app" directory:


/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': '/node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: '/app',

      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',      
      '@angular/upgrade/static':'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      }
    }
  });
})(this);

This files points to system module loader where the scripts located. Lets see if it loaded now in the chrome developer tools:
After we can see everything is still working lets add angular2 dependencies to package.json:

    "@angular/common": "~2.4.0",
    "@angular/compiler": "~2.4.0",
    "@angular/core": "~2.4.0",
    "@angular/forms": "~2.4.0",
    "@angular/http": "~2.4.0",
    "@angular/platform-browser": "~2.4.0",
    "@angular/platform-browser-dynamic": "~2.4.0",
    "@angular/router": "~3.4.0",

    "angular-in-memory-web-api": "~0.2.4",
    "systemjs": "^0.20.4",
    "core-js": "^2.4.1",
    "rxjs": "5.0.1",
    "zone.js": "^0.7.4"
You also must point to systems that you main module is inside "app" directory:
index.html

    <script src="systemjs.config.js"></script>
    <script>
      System.import('/app').catch(function(err){ console.error(err); });
    </script>

Important: you must remove main.js reference from index.html
And run again:npm install and after :tsc -p .

If everything is OK you should refresh and see the app running as usual.

Little Experiment

Now lets try to import some file into main.ts file using import command:
main.ts


import './app'
declare var angular: ng.IAngularStatic;//must not override global angular
angular.bootstrap(document.body, ['myApp'], { strictDi: true });

Now you can remove app.js reference from index.html and see that app still running (since the code imported by systemjs!)

You can view full code on this branch

Step 05 - Install Angular Upgrade

Now we about to enter cherry-in-the-cake zone of this article - start using angular2 and angular1 in the same project

 npm i @angular/upgrade -D
This angular2 module makes you to be able to include angular2 modules into your angular1 project.
Lets add angular2 module named AppModule
app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static'
@NgModule({
  imports: [
    BrowserModule,
    UpgradeModule,
  ],
})
export class AppModule {
  ngDoBootstrap() {}
}

Now the only thing left is to inject your old myApp module angular2 way:
main.ts

/*angular.bootstrap(document.body, ['myApp'], {strictDi: true});*/
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
  upgrade.bootstrap(document.body, ['myApp']);
});

Voula! you running angular2 and angular1 together now!
You can view source code on this branch

Thanks for reading

Getting started with docker

It is very simple to get started usig docker. All you need to do-is download the docker desktop for your system Once you get docker syste...