Angular 7 Progress Indicator Component

I came across the following progress indicator for jquery and wanted to try to recreate it as an angular component.

<ol class="ProgressBar">
    <li #lis class="ProgressBar-step" *ngFor="let step of steps; let i = index">
      <svg class="ProgressBar-icon"><use attr.href="{{svgUrl}}"/></svg>

      <span class="ProgressBar-stepLabel">{{step}}</span>
    </li>
</ol>

The only modifications done to the HTML were adding a template variable #lis and iterating on the steps to be displayed.

xlink:href has been deprecated so it was replaced with attr.href and the svg was saved in a file and the path to the file is passed to the component. Styling is pretty much identical.

import { Component, OnInit } from '@angular/core';
import { ElementRef, QueryList, ViewChildren, Renderer2} from '@angular/core';
import { Input } from '@angular/core';

@Component({
  selector: 'app-progress-indicator',
  templateUrl: './progress-indicator.component.html',
  styleUrls: ['./progress-indicator.component.scss'],
})
export class ProgressIndicatorComponent {

  @Input() public steps: string[];
  @Input() public svgUrl:string;

  @ViewChildren('lis') lis: QueryList<ElementRef>;

  private elems: ElementRef<any>[];

  constructor(private renderer: Renderer2) {
  }

  advance() {
    this.elems = this.lis.toArray();
    var count = this.lis.filter(x => x.nativeElement.classList.contains('is-current')).length;
    if (count > 0) {
      let index = 0;
      for (let i = 0; i < this.elems.length; i++) {
        if (this.elems[i].nativeElement.classList.contains('is-current')) {
          index = i;
          break;
        }
      }
      if (index < this.elems.length) {
        if(index <  this.elems.length-1){ // if last one done remove current
             this.renderer.removeClass(this.elems[index].nativeElement, "is-current");
        }
        this.renderer.addClass(this.elems[index].nativeElement, "is-complete");
      } 
      if (index +1 < this.elems.length) {
        this.renderer.addClass(this.elems[++index].nativeElement, "is-current");
      }
    } else {
      this.renderer.addClass(this.lis.first.nativeElement, "is-current");
    }
  }

  previous(){
    this.elems = this.lis.toArray();
    var count = this.lis.filter(x => x.nativeElement.classList.contains('is-current')).length;
    if (count > 0) {
      let index = 0;
      for (let i = 0; i < this.elems.length; i++) {
        if (this.elems[i].nativeElement.classList.contains('is-current')) {
          index = i;
          break;
        }
      }
      if (index >= 0) {
         this.renderer.removeClass(this.elems[index].nativeElement, "is-current");
         this.renderer.removeClass(this.elems[index].nativeElement, "is-complete");
      }
      if(index > 0){
         this.renderer.addClass(this.elems[--index].nativeElement, "is-current");
        this.renderer.removeClass(this.elems[index].nativeElement, "is-complete")
      }
    }
  }
}

The component uses @ViewChildren to access the li tags and Renderer2 to do safe modifications to the classes of each element.

 <app-progress-indicator 
     [steps]='steps'  
     [svgUrl]='"./assets/svg/checkmark-bold.svg#checkmark-bold"'>
</app-progress-indicator>

Usage is as above steps should be an array of strings.

  public steps = ["Test","Review","Result","Mistakes"]; 

Note that QueryList is not accessible by index nor one could iterate on it for ES5 so toarray() was used to get things done. ES6 makes it possible to iterate directly.

JavaScript BreakOut

A couple of weeks ago I was playing around with canvas for the first time I decided to give a try in recreating a BreakOut like game using JavaScript.

The game is developed using Object Oriented approach for better structure and the code is easier to handle.

I found that using multiple canvas with some CSS to overlay them is a better approach to minimize computations and separate things.

Breakout
Breakout

 

 

It is unfinished let alone polished.

Can be viewed at JSFiddle: here

Things missing

  • Menu
  • Ball moving with paddle before start
  • Instructions of play ( Left/Right/Space )
  • Score Keeping
  • Game calculations could be better
  • Level transition although loading mechanism is in place and levels can be described in JSON format.

Might get back to it at some point, but right now I’m working on something else.

Basic AngularJS (1.3.13) SPA

Being on the saga to master AngularJS I decided to post about a basic application with a  module and controller that returns static data to the view. The view and controller are married by routing. This post will not go in detail on how things work.

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" data-ng-app="app">
<head>
    <meta charset="utf-8" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular-route.min.js"></script>
    <script src="app.module.js"></script>
    <script src="app.config.js"></script>
    <script src="posts.module.js"></script>
    <script src="postsController.js"></script>
