I am building my first AngularJS app and am struggling to figure out how to organize my code into services/factories and directives. My controller code keeps getting longer and longer and I know I must be doing something wrong.
Originally my app had three controllers: "BuildingTypeController", "AddressController", and "LayoutController". I used the ng-controller directive to attach each controller to each of my fieldsets. However I encountered problems when:
- I needed to pass one controller's data to another controller to be able to use in the $scope.$watch code.
- When I needed to pass one controller's data to another controller in my Get... $http.get methods (replaced with hardcoded values in my code below).
So then I went back and took all of my properties and functions and through them in one big "FormController". This gives me the functionality I'm looking for, however I know this can't possibly be the right way to organize all of this code.
If anyone could offer any advice on how to structure a long controller into smaller pieces I would greatly appreciate it. Thank you!
EDIT: The hardcoded datasets in this code were created to allow for the fiddle to work - they will be replaced with database calls and should not be factored into the "length" of the single controller.
var app = angular.module('formBuilder', []);
app.controller('FormController', ['$http', '$scope', function ($http, $scope) {
//This could really be thought of as "BuildingTypeController"
var form = this;
form.state = "";
form.states = [];
form.buildingType = "";
form.buildingTypes = [];
form.GetStates = function (buildingType) {
//This will be replaced with $http.get later
if (buildingType == null)
{
form.states = ["AZ","CT","NY"];
}
if (buildingType == "Single Story") {
form.states = ["AZ","CT"];
}
if (buildingType == "Mansion") {
form.states = ["CT"];
}
if (buildingType == "Apartment") {
form.states = ["CT","NY"];
}
if (buildingType == "Sky Scraper") {
form.states = ["NY"];
}
};
form.GetBuildingTypes = function (state) {
//This will be replaced with $http.get later
if (state == null)
{
form.buildingTypes = ["Single Story","Mansion","Apartment","Sky Scraper"];
}
if (state == "AZ") {
form.buildingTypes = ["Single Story"];
}
if (state == "CT") {
form.buildingTypes = ["Single Story", "Mansion","Apartment"];
}
if (state == "NY") {
form.buildingTypes = ["Sky Scraper", "Apartment"];
}
};
//initializations
form.GetStates();
form.GetBuildingTypes();
//This could really be thought of as "AddressController"
form.addressId = "";
form.addresses = [];
form.GetAddresses = function (form) {
//This will be replaced with $http.get later
if (form.state == "AZ" && form.buildingType == "Single Story") {
form.addresses = [{
addressId: 1,
description: "123 Grove Ave"
},{
addressId: 2,
description: "2352 High Court"
}];
}
if (form.state == "CT" && form.buildingType == "Single Story") {
form.addresses = [{
addressId: 3,
description: "1515 Lark Ave"
},{
addressId: 4,
description: "2 Front St"
}];
}
if (form.state == "CT" && form.buildingType == "Mansion") {
form.addresses = [{
addressId: 5,
description: "6 Waterfront Dr"
}]
}
if (form.state == "CT" && form.buildingType == "Apartment") {
form.addresses = [{
addressId: 6,
description: "13 Center St"
},{
addressId: 7,
description: "5985 Elizabeth Court "
}]
}
if (form.state == "NY" && form.buildingType == "Sky Scraper") {
form.addresses = [{
addressId: 8,
description: "13245 12th Ave"
},{
addressId: 9,
description: "345 Park Ave"
}]
}
if (form.state == "NY" && form.buildingType == "Apartment") {
form.addresses = [{
addressId: 10,
description: "6668 115th St"
},{
addressId: 11,
description: "2839 3rd Ave"
}]
}
};
form.performAction = function (expr) {
return function () {
if (expr == "GetAddresses") {
form.GetAddresses($scope.form);
}
if (expr == "GetLayouts") {
form.GetLayouts($scope.form);
}
};
};
$scope.$watch('form.state', form.performAction('GetAddresses'));
$scope.$watch('form.buildingType', form.performAction('GetAddresses'));
//This could really be thought of as "LayoutController"
form.layout = {};
form.layouts = [];
form.GetLayouts = function (form) {
if (form.addressId == 1)
form.layouts = ["A", "B", "C", "D"];
if (form.addressId == 2)
form.layouts = ["B", "C", "D"];
if (form.addressId == 3)
form.layouts = ["A", "D"];
if (form.addressId == 4)
form.layouts = ["A", "D"];
if (form.addressId == 5)
form.layouts = ["A"];
if (form.addressId == 6)
form.layouts = ["D"];
if (form.addressId == 7)
form.layouts = ["C", "D"];
if (form.addressId == 8)
form.layouts = ["A", "D"];
if (form.addressId == 9)
form.layouts = ["A", "B"];
if (form.addressId == 10)
form.layouts = ["B", "C", "D"];
if (form.addressId == 11)
form.layouts = ["C", "D"];
};
$scope.$watch('form.addressId', form.performAction('GetLayouts'));
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="formBuilder">
<form name="createForm" class="form-horizontal" ng-controller="FormController as form" novalidate>
<fieldset>
<legend>Building Type</legend>
<select class="form-control" ng-model="form.state" ng-options="state for state in form.states" ng-change="form.GetBuildingTypes(form.state)">
<option value="">Select a state</option>
</select>
<select class="form-control" ng-model="form.buildingType" ng-options="buildingType for buildingType in form.buildingTypes" ng-change="form.GetStates(form.buildingType)">
<option value="">Select a building type</option>
</select>
</fieldset>
<fieldset>
<legend>Specific Address</legend>
<select class="form-control" ng-model="form.addressId" ng-options="obj.addressId as obj.description for obj in form.addresses">
<option value="">Select an address</option>
</select>
</fieldset>
<fieldset>
<legend>Select Room</legend>
<select class="form-control" ng-model="form.layout" ng-options="layout for layout in form.layouts">
<option value="">Select a room</option>
</select>
</fieldset>
</form>
</div>