Opencpu and Meteor - angularjs

I have seen some examples of using opencpu together with angular, but no examples of using opencpu in meteor (where angular could be inplemented easily).
Is it as easy as just including ocpu.seturl and jquery.min.js in meteor (as is done here), or does one need to think differently in meteor when using opencpu?
For example, there might be some conflicts between angular and meteor.
I know that is a diffuse question, but I've seen that I'm not the only one who does wonder about it.
Related:
https://groups.google.com/forum/#!topic/opencpu/rEi7lMK65GU
https://www.quora.com/Is-it-possible-to-call-the-R-server-within-a-website-made-with-Meteor-run-some-R-code-then-display-its-output
For example (thanks to http://jsfiddle.net/ramnathv/uatjd/15/):
var myApp = angular.module('myApp', ['angular-meteor']); //added 'angular-meteor'
//set CORS to call "stocks" package on public server
ocpu.seturl("//public.opencpu.org/ocpu/library/graphics/R")
myApp.factory('OpenCPU', function($http){
return {
Dist: function(dist){
var url = "http://public.opencpu.org//ocpu/library/stats/R/" + dist +
"/json"
return $http.post(url, {n: 100})
}
}
})
myApp.controller("HistCtrl", function($scope, $http, OpenCPU){
$scope.dist = 'rnorm'
$scope.dists = ['rnorm', 'runif']
$scope.color = 'blue'
$scope.colors = ['blue', 'red', 'darkmagenta']
$scope.breaks = 10
$scope.submit = function(){
var req = $("#plotdiv").rplot("hist", {
x : $scope.data,
col: $scope.color,
breaks: Math.floor($scope.breaks),
main: $scope.main
});
}
$scope.$watchCollection('[main, color, breaks, data]', function(x){
$scope.submit()
})
$scope.$watch('dist', function(newDist){
OpenCPU.Dist(newDist).success(function(result){
$scope.data = result
})
})
})
Would the above be a "correct" starting point? How should one declare dependencies in meteor (i.e. opencpu, jquery.min.js) ? New to meteor so any suggestions are highly appreciated!

Not using angular (not sure why one would need that), but here is a super basic setup in meteor:
HTML:
<head>
<title>opencpu</title>
<script src="//cdn.opencpu.org/opencpu-0.4.js"></script>
</head>
<body>
<h1>Testing OpenCPU</h1>
{{> hello}}
</body>
<template name="hello">
</template>
JS:
if (Meteor.isClient) {
Template.hello.onRendered(function() {
// ocpu.seturl("//public.opencpu.org/ocpu/library/graphics/R");
// couldn't come up with a good example for this
ocpu.seturl("//public.opencpu.org/ocpu/library/stats/R")
// this gives me a CORS error but the below still seems to work
console.log(ocpu);
var req1 = ocpu.call("rnorm", {n: 100}, function(session1){
var req2 = ocpu.call("var", {x : session1}, function(session2){
session2.getObject(function(data){
alert("Variance equals: " + data);
});
});
});
});
}
All I know about opencpu I've learned in the last 30 minutes -- little! So I don't know how to get past the CORS error. That error doesn't seem to happen when pointing at the graphics package, but for that one I couldn't think of a good example.

Related

Is it possible to use parameterized URL templates with angular $http service

I'm using $resource for my RESTful api's and love the parameterized URL template for example 'api/clients/:clientId'
This works great for CRUD operations. Some of my api's however are just reports or read-only end points without the need for the full RESTful treatment. I felt it was overkill to use $resource for those and instead used a custom data service with $http.
The only drawback is I lose the parameterized URL templates. I would love to define a url like'api/clients/:clientId/orders/:orderId' and just pass { clientId: 1, orderId: 1 }. I realize I can build the url dynamically but was hoping $http supported the parameterized template and I just haven't found it yet.
All the best
UPDATE 7/5
The word I was missing in my searches is 'Interpolate'. More information comes up when I search for 'url interpolation in angular $http'. The short answer looks to be 'No' $http doesn't support url interpolation. There are a few fairly easy ways to accomplish this however.
1. Use $interpolate:
Documentation for $interpolate here
var exp = $interpolate('/api/clients/{{clientId}}/jobs/{{jobId}}', false, null, true);
var url = exp({ clientId: 1, jobId: 1 });
2. Write your own url interpolation function
Ben Nadel has a great post on this exact topic here.
3. Steal the functionality right out of angular-resource
Check out setUrlParams on Route.prototype in angular-resource.js. It is fairly straightforward.
Sample data service using $interpolate
(function () {
'use strict';
var serviceId = 'dataservice.jobsReports';
angular.module('app').factory(serviceId, ['$http', '$interpolate', function ($http, $interpolate) {
var _urlBase = 'http://localhost:59380/api';
var _endPoints = {
getJobsByClient: {
url: 'Clients/{{clientId}}/Jobs',
useUrlInterpolation: true,
interpolateFunc: null
}
};
// Create the interpolate functions when service is instantiated
angular.forEach(_endPoints, function (value, key) {
if (value.useUrlInterpolation) {
value.interpolateFunc = $interpolate(_urlBase + '/' + value.url, false, null, true);
}
});
return {
getJobsByClient: function (clientId) {
var url = _endPoints.getJobsByClient.interpolateFunc({ clientId: clientId });
return $http.get(url);
}
};
}]);
})();
To prevent this being "unanswered" when it has been answered ...
1. Use $interpolate:
Documentation for $interpolate here
var exp = $interpolate('/api/clients/{{clientId}}/jobs/{{jobId}}', false, null, true);
var url = exp({ clientId: 1, jobId: 1 });
2. Write your own url interpolation function
Ben Nadel has a great post on this exact topic here.
3. Steal the functionality right out of angular-resource
Check out setUrlParams on Route.prototype in angular-resource.js. It is fairly straightforward.
Sample data service using $interpolate
(function () {
'use strict';
var serviceId = 'dataservice.jobsReports';
angular.module('app').factory(serviceId, ['$http', '$interpolate', function ($http, $interpolate) {
var _urlBase = 'http://localhost:59380/api';
var _endPoints = {
getJobsByClient: {
url: 'Clients/{{clientId}}/Jobs',
useUrlInterpolation: true,
interpolateFunc: null
}
};
// Create the interpolate functions when service is instantiated
angular.forEach(_endPoints, function (value, key) {
if (value.useUrlInterpolation) {
value.interpolateFunc = $interpolate(_urlBase + '/' + value.url, false, null, true);
}
});
return {
getJobsByClient: function (clientId) {
var url = _endPoints.getJobsByClient.interpolateFunc({ clientId: clientId });
return $http.get(url);
}
};
}]);
})();
For URL templateing, there is a clearly defined recommandation: RFC 6570
You can find one implementation on Github : bramstein/url-template
It is quite simple. Here is an AngularJS service making use of a library implementing RFC 6570 standard:
var app=angular.module('demo',[]);
app.service('UserStore',function () {
var baseUrl=urltemplate.parse('/rest/v1/users{/_id}');
return {
load:function(id){
return $http.get(baseUrl.expand({_id:id}));
},
save:function (profile) {
return baseUrl.expand(profile);
//return $http.post(baseUrl.expand(profile),profile);
},
list:function (id) {
}
}
});
app.controller('demoCtrl',function(UserStore){
this.postUrlOfNewUser=UserStore.save({name:"jhon"});
this.postUrlOfExistingUser=UserStore.save({_id:42,name:"Arthur",accessory:"towel"});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.rawgit.com/bramstein/url-template/master/lib/url-template.js"></script>
<div ng-app="demo">
<div ng-controller="demoCtrl as ctrl">
<div>New user POST URL: {{ctrl.postUrlOfNewUser}}</div>
<div>Existing user POST URL: {{ctrl.postUrlOfExistingUser}}</div>
</div>
</div>
<script>
</script>
As you can see, the standard even handle optional PATH component. It make it a breeze !
And you can also use "." or ";" -- for matrix notation and even expand query strings!

Using Express to render an .ejs template for AngularJS and use the data inside AngularJS $scope

I hope I can explain myself with this first question I post on Stack Overflow.
I am building a small test application with the MEAN stack.
The application receives variable data from Mongoose based on an Express Route I have created.
For example the url is: localhost:3000/cities/test/Paris
Based on the name of the city the response gives me the name of the city and a description. I Know how to get this data inside the .ejs template
But thats not what I want. I want to use this data inside an ngRepeat.
Maybe this is not the right way but maybe you can help me figure this out.
The reason I want to do this is because I don't want a single page application but an Angular template that can be used over and over for each city and only uses the data that gets back from the mongoose find() results and not the whole cities array.
app.js :
var cityRoutes = require('./routes/cities');
app.use('/cities', cityRoutes);
app.set('views', './views'); // specify the views directory
app.set('view engine', 'ejs'); // register the template engine
./routes/cities/cities.js :
var express = require('express');
var citiesList = require('../server/controllers/cities-controller');
var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: false });
var router = express.Router();
// because this file is a fallback for the route /cities inside app.js
// the route will become localhost:3000/cities/test/:name
// not to be confused by its name in this file.
router.route('/test/:name')
.get(citiesList.viewTest)
module.exports = router;
../server/controllers/cities-controller.js :
var City = require('../models/cities');
module.exports.viewTest = function(request, responce){
City.find({ stad: request.params.name }, function(err, results){
if (err) return console.error(err);
if (!results.length) {
responce.json( "404" );
} else {
responce.render('angular.ejs', { messages:results });
// through this point everything works fine
// the angular.ejs template gets rendered correctly
// Now my problem is how tho get the results from the
// response.render inside the Angular directive
// so I can use the data in a $scope
}
});
};
../models/cities.js
var mongoose = require('mongoose');
module.exports = mongoose.model('City', {
stad: { type: String, required: true },
omschrijving: String
});
AngularJS directive :
// This is where I would like to use the messages result data
// so I can create a $scope that handles data that can be different
// for each url
// so basically I am using this directive as a template
app.directive('bestelFormulier', function () {
return {
restrict: 'E',
templateUrl: '/partials/bestel-formulier.html',
controller: ['$scope', '$http', '$resource', '$cookieStore',
function($scope, $http, $resource, $cookieStore){
// at this point it would be nice that the $scope gets the
// url based results. But I don't now how to do that..
// at this point the var "Cities" gets the REST API with
// all the cities...
var Cities = $resource('/cities');
// get cities from mongodb
Cities.query(function(results){
$scope.cities = results;
//console.log($scope.products);
});
$scope.cities = {};
}],
controllerAs: 'productsCtrl'
}
});
The database is stored like this :
[
{
stad: 'Paris',
omschrijving: 'description Paris',
},
{
stad: 'Amsterdam',
omschrijving: 'description Amsterdam',
}
]
I hope these files included helps explaining my issue.
Thanks in advance for helping me out
I figured out a way to do it...
The following changes to my code fixed my issue.
in app.js
var cityRoutes = require('./routes/cities');
app.use('/', cityRoutes);
// removed the name cities
./routes/cities/cities.js :
router.route('/cities/test/:name')
.get(citiesList.viewTest)
// added this route to use as an API
router.route('/api/cities/test/:name')
.get(citiesList.viewStad)
../server/controllers/cities-controller.js :
// added this callback so that a request to this url
// only responses with the data I need
module.exports.viewStad = function(request, responce){
City.find({ stad: request.params.name }, function(err, results){
if (err) return console.error(err);
if (!results.length) {
responce.json( "404" );
} else {
responce.json( results );
}
});
};
in my AngularJS app I added the $locationDirective and changed the following in my Angular directive to :
var url = $location.url();
var Cities = $resource('/api' + url);
// now when my .ejs template gets loaded the Angular part looks at
// the current url puts /api in front of it and uses it to get the
// correct resource
That is the way how I can use it in my $scope and use al the lovely Angular functionality :-)
Hope I can help other people with this... Eventually it was a simple solution and maybe there are people out there knowing beter ways to do it. For me it works now.

