Monday, April 7, 2014

Parsing Google Visualization data with PHP

A project of mine queried another service that returned the data to me as a "Google Visualization" data. This is a data table, and while native to many languages, PHP isn't one of them.

function parseGV($gv) {
 // Return array
 $data = array();
 // Buh-Bye extra BS.
 $gv = preg_replace('/google.visualization.Query.setResponse\(/', '', $gv);
 $gv = preg_replace('/\)\;/', '', $gv);
 // Get table Headings
 preg_match('/"cols":\[{(.*)}\],"rows"/', $gv, $tables);
 $columns = array();
 $cols = explode('},{', $tables[1]);
 foreach ($cols as $col) {
  $items = explode(",", $col);
  foreach ($items as $item) {
   $item = preg_replace('/\"/', '', $item);
   $arr = explode(':', $item);
   if ($arr[0] == 'id') {
    array_push($columns, $arr[1]);
   }
  }   
 }
 // Get the rows
 preg_match('/"rows":\[{"c":(.*)\]/', $gv, $r);
 if (count($r)) {
  preg_match_all('/\[{(.*?)}\]}/', $r[1], $rows);
  for ($i = 0; $i < count($rows[1]); $i++) {
   $pairs = explode('},{', $rows[1][$i]);
   for ($p = 0; $p < count($pairs); $p++) {
    $pair = preg_replace('/\"/', '', $pairs[$p]);
    $s = preg_replace('/v:/', '', $pair);
    $data[$i][$columns[$p]] = $s;
   }
  }
 }
 return $data;
}

You use it like so:

$companies = parseGV(file_get_contents("https://rvacore-test.appspot.com/d/company/".$my_co_id."/companies?auth=".$auth_token, false, $context));

And you get back an array like:

(
    [0] => Array
        (
            [id] => 77db8797-7c01-4b87-84a9-XXXXXXXXXXX
            [name] => My Sub-Company
            [street] => 1313 Mockingbird Ln.
            [unit] => 
            [city] => Chester
            [province] => VA
            [country] => 
            [postalCode] => 23836
            [address] => 1313 Mockingbird Ln., Chester, VA, 23836
            [timeZone] => (GMT  00:00) Dublin, Edinburgh, Lisbon, London
            [telephone] => 
            [fax] => 
            [parentId] => 7ba8917f-b1d2-42f1-96fe-XXXXXXXXXXXXXXX
            [networkOperatorStatus] => 0.0
            [networkOperatorStatusChangeDate] => new Date(2014,1,7,20,52,55)
            [companyStatus] => 1.0
            [companyStatusChangeDate] => new Date(2014,1,7,20,52,55)
            [notificationEmails] => 
            [changeDate] => new Date(2014,1,7,20,52,57)
            [changedBy] => System
        )
    [1] => Array
        (
            [id] => 11a9e443-a1b9-45b8-bee2-XXXXXXXXXXXX
            [name] => Another Sub-Company
         ...
        )
    [2] => Array
        (
         ...
        )
    [3] => Array
        (
         ...
        )
)

Didn't see this elsewhere on the web, so here it is.

Wednesday, November 6, 2013

Angular: Disable the back button/Warn before leaving App

Been a while, I've been busy rolling out our latest project and work has to come first.

I have a single page app in Angular that has 14 different tabs. (3 main tab groups and then subgroups under them. I'm not insane.) While doing user testing,  I noticed that one of our users was under the distinct impression that hitting the "back" button would take him to the previous tab. He did this repeatedly, losing his input each and every time.

At some point we will add some routing to handle these cases. However, that's a good amount to put into this program and we are in "live beta" right now.

A simple solution:

window.onbeforeunload = function (e) {

  return 'You are reloading or leaving this App. Any unsaved data will be lost.';

};


Tuesday, September 17, 2013

Show/Hide div directives.

Here's a fun one...

We all have need for show/hide divs every now and again, right? Why not let Angular do the heavy lifting?

If you haven't played with directives yet, you should start learning. They're powerful!



Here's the fiddle. This directive looks for and divs with a 'class="showhide"' and then makes them collapsible divs. (Click on "result" above to see how they work.)

Within each "showhide" div, we create a"less" div, a "more" div, and a "show" div. Less is the text that will show when the div is collapsed, More shows when it's open, and the Show div has the link to turn them on and off.

I think that the code is pretty self-explanatory, but if you have any questions, hit us up in the comments.

Thursday, September 12, 2013

Custom Angular Filters

The current filter docs are a bit confusing. Let's break down how simple it is to add an Angular filter!

The currency filter does not allow you to choose how many decimals are involved. So let's create a custom filter that does currency in whole dollars.

var app = angular.module('app', ['dollarFilter']);
angular.module('dollarFilter', []).filter('dollars', function() {
 return function(value) {return "$" + addCommas(Math.round(value));}
});

You can now call this filter like so:

{{total | dollars}}

So, let's breakdown the code so we know exactly what we need to do.

We are creating an angular module.

angular.module('dollarFilter', []


We name the module 'dollarFilter'. The array brackets would be where you would list any dependent modules. So let's look at the controller init:

var app = angular.module('app', ['dollarFilter']);

dollarFilter is now a required module for our controller and will be loaded on start up.

Note that dollarFilter is the name of the module itself, NOT the name of our filter! This name is only used for the injector. Modules can contain multiple filters, coding, etc...

.filter('dollars', function() {

Here is where we actually name our filter. In this case, "dollars". That is the name we use when we want to call the filter.

Now we write the function. In the case of a filter, it will take one argument representing the value passed to our filter.

return function(value) {return "$" + addCommas(Math.round(value));}

I've set up a basic Fiddle for you to play with and see how the code works. (You can also get the "addCommas" function from here.)

What if we want to add multiple filters to one module?

Declare our filter, and store the object in a variable.
var df = angular.module('dollarFilter', []);

Add filters to the object:
df.filter('dollars', function() {
    return function(value) {return "$" + addCommas(Math.round(value));}
});
df.filter('percentage', function () {
    return function(value) {return value * 100 + "%";}
});

And here's another fiddle for you to see how it comes together.


Hope this helps. If there's a question we didn't answer, let me know in the comments.

Wednesday, September 11, 2013

Passing your PHP variables to Angular

New to angular from other JS frameworks and can't figure out how to pass PHP variables to Angular? I hit this when I first started, and Google was of no help.

In General, you want to use AJAX calls to get values from your database to your angular app. But what about user authentication?

<?php
session_start();
if (empty($_SESSION['uname'])){
    header("location:auth/login.php");
}
?>


That's a pretty common piece of code. So, how do you pass the username to your Angular app?

Use ng-init when you set up your controller in the HTML. Use PHP to echo variables to the page.

<div class="container-fluid" ng-controller="appCtrl" 
ng-init="userInit('<?php echo $_SESSION['uname']."', '".$_SESSION['role'] ?>')" >

Now, create a userInit function in your angular controller that will handle the variables:

$scope.userInit = function(uid, role) {
 $scope.user = uid;
 $scope.role = role;
 // Get a list of projects for user
 $scope.projectList($scope.user);
}

And it's that simple!