Skip to content

ryan-haskell/docker-angular

Repository files navigation

Docker | AngularJS

An isolated AngularJS frontend container that offers an intuitive folder structure and a guided developer workflow.

Local Development

  1. Install Docker.
  2. Run docker-compose up.
  3. That's it.

Windows: Go to http://192.168.99.100:8000 to get started.

Linux/Mac: Go to http://localhost:8000 to get started.

Project Architecture

This frontend project was designed to help guide developers in the right direction when making decisions for their website or application.


Introduction

As a frontend developer, the app folder should serve as your root directory. Any changes you make will "magically" bundle into the correct folder behind the scenes in your docker container. If there is ever a syntactical error in this process, it will be clearly displayed in the terminal running your docker-compose up command.

The entrypoint of this application is index.html. It is a simple template that does the following things:

  • Imports style.css (bundled .scss files)
  • Imports angular.min.js (minified AngularJS framework)
  • Imports bundle.js (bundled JS files)
  • Renders content within <div ng-view></div> (where your page will render)

The entrypoint for the AngularJS application is index.js. This file is in charge of loading the router, as well as other dependencies your application may have. It is also the entrypoint for our JS bundler.

The application routes are defined in the routes.js file. All this file does is render the appropriate component into the ng-view div, as mentioned before. We'll discuss components in a bit.

The index.scss file serves as the entrypoint for our styles. Sass allows us to modularize our styles, similar to how AngularJS will enable us to modularize our logic. It will be the entrypoint for our SASS bundler.

Our application will primarily be composed of components (views for the user) and services (view-independent logic).

Whether creating a component or a service, you will be creating an isolated, testable module. This means that all of the code relevant to that module will be neatly stored in a designated folder.


Folder Structure

  • index.html (main entrypoint)
  • index.js (js entrypoint)
  • routes.js (route configuration)
  • index.scss (css entrypoint)
  • shared/ (modules shared across pages)
    • example-cmpt/ (shared component)
      • index.js (creates module, requires dependencies)
      • tpl.html (content to display)
      • ctrl.js (exposes and maintains view model)
      • style.scss (specifies component-specific styles)
      • spec.js (tests all public interfaces of component)
    • example-service/ (shared service)
      • index.js (creates module, requires dependencies)
      • srvc.js (exposes and maintains data model)
      • spec.js (tests all public interfaces of service)
  • pages/ (pages in the application)
    • index.js (creates pages module, requiring page folders)
    • welcome-page-cmpt/ (example page)
      • (matches example-component structure)
      • page-specific-cmpt/ (some component only used in welcome-page)
        • (matches example-component structure)
    • .../ (other pages)

Example Component

index.js

angular.module(module.exports = 'exampleCmpt', [])
    .component(module.exports, {
        template: require('./tpl.html'),
        controller: require('./ctrl')
    });

tpl.html

<!-- Example Component -->
<h1 class="example-header" ng-bind="$ctrl.name"></h1>
<input type="text" class="example-input" ng-model="$ctrl.name">

ctrl.js

module.exports = [function(){

    // All properties of '$ctrl' are exposed to template
    var $ctrl = this;

    // Available in template
    $ctrl.name = 'Jack';

    // Private to controller
    var hiddenName = 'Jill';

}];

style.scss

example-cmpt {

    .example-header {
      font-family: Arial;
    }

    .example-input {
      /* Style your input */
    }

}

spec.js

describe('exampleCmpt', function() {

    var ctrl;

    beforeEach(function(){

        // Load module
        angular.mock.module(require('.'));

        // Initialize component
        inject(function($componentController) {
            ctrl = $componentController('exampleCmpt', {});
        });

    });

    it('has initial name set to John', function(){

        expect(ctrl.name).toEqual('John');

    });

});

Example Service

index.js

angular.module(module.exports = 'ExampleSrvc', [])
    .service( module.exports, require('./srvc') );

srvc.js

module.exports = [function(){

  var srvc = this;

  srvc.data = {
    person: {
      name: 'Jack',
      age: 21,
    }
  };

}];

spec.js

describe('ExampleSrvc', function() {

    var ExampleSrvc;

    beforeEach(function(){

        angular.mock.module(require('.'));

        inject(function(_ExampleSrvc_) {
            ExampleSrvc = _ExampleSrvc_;
        });

    });

    it('has right name',function(){

        expect(ExampleSrvc.data.person.name).toEqual('Jack');

    });

});

Unit Testing

You may have noticed that the spec.js files require you to write tests for all public interfaces. For component controllers, this means that if a function is not private to the controller, it needs to be tested to define and validate the purpose of that function. The same rule applies to services.

This rewards privatizing functions that aren't necessary to expose. Unit tests also help keep modules lightweight and focused.

About

An isolated AngularJS frontend container.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published