AngularJS Service to Service with a delay

I am currently facing a problem with my project's design.
I am using angularjs framework and my task is to provide a translations for a webpage, but the translations need to be provided form the xml file o the BE side.
So since I#ve found out that angulars i18n is configurable on the FE side i had to use another strategy.
I've decided to make a service which fetches the data during a resolve period before everything else is loaded:
app.factory('dictionaryService', ['$http', '$rootScope', function ($http, $rootScope) {
return {
getDictionary: function (defaultLanguage) {
var chosenLanguage = null;
if (angular.isUndefined($rootScope.defaultLanguage) || $rootScope.defaultLanguage == null) {
chosenLanguage = defaultLanguage;
$rootScope.defaultLanguage = chosenLanguage;
} else {
chosenLanguage = $rootScope.defaultLanguage;
}
var translation = new Array();
translation[chosenLanguage] = new Array();
return $http.get('Translation/GetCurrentDictionary/', {
params: {
language: chosenLanguage
}
});
},
GetLanguagesSetup: function () {
return $http.get('Translation/GetLanguagesSetup/');
}
}
}]);
and then resolve it as follows:
$routeProvider.when("/diagnose", {
controller: "diagnoseCtrl",
templateUrl: "/app/views/diagnose.html",
resolve: {
startupData: function (dictionaryService, $q) {
var def = $q.defer();
var translation = new Array();
var startupData = new Array();
var defaultLanguage = "EN";
var dict = dictionaryService.getDictionary(defaultLanguage).then(function (JSONData) {
var keys = Object.keys(JSONData.data.data);
var chosenLanguage = JSONData.data.lang;
translation[chosenLanguage] = {};
for (i = 0; i < keys.length; i++) {
translation[keys[i]] = JSONData.data.data[keys[i]];
}
startupData['translations'] = translation;
def.resolve(startupData);
}).catch(function (e) {
console.log("Translation fetching exception, " + e);
return $q.reject(e);
});
return def.promise;
}
}
});
So as you can see I am storing my fetched translations in a startupData. Then in a controller which is using it I am assigning this data to the $rootScope. It seems already here as a not the best solution, but I could not come up with a different one
Then I have created a translation service which gets the direct translation text:
app.factory('translationService', ['$rootScope', '$http', function ($rootScope, $http) {
var translations = null;
return {
getText: function (key) {
if ($rootScope.cachedTranslations == undefined) {
return key;
}
var result = $rootScope.cachedTranslations[key];
if (result == null) {
return key;
} else {
return result;
}
}
}
}]);
The biggest problem with this solution is, that I am not using promises, but I do not want to make an http query to BE for each translation.
The other problem is with the html template provided by the designers:
<body ng-controller="mainController">
<loading-screen ng-show="!isDataLoaded"></loading-screen>
<div id="header" class="headerView" ng-controller="headerController" ng-show="isDataLoaded">
some header stuff
...
<button ng-bind="option1" ng-click="redirectTo('#subpage1')"></button>
<button ng-bind="option2" ng-click="redirectTo('#subpage2')"></button>
<button ng-bind="option3" ng-click="redirectTo('#subpage3')"></button>
<button ng-bind="language" ng-if="availableLanguages.length > 1" ng-repeat="language in availableLanguages" ng-click="setLanguage(language)"></button>
</div>
</div>
<
<div id="content" ng-view ng-show="isDataLoaded">
</div>
<footer id="footer" class="footer" ng-show="isDataLoaded">
<status-bar></status-bar>
</footer>
Resolve applies only for ng-views's controller, but header stuff needs to be translated as well, so I need to make a headerCtrl somehow wait before it tries to apply translations.
So I have made another unpopular decision to inform all controllers about the finished startup via a broadcast message and to wait until it is all done while showing the loading screen.
It looks fine and is pretty responsive (1sec per startup is acceptable at this point).
The problem is, that I see many design mistakes with this attempt and I just can not come up with the better design.
So my main question is:
How can I make it better? 1st service returns a whole array which is used by the 2nd service so I do not know how to combine it with promises?
I am afraid that with the development of the application I will find myself in a global variables and global events hell
Thanks in advance for your help!
It seems like you are looking for the angular-translate-loader-static-files extension for angular-translate. See the documentation here.
This together with proper configuration of $translateProvider will allow you to fetch json files with translations from the backend or even swap translations on demand - for example user changes language setting, controller reconfigures $translateProvider. Your job is done - everything will be fetched and updated automatically without a page reload.

