In my foray into AngularJS, I've been a little confused. The main reason for this, is because I never really quite understood, what the model part of the whole thing was. I mean, its a MVC framework, so it had to have models, correct? So, I did a little bit of reading on the matter. I tried reading this bit of documentation, here.
What I understood from that was, that the model aspect of the controller, what in fact what was inside the $scope dictionary. Fine, and this did not bother me, until I read a blog post by evil-trout, one of the makers of discourse.
What he was trying to get by, was that Angular did not have a proper modelling scheme. I tried looking into SO for answers, and I bumped into this. This was a good read, but really did not give me concrete examples of how to structure models in AngularJS.
I've felt that this was indeed lacking since, I'm used to django development, and having clear models is helpful. In emberjs, there seems to be a way to make models, that inherit from an Ember class. Also, after reading evil-trout's blog post, I understand the potential pitfalls of having all variables attached to the scope, and many of them being primitives, and not objects.
So, what is the best way to structure a model in AngularJS, such that you can have maintainable code in the future. The main reason I stick with angular is because it is wonderfully simple to write, but I fear that it might end up being something like php, where functionality has often been supplanted for the sake of simplicity.
I hope I've been able to make my question clear, if not then please feel free to leave a comment, telling me how I can improve.
Things to remember about models
They represent a chunk of data...
That chunk can come from an API, a static file, be explicitly declared.
It can be updated by events in your app.
They can be many or one...
A model does not have to be an all encompassing object. If you see potential for abstracting smaller models from a single model, you have discovered modular code. Injecting child services into your parent ensures a separation of concerns and re-usability.
A good example here is think about a service that consumes two API's to build a single model. You could certainly build it like this:
angular.module('things', [])
.factory('Things', function($http) {
var _things = {};
_things.getThing1 = function(){return $http.get('http://ONE.com/1')};
_things.getThing2 = function(){return $http.get('http://TWO.com/2')};
return _things;
};
But what if you want to use those API calls in another project? Are the components that make up my single service really best represented as their own services?
angular.module('thing1', [])
.factory('T1', function($http) {
var _thing1 = {};
_thing1.getThing1 = function(){return $http.get('http://ONE.com/1')};
return _thing1;
};
angular.module('thing2', [])
.factory('T2', function($http) {
var _thing2 = {};
_thing2.getThing2 = function(){return $http.get('http://TWO.com/2')};
return _thing2;
};
angular.module('things', ['thing1','thing2'])
.factory('Things', function(T1,T2) {
var _things = {};
_things.getThing1 = T1.getThing1();
_things.getThing2 = T2.getThing2();
return _things;
};
Now you can use thing1 or thing2 independent of things. Which is great news, because the next project you are working on doesn't need thing1 but definitely needs thing2. If nothing else, modular services (or any code in general) will give you structure to your app that will help you identify things as components rather than blobs.
We have been using Angular for some time now and we have come up with a convention that helps us in keeping scope pollution under control.
We define at max 2 properties on the the $scope variable in every controller. viewModel and model. The viewModel being a object which helps us in achieving easy model binding and the model object which is the data pertaining to the view for CRUD operations.
We follow this convention across main view (ng-view),sub-view (view created with ng-include), directives (if we create isolated scope).
Shameless plug: I wrote a blog post detailing this just few days back :)
Related
For a project I am working on, one of the things I've written is an instantiable service for an Angular UI Bootstrap Calendar control.
You can see the plunker for it in action here.
The code question I have is more of an architectural and best-practices question. Specifically, I think I've written an Angular anti-pattern.
Services - like the calendarSvc - are singletons, yet I am explicitly circumventing this by making the factory return a constructor function.
That being said, there is a concrete business need for 1-n calendars to exist on a single page. This code is an effective refactor of the code needed to manage a single calendar, so it definitely helps the code to be more DRY.
Question: What are some effective alternatives to this instantiable service that still let me specify instances of reusable Calendar objects as needed, but are done without circumventing the Angular way of managing the code?
What you did is not a antipattern, but indeed best practice!
See this style guide page for example: http://github.com/mgechev/angularjs-style-guide#services.
You did not circumvent the Angular way. The idea of the factory is the possibility to return constructor functions. The other alternative to creating services is the service-method of module which would automatically instantiate your service with the new keyword.
Take also a look at this other StackOverflow answer as reference: https://stackoverflow.com/a/20110304/669561
I have this situation now where I’ve implement models as a plain JavaScript object. So you can synchronously ask the model for a value and you can subscribe to event to get notified about updates to the model. But I’m not happy doing it this way. It leads to a lot of code and checks everywhere.
Now, I’ve been thinking, wouldn’t it be better to make use of Angular and use isolated scopes for the models? This way anyone interested in a particular value can just watch the model for changes.
Example:
function UserService($rootScope) {
var model = $rootScope.$new(true);
this.getModel = function() {
return model;
};
}
function userWidget(userService) {
var user = userService.getModel();
user.$watch('isLoggedIn', function(isLoggedIn) {
//React to if the user i signed in or not...
});
}
Is it a good idea or a bad idea? Any thoughts about this? How have you solved this?
Even if silly, here is a small demo:
http://plnkr.co/edit/JTggQ0FVYpo4saLmjLAo
Thanks!
/Martin
There's nothing wrong with it, but I would personally have a benefit to describe before I just randomly did that. $rootScope.$new is actually sort of heavy - an AngularJS scope has a lot of additional reference objects like siblings and parents. If you have 5, who cares? But if you have 5,000 that's going to be heavy for the garbage collector to manage. It's totally justified if it gives you some advantage, but if it's just for the sake of itself I wouldn't bother.
Is there a reason you rely on variable hoisting so much in your example? It's usually viewed as a by-product or anti-pattern, so it may throw off other developers who help maintain your code. Or are you flying solo? :)
How would you implement something like this in Angular:
I have a multi-page user interaction that shares state across pages/controllers. Page A launches a multi-page process across pages B, C, and D. I need to share state across pages B-C-D but as soon as the user goes back to page A (either at completion, or abandoning halfway through) the shared B-C-D state should go away.
I could put the shared state in a service and that would take care of sharing across pages. But then it's a global singleton for the whole application. Is there a way to ensure the service is disposed if the transaction is abandoned or completed?
In the server-side, Java EE world this was called "conversation scope" - I'm wondering what the equivalent might be in Knockout or Angular.
Or there a better way to approach the design? Should I use nested controllers?
This is a pretty broad question and is going to certainly elicit some opinion based responses. That said, one of the things you can rely on is that services (and factories) are singletons. What that means is if you need to share data between controllers, or across the life of a SPA you can create a service to hold and share that data. That service and its data will exist as long as the page isn't re-loaded.
The basic pattern for a shared data factory is like this is:
// define the shared data service
app.factory("SharedData", function () {
return {
// just one data object for the purposes of the example
sharedDataObject: {}
};
});
Once you have defined the service you can define a controller that uses the service something like:
app.controller("FirstController", function ($scope, SharedData) {
$scope.localData = SharedData.sharedDataObject;
});
Because we have defined the shared data as an object and not as a value - binding to "localData" will allow us to set values that can then be retrieved for as long as the page isn't changed. I put together an example that shows sharing data between two controllers here. This pattern works just as well if the controllers were on separate views.
Again - I'm not sure if this is the recommended pattern but it is one I have seen around and it works pretty well. Best of luck!
NOTE - This answer is referenced in your question - so it probably isn't exactly what you are looking for. That said, I am posting for others that may need a simple method of saving state on an SPA.
If you put the shared state into a service, just add a reset() function to it that gets called when they go to the "A" step or when they complete the process.
And I think you could do it with a nested controller too. You'd probably still need to add a reset() function for handling all the cases.
I am working on a web app with AngularJS which I just started learning a while back. I find it extremely useful but after working on it for few days, I figured that the app is going to get all messed up sooner or later, since I wrote all my 'backend' code in one controller.
The app uses lots of $http requests to get/post/delete/put data from/to remote servers and also many scope variables which are needed to manipulate page in one way or another.
I checked lots of tutorials/info sites on AngularJS (similar question, great blog post for instance) but I am still not sure how to implement one of my own within my app. I was wondering what is the usual case with using your own service/module/directive/factory? I am hoping to restructure my code a little bit so everything is going to seem more organized; at the moment I think I am not fully taking advantage of AngularJS with all my code in one place and without using any services/modules besides my main app module and controller and built-in $http.
So you can better understand my problem, so far I only use two javascript files, first one being app.js :
var app = angular.module('MyAppName',[]);
and the second one being controller.js (I could of course use only 1 file for this):
app.controller("MyController", function($scope, $http){
// all my functions/variables in here
// I initialize them with $scope.someName = … if they are needed within this controller view.
// If they are not needed within view I initialize them (functions for instance)
// as functionName = function(){};
}
Everything works as it should this way, but I think this approach is not using all the capabilities of AngularJS. For instance: I don's use routing which I probably should?(url stays the same all the time). I also don't use any other advanced features of angularJS such as custom services/directives/modules.
So I ask: how can I restructure my code so that it uses more of AngularJS features and so that it stays readable? When do you usually create your own service/module/factory ?
I kind of didn't grasp the whole thing on AngularJS site, probably because I started developing too early with not enough knowledge and now I hardly get it (was too much into two-way-binding and started coding immediately).
Any help on the subject is appreciated.
EDIT:
OK, I see I should clear some things up: my main problem is not the outside folder/file structure, but the code structure itself. Now I have one controller which contains every variable (30+) and function to use in my web app, such as login function, sign out function, functions for showing/hiding parts of page, function to add/delete data to/from server etc…
I would like to be able to structure these functions/variables as some independent parts somehow, but I am not sure how.
EDIT2:
I figured how to use services for instance, but unfortunately you cannot call service functions inside views, such as with ng-click directly... you can only call $scope variables which is logical actually... unfortunately i still don't know how to organize my code to seem more readable and structured
There are lots of opinions about how to organize AngularJS code. Have a look at these blog posts:
Code Organization in Large AngularJS and JavaScript Applications
Code Organization in Angular
There are also lots of sample projects out there that showcase various code organization schemes.
Take a look at the angular-seed project:
https://github.com/angular/angular-seed
One alternative to the above is angular-enterprise-seed:
https://github.com/robertjchristian/angular-enterprise-seed
You didn't mention what backend you're using, but there are also similar "seed" projects demonstrating the recommended code organization scheme for AngularJS + [your backend]. For instance, if you're using Express.js, you might want to take a look at angular-express-seed:
https://github.com/btford/angular-express-seed
Data Binding - Angular JS provides two way binding is automatic synchronization of the data between model and view.
Extensible - AngularJS is customized and extensible . Allows you to create customizable components.
Code Reusability and Maintainability - AngularJS forces you to write code in modular way. Variables and functions can only be created to the respective component(Controller). Provides service and factory implemetation to use across the controllers.
Compatibility - AngularJS is compatible to all major browsers
Testing - AngularJS is designed to be testable so that you can test your AngularJS app components as easy as possible. It has dependency injection at its core, which makes it easy to test.
http://astutejs.blogspot.in/2015/06/advantages-of-angular-js.html
First of all I must admit I am quite new to Angular.js and I haven't used any new generation js framework like Backbone or Knockout before. I'm creating an application which communicates with server using RESTful API. I dug a lot into angular documentation and blog notes so as I could do it right.
I found examples mostly with $resource. It looks pretty good: many built-in methods, when you design your REST interface properly you don't even have to write anything more.
But I (and my whole team too) are more used to JavaEE way of thinking about model layer: lightweight model classes (POJO, etc), DAO classes persisting and fetching model and optionally service layer between DAO and controllers. On the other hand in Angular $resource creates something more resembling active record.
I've already come up with two ways how to implement DAO pattern in Angular:
Writing everything from scratch, going down to the $http abstraction level. I'd implement every DAO method as $http call, take care about errors.
Using $resource objects normally like lightweight model classes and passing them to DAOs which are the only unit responsible for calling actions like .$save() on them. Of course we cannot prevent calling it in different place, but solution with such convention is good enough for me.
Second way looks better for me because of reusing existing code. $resource has nice behaviour of promise object and I will be happy if I don't have to implement it myself.
So finally the main question: is active record approach is the only way of doing data access right in Angular, Backbone and other tools like that? Maybe somebody have already tried to incorporate similar solution more resembling DAO in his code and can share his thoughts about it?
And the second question: is $resource object sufficient when it comes to dealing with errors, connection losses and different problems? Is it worth to use $resource having this in mind or it's better to start with lower level $http.
I am at the beginning of the project and I know that this decision may well affect the whole project life later, so I want to choose the best.
I totally agree. Here is the way I do it:
bankApp.factory("CustomerRepository", function ($resource) {
var customerRepository = $resource("rest/customers/:id", {id:'#id'}, {'update': {method:'PUT'}});
// You can also add addition repository like $http calls onto the
// customerRepository like getting the count and other stuff.
return customerRepository;
});
Then you can inject the CustomerRepository where ever you need it. For example:
bankApp.controller("BankController", function ($scope, CustomerRepository) {
$scope.customers = CustomerRepository.query();
$scope.createCustomer = function () {
CustomerRepository.save($scope.customer, function (customer) {
...
});
};
...
$scope.saveCustomer = function () {
CustomerRepository.update($scope.customer, function (customer) {
...
});
};
});