How can I have one file per controller?


#1

Trying something like this to get to work…

Hi, I am trying Ionic and loving the way it works. I am building my first ionic mobile app and trying to keep things neat and tidy. In my AngularJS projects, I use to have a controllers folder where all my controllers live (one controller per file), then in each file I would do something like this:

angular.module(‘starter’, [])

.controller('PetIndexController', function($scope, PetService)
{
    $scope.pets = PetService.all();
})

and the dependencies in the module declaration within app.js would look something like,

angular.module(‘starter’, [‘ionic’,])

.config ( etc…

As you can see, in this example I am attaching a controller to the main app module and it works when writing an angular app, for some reason this is not the case in my Ionic project, as it seems to need a new module for each file defining a controller (think the same happens for services, factories and so on). I know the sample project uses a single file for all controllers and a single services.js file for all factories, each one becoming a separate module, but I would really like to have my controllers and services as part of the main module and defined in different files each one, and correctly classified within controllers and services folders, thus, leaving the module without dependencies other than ionic itself. In this way I can add modules that provide new functionality to the app when needed in a more semantic way.

The way it is now looks a little convoluted to me, since if, for example, I have, let’s say 20 controllers with an average of 50 lines each one, the controllers file would grow in a way that it would become some more difficult to maintain. On the other hand, removing the extra modules from the dependencies in the main module (app.js), would look cleaner, after all, if the controllers are for the main module, they probably should be part of the module itself, same for services and factories…

Probably I am getting something wrong, or because I am coming from the desktop RIAs world, I am seeing this from a wrong standpoint. I have tried to move the controllers into different files for hours now and every single try has resulted in getting a blank page (error). Is there any dependency in the Ionic framework to a component that enforces certain file structure in the project AngularJS files?

I appreciate your comments on this matter, also if you know of any good piece of documentation where I can read more on the subject, that would be awesome.


Separating out the controllers into different js files
#2
//file module.js
var starter = angular.module('starter', ['ionic']);

//file controller/some.js
starter.controller('someController',function(){});

//file controller/another.js
starter.controller('anotherController',function(){});

Make sure you include the module.js file before any of its children.


#3

Take a look at this:

http://calendee.com/angularjs-code-organization/

@jasonfutch has a good example. But if you do that, you end up with problems later. Using a variable name, like that, you can’t inject your services into the app config later on.


#4

Thanks for the info… haven’t ran into that yet.


#5

Jason, this is awesome, it works great, thanks!

Justin, Thanks for the info. I am taking a look at the article now. There should be an approach that make easy to break logic in different discrete files when the app complexity grows and that doesn’t hurt dependency injection or testability later on. For the moment using a var works great. Is there any way to get the best of both options?


#6

The link suggest to do it this way.

//file module.js
angular.module('starter', ['ionic']);

//file controller/some.js
angular.module('starter').controller('someController',function(){});

//file controller/another.js
angular.module('starter').controller('anotherController',function(){});

Maybe a combination of both

//file module.js
angular.module('starter', ['ionic']);
var starter = angular.module('starter');

//file controller/some.js
starter.controller('someController',function(){});

//file controller/another.js
starter.controller('anotherController',function(){});

#7

Actually it seems like declaring the array of dependencies as the second parameter of the module constructor should only be done the first time or the module will be recreated, overwriting the previous instance. Most likely the angular.module method are actually two, a constructor and a getter, and angular calls the right one depending on the received parameters.

Using modules (submodules?) for inherent members of a module (controllers, factories) doesn’t look very clean, but because of the order in which these moving parts are loading, seems to be the best way to proceed in order to have a clean and dependable environment in the app. Probably a solution would be calling these modules (which I think are a necessary evil) as “submodules”, as recommended in the ionic example (app.controllers, app.services, etc).

At least being capable or dividing the code in different files is good enough for a practical purpose, then using grunt to put all together will work just great. The semantics (IMO) are not perfect for my particular case, because I’d like being able to only reference modules with extra functionality and external to the project logic (ng-sanitize, ng-cookies, etc) from the module constructor, however this approach may be good enough, which is great.


#8

Fantastic Article and a must read for any Angular dev.
Will definitely use these tips when designing my apps from now on.


#9

Have you taken a look at organising your application by feature? This is how I organise my application…

Each feature is a self contained angular module.

Take the “myapp.login” feature for example:

angular.module('myapp.login', ['myapp.login.svc'])
.config(function($stateProvider) { ...login only states...})
.controller(function($scope, $state, loginSvc) { ...login only functionality... });

it is a module with controller and config methods. Only this feature’s states are defined in this feature’s config method. The myapp.logic.svc feature is also a module that myapp.login requires.

It makes it sooooo much easier to break down your app and work on discrete pieces of functionality. It also makes it easier to plug in features as and when, or take them out. Separation of concerns is clearly at play!

My app.js file now is the top-level module that “requires” which ever feature it needs.

Hope that A) makes sense, and B) is helpful!


Folder Structure to Also Include Server-Side JS
Image missing
#10

Looks great, actually this is exactly what I have been trying to do. For those who do php, this is a little bit like what you get using a solid MVC framework like ZF2 or Symfony. Clear semantics, clear separation of concerns and good modularity. Thanks for the advice. Is there any more info on this pattern?


#11

Example of how to structure an AngularJS app…


#12

Could you include a bit more example code? Specifically the angular.module definitions in your app.js, some states in your app.js, and the app.js-like-file for your login module, as well as some states from your login module?


#13

Nevermind - I finally figured out what the problem was.

The best guide for this is here

Make sure that you explicitly include the additional app.js-like files for each module in your index file, as well as doing the rest of the modular design.

<script src="app/app.js"></script>
<script src="app/storage/storage.js"></script>

#14

If you take a look at this https://github.com/GrumpyWizards/Absorbed/tree/master/src - even though its still heavily in development - you’ll hopefully see the blog.app.js file, thats the starting position.

Then each features is a module.

Inside this features ( https://github.com/GrumpyWizards/Absorbed/tree/master/src/features/auth/post ) there is one module, two controllers, a service and one reused template.

Organisation, reuse and robustness through redundancy are benefits of the module approach.


#15

Sorry - i mis-posted a reply as a new topic.

Just wondering if you could reinstate the image; it doesn’t appear as part of the post, and when attempting to view it, a 404 error appears. Curious to see how you structure your app as i too am having similar issues. Thanks!


#16

Are you talking about this image?


#17

This link also gives a 404 Not Found.


#18

Here, this should illustrate how it works: https://github.com/GrumpyWizards/ngSeed


#19

Good tips here. Is it safe to assume that Ionic isn’t opinionated about file structure within the www folder? I’m currently using the default Ionic recipe file/folder structure, but I’d like to break out of it into something more modular/component based.


#20

Ionic imposes no restrictions on the structure of your code at all. As long as you index.html includes your files properly, you are good to go.