angularfire binding to primitive

I'm trying to bind to a primitive with angularfire. Here's how I"m doing it:
$firebase(fb.child('counts/node')).$on('value', function (obj) {
$scope.nodeCount = obj.snapshot.value
})
Is this correct? This API seems very different from the rest of firebase. I expected to get an ss as callback and do ss.val() but that doesn't seem to be the case. Can someone confirm if this is how it's supposed to be or if I'm doing it wrong. Thanks.
Generally, as outlined in the getting started guide and API, you should simply be accessing the data directly in the view:
// javascript
$scope.messages = $firebase(new Firebase(URL));
<!-- html -->
<li ng-repeat="message in messages">{{message}}</li>
If you want to iterate the data in a controller (bad) or service (better), you can read the keys in the order as the database by using $getIndex().
// javascript
var ref = $firebase(new Firebase(URL));
ref.$on('loaded', function() {
angular.forEach(ref.$getIndex(), function(key) {
console.log('the next message is', key, ref[key]);
});
});
If you are, in fact, trying to synchronize a single primitive value, angularFire is hardly necessary:
$scope.primitive = null;
var ref = new Firebase(URL);
ref.on('value', function(snap) { $scope.primitive = snap.val(); });
$scope.saveValue = function(newValue) {
ref.set(newValue);
};
But certainly possible:
// javascript
$scope.primitive = $firebase(new Firebase(URL));
<!-- html -->
<input ng-model="primitive.$value" />
All of this is covered in the above links, which should be treated as required reading before getting started with Angular + Firebase.
changes in 0.8
angularFire 0.8 will be out soon. It will change this structure a little bit, utilizing a $asArray(), $asObject(), and also providing a .then() method, so a bit more like this:
// javascript
var ref = $firebase(new Firebase(URL));
$scope.messages = ref.$asArray();
$scope.ref.then(function() {
angular.forEach($scope.messages, function(message) {
console.log('the next message is', message.$id);
});
});
<!-- html -->
<li ng-repeat="message in messages">{{message}}</li>

