Monday, May 13, 2013

Making RequireJS and AngularJS Play Together

If you have to make AngularJS and RequireJS play together, here's how to do it.

1. Make Angular wait until you're ready.

  • Remove the ng-app from your HTML. This way, Angular won't run before Require has gathered dependencies.
  • In your main JavaScript file for Require, start Angular manually:
require([], function(){
  
  //... snip ...

  //start angular after dependencies are gathered
  //I'm using document here, but it should be whatever element 
  //you'd put the ng-app on normally
  angular.bootstrap(document, ["moduleWithControllers"]); 
});

2. Put your RequireJS stuff into an Angular module

  • This lets you stay Angular-y from inside Angular code!
  • This should also be in the main .js file for your Require stuff, before running bootstrap()
require(['someDependency'], function(someDependency){
  
  angular.module('requireStuff')
    .factory('someDependency', function(){
      //make this require object or whatever available to angular
      return someDependency;
    });

  //from section #1
  angular.bootstrap(document, ["moduleWithControllers"]); 
});

Then from the Angular code:
angular.module('moduleWithControllers', ['requireStuff'])
  .controller('MyCtrl', function($scope, someDependency){
    //do something with someDependency
  });

3. Get Angular libraries into your Require modules (Optional)

  • This lets you access libraries provided by Angular from outside of Angular code.
  • Warning: These won't be available until after Angular runs the first time, after all Require dependencies are gathered
define([], function(){
  var result = {
    $http: null,
    $q: null
  };

  angular.module('requireLibStuff')
    .service('randomService', function($q, $http){
      result.$http = $http;
      result.$q = $q;
    });

  return result;
});
Then you just need to reference the service from your angular code:
angular.module('main', ['requireLibStuff'])
  .controller('MyCtrl', function(randomService){
    //randomService won't be used, it's only referenced here 
    //to make Angular run the code above
  });

Update

I forgot to mention something for step #3 above: most Angular-provided libraries only work if called within Angular code. For example, the $q.defer() object will only notify its listeners if resolve/reject are called from within the regular Angular $apply and the like.

Wednesday, January 9, 2013

Check All Bookmarklet

Here's a bookmarklet for checking or un-checking all check boxes on a web page. It will flip the first check box, then set all the others accordingly.

check!

Here are a couple checkboxes, just to try it:
Here's the code, de-minified:
(function(){
 //all inputs on the page
 var cbs=document.getElementsByTagName('input'); 
 //the value for the checked (true of false)
 var cv;
 //the current checkbox
 var cb;
 
 for(var i in cbs){
  cb=cbs[i];
  if(cb.type=='checkbox'){
   if(cv==null)
    cv = !(cb.checked);
   
   cb.checked=cv;
  }
 }
 
 void(0); //prevent the bookmarklet from switching pages
})() //call the anonymous function


To get this bookmarklet, just drag it to your bookmarks toolbar or your bookmarks area. Click it whenever you want to use it.

Arduino - HSV to RGB

I got an Arduino for Christmas, along with a cool starter pack that contains all kinds of cool switches, LEDs, wires, etc. My favorite component to play with so far is the RGB LED. It has red, green, and blue LEDs inside of one unit, so you can use it to fake any color.

I started with making it just show random colors, but then thought I could do better. The code below chooses a random Saturation and Hue, then turns the brightness all the way up, all the way down, and then starts over again.

//these have to be attached to PWM pins
int REDPin = 6;
int GREENPin = 5;
int BLUEPin = 3;


int vIncrement = 5;

unsigned int h = 0, s = 0, v = 0; //hsv
unsigned int r, g, b, hh, c, x, m;


void setup()
{
  pinMode(REDPin, OUTPUT);
  pinMode(GREENPin, OUTPUT);
  pinMode(BLUEPin, OUTPUT);
  randomSeed(analogRead(0));
  Serial.begin(9600);
}

void loop()
{
  v = v + vIncrement;

  if (v <= 0){
    h = random(0, 360);
    hh = h / 60;
    s = random(0, 255);
  }
  
  if (v <= 0 || v >= 255)    // reverse the direction of the fading
  {
    if (v > 0x10000) //handle overflow - unsigned int
      v = 0;
    vIncrement = -vIncrement;
    v = constrain(v, 0, 255);
  }
  
  c = (v * s) / 256;
  x = (c * (60 - abs(h % 120 - 60))) / 60;
  m = v - c; // 44
  
  switch(hh){
    case 0:
      r = c + m;
      g = x + m;
      b = m;
      break;
    case 1:
      r = x + m;
      g = c + m;
      b = m;
      break;
    case 2:
      r = m;
      g = c + m;
      b = x + m;
      break;
    case 3:
      r = m;
      g = x + m;
      b = c + m;
      break;
    case 4:
      r = x + m;
      g = m;
      b = c + m;
      break;
    case 5:
      r = c + m;
      g = m;
      b = x + m;
      break;
    default:
      r=g=b=m;
  }
  
  
  r = constrain(r, 0, 255);
  g = constrain(g, 0, 255);
  b = constrain(b, 0, 255);
  analogWrite(REDPin, r);
  analogWrite(GREENPin, g);
  analogWrite(BLUEPin, b);

  delay(20);  // wait for 20 milliseconds to see the dimming effect
}

There are lots of algorithms out there for converting HSV to RGB, but I didn't like all the converting between float and int. This one does it only using unsigned ints (my Arduino uses 16-bit numbers, so I needed them unsigned to prevent overflow). It was based on the Wikipedia HSV page.

(For this algorithm, S, V, R, G, B are in [0, 255] and H is in [0, 360])