<body>
    <div>
      <div data-ng-view></div>
    </div>
</body>
</html>

line 2 defines data-ng-app=”app” which is an attribute Every angular application should have  (could live in other elements)

Line 8-11 are the JavaScript inclusion for the application (in a real website one would minify and merge the files together for faster loading)

Line 14 is where the view will be loaded     <div data-ng-view></div>

AngularJS is modular in such a way that one could separate functionality but one or more modules can be injected into another module for richer functionality.

app.module.js

(function () {
    'use strict';
    
    angular.module("app", [
        'ngRoute',
        'app.posts'
    ]);
   
})();

The main module’s name should match the data-ng-app=”app” as above

ngRoute and app.posts are injected modules that the app module will make use of.

ngRoute is a standard module that takes care of routing

app.posts is a custom module that is built for this application

app.config,js

(function(){
  'use strict';
  
    angular.module("app").config(['$routeProvider',
      function ($routeProvider) {
        $routeProvider
            .when('/', {
		  controller: 'postsController',
		  controllerAs: 'vm',
                  templateUrl: 'posts.html'
            })
            .otherwise({
                redirectTo:"/"
            });
     }
    ]);
});

Every module may have a configuration and this is the first thing that will execute from that module for initialization.  In this case the main module has routing initialized.

$routeProvider is where routing is setup.

in a nut shell the above is configuring that when visiting root ‘/’ use controller postsController with vm alias and use posts.html as a view template else redirect to root.

posts.module.js

(function () {
    'use strict';

    angular.module('app.posts', []);
    
})();

This is just the definition of posts module which has no dependencies. As one may notice it is almost the same as app.module.js

postsController.js

(function () {
    'use strict';

  // Register
  angular
        .module('app.posts')
        .controller('postsController',postsController);
        
 // Inject
 postsController.$inject = [];        

  // Function
 function postsController() {
    var vm = this;
    vm.persons = [
                   {
                      "Name":"Alfreds Futterkiste",
                      "City":"Berlin",
                      "Country":"Germany"
                   },
                   {
                      "Name":"Berglunds snabbkkp",
                      "City":"Luleb",
                      "Country":"Sweden"
                   }
                 ];
  }

})();

Controllers can be written in different ways but the most elegant (opinionated) is Register/Inject/Function

Register the controller with a function name

Inject parameters

Function is the controller’s logic. The variable vm stands for ViewModel because that’s exactly what it represents. and Some JSON data is set to a property in that view model.

posts.html

<ol>
    <li data-ng-repeat="person in vm.persons">
      {{ person.Name + ', ' + person.Country }} <br/>
    </li>
</ol>

This is the view template that will be loaded instead of <div data-ng-view></div>

data-ng-repeat means repeat this element for as much items in the list

The vm here is the alias that was defined in the routing and has nothing to do with the controller vm variable ( but for logical sense it is the same )

{{}} mean execute the expression in between which in this case are the Name and Country

 

here is the code

Same example but using $http request here

Best Practices learned so far

Always encapsulate your code as a module to avoid polluting the global namespace

Always use ‘use strict’;

Use employ single responsibility principle

Separate every thing in files and make sure you organize files by feature if the application is large

Code neatly and use indentation

Love the community: When posting on the internet about code always include a version number

Experts worth following

John Papa

Tod Motto 

Resources

Very good introduction by Dan Wahlin : https://www.youtube.com/watch?v=i9MHigUZKEM

www.angular-tips.com

www.scotch.io

www.egghead.io

https://angularjs.org/

https://www.ng-book.com/

JavaScript Mine Sweeper

While trying to get a good grasp of JavaScript/CSS, I decided to implement Mine Sweeper.

I tried to use the standard colors for the numbering and standard icons for mines/flag/unknown.

 

I’ve identified the 5 states that any particular cell could be and designed a finite state machine for one cell

  • S is for initial state
  • B is for bomb
  • F is for flag
  • ? is for unknown
  • C is for clear

Finite State Machine for one Mine Sweeper cell
Finite State Machine for one cell

 

This is what the final product looks like

Mine Sweeper Screenshot
Mine Sweeper Screenshot

You may try it out at the link below

http://code.fairmutex.com/projects/web/minesweeper/
What I learned?
Discovered classList
Try to avoid recursion unless the recurring depth is shallow and the worst case scenario is known.

Good explanation about performance (may contain outdated information).
https://www.youtube.com/watch?v=mHtdZgou0qU