fbpx

The Line Has Been Drawn

Last week I was working in an Angular2 project. The feature called for us to draw a line on a canvas element.  The gotcha; the line had to fade out like a comet tail and we had maintain visibility of a background image.


Using this Tarik A’s free hand drawing implementation, to capture the points of the line, Greensock to animate the tail, and this bit of code.  We were able to achieve a nice fade out effect.
...

@Component({
  template: `
<div class="container" #container>
              <canvas #canvas></canvas>
              <svg #svg></svg>
            </div>

`
})

...

@ViewChild(‘svg') svg: ElementRef;
svgns = ‘http://www.w3.org/2000/svg';    

createLine(leader, follower) {
        const line = document.createElementNS(this.svgns, 'line');
        
        TweenMax.set(line, { stroke: `#FFFFFF`, strokeWidth: 3, alpha: 1 });
        line.setAttribute('x1', `${follower.x}`);
        line.setAttribute('y1', `${follower.y}`);
        line.setAttribute('x2', `${leader.x}`);
        line.setAttribute('y2', `${leader.y}`);

        this.svg.nativeElement.appendChild(line);        

        // fade out
        TweenMax.to(line, 0.5, { alpha: 0 });
    }

...

Testing time based activities in Angular

When testing time streams or promised based activities use ‘fakeAsync’ and ‘tick’.

For example, given a service:

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

@Injectable()
export class CountdownService {
  // counts down from given number to zero
  source(num: number): Observable<number> {
    return Observable.timer(1000, 1000)
    .map( (v) => num - v)
    .takeWhile( (v) => v !== -1);
  }
}

To test the CountDown class source method:

// … test setup above, inside describe function

it('should count down from 5 to 0', inject([CountdownService], fakeAsync( (service: CountdownService) => {
    let num: number = undefined;
    const count = service.source(5).subscribe( (value) => num = value);
    tick(7000)

    expect(num).toEqual(0);
})));

Wrap the ‘it’ callback function in fakeAsync() which creates a new zone for the asynchronous code to run.

Calling tick() with a time span in ms, simulates the code after that amount of time has passed.

Use tick() with no arguments for promise based code

My expectation is based on what happens after 7 seconds has passed.

Styling Select Elements with JCF

As an Apprentice Product Developer at TRIM, I’ve had the amazing opportunity of working and learning alongside an exceptional team of developers, designers, and strategists. I’m nearing the end of my apprenticeship, and wanted to share a TIL I encountered while working with Angular and TypeScript.

Having previous experience in Ruby, Rails, and JavaScript, working with Angular was different but also eye-opening. It is a lot of fun creating the functionality of a client app with components, modules, and services.

One of my biggest challenges was styling a select dropdown to match our designs. Thankfully the team ( Dom Miller!) created a JCF module that can be easily imported into an Angular project.

The JavaScript Custom Forms library (JCF) is a really great tool to customize form elements with CSS.  Once it’s imported to the project, you can place the jcf attribute in the desired element. Adding the attribute will style the element with the default jcf styles.

<select id=“dropdown-example” jcf>
    <option>Pick me</option>
    <option>No, Pick me!</option>
</select>

It is possible to include options with the jcf attribute for the select element. I’d like my dropdown to only show three options at a time. That would look something like this:

<select id=“dropdown-example”         
        jcf='{"maxVisibleItems": 3}'>
    <option>I’m option 1</option>
    <option>I’m option 2</option>
</select>

Now that the default styles and other options are set, we can add in our own styles by selecting and overriding the appropriate jcf classes. To do this, I created a file like this one within my assets folder:

project-name/src/assets/scss/base/_jcf_overrides.scss

.jcf-scrollbar-vertical {
 display: none;
}

.jcf-scrollbar-horizontal {
 display: none;
}

.jcf-list .jcf-option {
 font-size: 18px;
 font-weight: bold;
 background-color: $white;
 padding: 11px 20px;
 margin: 0px;
 text-align: left;
 border-top: 1px solid #ccc;
 cursor: pointer;
}

You can view the different jcf classes by opening your chrome dev tools on the page where the element is located, and looking near the bottom of the html. You’ll see the jcf classes created by the module.

There you have it! You now have a customized form element.

Angular 1.x Dropdown Menus
(Removing The Blank Option)

Over the past week I kept running into the issue of iterating over an array or an object in a <select> field with ng-repeat, only to find that I had a blank option as the first item in the dropdown.  After trying several strategies, I finally found one that worked.

Let’s say you want to iterate over the array ctrl.items in your <select> field.

some.component.js

(function() {
  'use strict';

  function SomeController() {

    var ctrl = this;

    // item array for dropdown
    ctrl.items = [
      {
        select: 'data1',
        label: 'Option 1'
      }, {
        select: 'data2',
        label: 'Option 2'
      }, {
        select: 'data3',
        label: 'Option 3'
      }
    ];

  }

  angular
    .module('app')
    .component('someComponent', {
      controller: SomeController,
      templateUrl: '/app/components/some.component.html',
    });
})();

Instead of using ng-repeat, this can be accomplished with ng-options.

ng-options Pattern Usage: select as label for value in array

some.component.html

<select name="selectName"
        ng-model="$ctrl.formName.selectName"
        ng-options="item.select as item.label for item in $ctrl.items">

  <!-- this option sets the dropdown placeholder -->
  <!-- value must be an empty string for this to work -->
  <option value="" selected="selected">Select an Item</option>
</select>

Where: select: value that will be submitted or bound to the model of the parent label: each <option> shown in dropdown list value: local variable for each array item or object property value being iterated over.

You can find more ng-options usage patterns in the AngularJS API Documentation