Proper place for data-saving logic in AngularJS

App design question. I have a project which has a very large number of highly customized inputs. Each input is implemented as a directive (and Angular has made this an absolute joy to develop).
The inputs save their data upon blur, so there's no form to submit. That's been working great.
Each input has an attribute called "saveable" which drives another directive which is shared by all these input types. the Saveable directive uses a $resource to post data back to the API.
My question is, should this logic be in a directive at all? I initially put it there because I thought I would need the saving logic in multiple controllers, but it turns out they're really happening in the same one. Also, I read somewhere (lost the reference) that the directive is a bad place to put API logic.
Additionally, I need to introduce unit testing for this saving logic soon, and testing controllers seems much more straightforward than testing directives.
Thanks in advance; Angular's documentation may be… iffy… but the folks in the community are mega-rad.
[edit] a non-functional, simplified look at what I'm doing:
<input ng-model="question.value" some-input-type-directive saveable ng-blur="saveModel(question)">
.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{id: question.id, answer: question.value},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
}
}])
No, I don't think the directive should be calling $http. I would create a service (using the factory in Angular) OR (preferably) a model. When it is in a model, I prefer to use the $resource service to define my model "classes". Then, I abstract the $http/REST code into a nice, active model.
The typical answer for this is that you should use a service for this purpose. Here's some general information about this: http://docs.angularjs.org/guide/dev_guide.services.understanding_services
Here is a plunk with code modeled after your own starting example:
Example code:
var app = angular.module('savingServiceDemo', []);
app.service('savingService', function() {
return {
somethingOrOther: {
save: function(obj, callback) {
console.log('Saved:');
console.dir(obj);
callback(obj, {});
}
}
};
});
app.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{
id: question.id,
answer: question.value
},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
};
}]);
app.controller('questionController', ['$scope', function($scope) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
}]);
The relevant HTML markup:
<body ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="saveModel(question)" />
</body>
An alternative using only factory and the existing ngResource service:
However, you could also utilize factory and ngResource in a way that would let you reuse some of the common "saving logic", while still giving you the ability to provide variation for distinct types of objects / data that you wish to save or query. And, this way still results in just a single instantiation of the saver for your specific object type.
Example using MongoLab collections
I've done something like this to make it easier to use MongoLab collections.
Here's a plunk.
The gist of the idea is this snippet:
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
Notes:
dbUrl and apiKey would be, of course, specific to your own MongoLab info
The array in this case is a group of distinct collections that you want individual ngResource-derived instances of
There is a createResource function defined (which you can see in the plunk and in the code below) that actually handles creating a constructor with an ngResource prototype.
If you wanted, you could modify the svc instance to vary its behavior by collection type
When you blur the input field, this will invoke the dummy consoleLog function and just write some debug info to the console for illustration purposes.
This also prints the number of times the createResource function itself was called, as a way to demonstrate that, even though there are actually two controllers, questionController and questionController2 asking for the same injections, the factories get called only 3 times in total.
Note: updateSafe is a function I like to use with MongoLab that allows you to apply a partial update, basically a PATCH. Otherwise, if you only send a few properties, the entire document will get overwritten with ONLY those properties! No good!
Full code:
HTML:
<body>
<div ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
<div ng-controller="questionController2">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
</body>
JavaScript:
(function() {
var app = angular.module('savingServiceDemo', ['ngResource']);
var numberOfTimesCreateResourceGetsInvokedShouldStopAt3 = 0;
function createResource(resourceService, resourcePath, resourceName, apiKey) {
numberOfTimesCreateResourceGetsInvokedShouldStopAt3++;
var resource = resourceService(resourcePath + '/' + resourceName + '/:id',
{
apiKey: apiKey
},
{
update:
{
method: 'PUT'
}
}
);
resource.prototype.consoleLog = function (val, cb) {
console.log("The numberOfTimesCreateResourceGetsInvokedShouldStopAt3 counter is at: " + numberOfTimesCreateResourceGetsInvokedShouldStopAt3);
console.log('Logging:');
console.log(val);
console.log('this =');
console.log(this);
if (cb) {
cb();
}
};
resource.prototype.update = function (cb) {
return resource.update({
id: this._id.$oid
},
angular.extend({}, this, {
_id: undefined
}), cb);
};
resource.prototype.updateSafe = function (patch, cb) {
resource.get({id:this._id.$oid}, function(obj) {
for(var prop in patch) {
obj[prop] = patch[prop];
}
obj.update(cb);
});
};
resource.prototype.destroy = function (cb) {
return resource.remove({
id: this._id.$oid
}, cb);
};
return resource;
}
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
app.controller('questionController', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('And, I got called back');
});
};
}]);
app.controller('questionController2', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What is the coolest JS framework of them all?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('You better have said AngularJS');
});
};
}]);
})();
In general, things related to the UI belong in a directive, things related to the binding of input and output (either from the user or from the server) belong in a controller, and things related to the business/application logic belong in a service (of some variety). I've found this separation leads to very clean code for my part.

Resources