<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@*" data-semver="1.4.0-beta.4" src="https://code.angularjs.org/1.4.0-beta.4/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
    <script src="file.js"></script>
  </head>

  <body>
    
    <!-- html approach (does not capture input change event) -->
    <button>
      <label>
        Open file dialog (html)
        <input type="file" style="display: none" file-handler>
      </label>
    </button>
  
    <!-- directive approach -->
    <div ng-app="app" ng-controller="sample">
      <button type="button" class="btn btn-default" file-browser>
        Open file dialog (ng)
      </button>
    </div>
    
  </body>

</html>
angular.module('app', [
  'file'
])

.controller('sample', function ($scope) {
  
});
button {
  width: 200px;
  height: 50px;
  background-color: lightblue;
  color: white;
  border: none;
  margin: 5px;
  font-weight: bold;
}
Hide input
----------

*   HTML approach: http://stackoverflow.com/a/28075416/1815446
*   Hidden input: http://stackoverflow.com/a/8385882/1815446
*   Detached input: http://stackoverflow.com/a/24776295/1815446

Trigger click
-------------

*   http://stackoverflow.com/questions/24628410
*   http://stackoverflow.com/questions/2381572
angular.module('file', [])

.factory('readFile', function ($window, $q) {
    'use strict';

    var readFile = function (file) {
        var deferred = $q.defer(),  
            reader = new $window.FileReader();

        reader.onload = function (ev) {
            var content = ev.target.result;
            deferred.resolve(content);
        };

        reader.readAsText(file);
        return deferred.promise;
    };

    return readFile;
})

// does not capture input change event
.directive('fileHandler', function (readFile) {
    'use strict';

    return {
        link: function (scope, element) {
            element.on('change', function (event) {
                var file = event.target.files[0];
                readFile(file).then(function (content) {
                    console.log(content);
                });
            });
        }
    };
})

.directive('fileBrowser', function (readFile) {
    'use strict';

    return {
        template: '<input type="file" style="display: none;" />' +
            '<ng-transclude></ng-transclude>',
        transclude: true,
        link: function (scope, element) {
            var fileInput = element.children('input[file]');
            
            fileInput.on('change', function (event) {
                var file = event.target.files[0];
                readFile(file).then(function (content) {
                    console.log(content);
                });
            });
            
            element.on('click', function () {
                fileInput[0].click();
            });
        }
    };
});