Sails.js how to call functions within a controller - javascript

Getting my hand dirty in Sail.js (and node).
Versions
$ sails --version
1.2.4
$ node --version
v12.16.1
My first sails controller (an example) is as follows:
// MyController
// MyController.js
module.exports = {
sum_it: function (a, b) {
return (a + b);
},
minus_it: function (a, b) {
return (a - b);
},
process_it: function (req, res) {
let i = 12;
let j = 4;
do_what = "sum"; //this will be an input extracted from req
if (do_what == "sum") {
let result = this.sum_it(i, j); //"this" doesn't work????
} else {
let result = this.minus_it(i, j); //"this" doesn't work????
}
console.log(result);
return res.send(result);
}
};
My intention is to have few functions defined within that controller itself as they would be ONLY used under this controller. I used this.sum_it(i, j) this.minus_it(i, j) and both of them don't work.
What is the best way to have multiple functions in the controller and call them within that controller file (assuming those functions are too specific to that controller and hence, no need to take them out and put in the other helper files)?

The way you have to think about it is like this: when Sails runs, it compiles all your controllers, services, helpers, etc and sets all the routes using an internal Express application, so, the concept of "this" inside controllers, services, helpers doesn't work.
For this, sails provides you a globally available object: sails. Within that object you can find all your runtime variables, controllers, services, etc.
To get access to your particular controller action within a controller, for Sails 0.12, you can do:
sails.controllers.my.sum_it(1,2)
For Sails 1.x, you can do:
sails.getActions()['my/sum_it'](1,2)
Finally, if you don't need to expose those functions as actions, you can just make them functions anyhwere in the file outside the module.exports, and call them without this.

Related

AngularJS communication between modules in different html files

There are a couple of variables I want to share between two html files and two modules. Firstly, I used the service as follows but it did not work.
In vote.js:
var vote = angular.module('vote', []);
vote.service('voteParam', function () {
this.candidates = [];
this.show_result;
this.vote_begin;
this.elec_begin;
this.setValue = function (voteParam) {
this.department = voteParam.department;
this.group = voteParam.group;
this.type = voteParam.type;
this.round = voteParam.round;
this.times = voteParam.times;
this.advance_num = voteParam.advance_num;
}
});
In vote-setting.js:
angular.module('admin')
.controller('vote_setting', function ($scope, $http, voteParam) {
$scope.begin_vote = function () {
init();
startit();
$scope.vote_begin = true;
$scope.elec_begin = true;
voteParam.vote_begin = true;
voteParam.elec_begin = true;
voteParam.show_result = false;
voteParam.setValue($scope.voteParam);
if (voteParam.candidates.length == 0) {
$scope.get_candidate();
}
};
}
When the value is set as true in vote-setting.js, it is showed as undefined in vote.js. I think it's because when I import vote-setting.js in vote-setting.html, variables in the service are initialized again. Is there any other way I can make this work?
The service worked. But the value of variables in it get initialized when the js file is imported again. This is the key of this problem. Thanks
You might want to know the following:
Generally,an angular app should have only one base module. This is the module which you add to your html using ng-app directive. So your html content will know about only one angular app.
You can however create as many other modules as you would like or need. These can be custom modules as in your case, or these can be third party library (modules written by other developers for your ready use.). In any of the above case you need to add extra modules to your base module as dependencies as shown below:
angular.module('baseModule', ['extraModule1, extraModule2]);
Once you are done with this, any component like any directive , service, factory written in any of the extra modules shall be available to you for use, as if they were all written in your baseModule.
Having said this and coming to your question, the code provided by you doesn't seem sufficient to entirely diagnose your issue. However from whatever I get, I suggest you to add vote module to admin module or vice-versa. If you have any other module as a base module, you need to add both vote and admin as dependencies to that module.
Hope this helps you to start fixing the issue. Let me know if any thing seems unclear yet.
Implement your shared data service as a factory.
Implement proper getter and setters.
Encapsulate your variables and only expose the getter, setters.
Example of shared data service (can also be used as a shared Model)
app.factory('voteParam', function() {
var param1;
var param2;
var param3;
return {
setParam1: function(value){
param1 = value;
},
getParam1: function(){
return param1;
},
setParam2: function(value){
param2 = value;
},
getParam2: function(){
return param2;
},
setParam3: function(value){
param3 = value;
},
getParam3: function(){
return param3;
}
}
});
In an application this factory should be initialized once only.
If you are using 2 different angular applications (in your case 'vote' and 'admin') then use local storage or session storage to share data between them

Amd, requirejs - want to ensure something always executes last

I'm trying to avoid global scope for the following problem, but cannot see a way to avoid it.
I have a singleton Javascript object called "Application". This is an AMD module.
I then have many "Modules" (not to be confused with AMD modules) which are just javascript objects that I'd like to register with the "Application" instance.
For example:
require(['Application'], function(app) {
var module = {
name: "theme-switcher",
start: function() { console.log("started") } }
app.registerModule(module)
}
The architecture I am going for, is i'd like for each "Module" on the page to register itself with the "Application" instance.
Here is the tricky part: Only once ALL modules have been registered with the application, do I then want the "Application" instance, to loop through those registered modules and call their "Start()" methods.
The way I thought to do this was to just add another require block at the bottom of the page like this:
<script type="text/javascript">
require(['Application'], function (app) {
// start all the registered modules running.
app.start(() => {
// this could be a call back function once all modules started..
});
});
Niavely thinking, that just because this require call was last, that it would allways be executed last. But actually, sometimes this gets fired BEFORE the require calls above - so the Application attempts to Start() all registered modules BEFORE the modules themselves have all registered themselves with the Application.
No matter how I think about this problem, I am often led back to the fact that I need to keep some state in global scope, Something like this:
Module 1:
var app = Application.Instance;
var moduleStart = function(){
require(['jquery'], function(jquery) {
// do module goodness here.
}};
app.registerModule({name: "theme-switcher", start: moduleStart })
// later on in page - some other widget
// Module 2
var app = Application.Instance;
var moduleStart = function(){
require(['jquery'], function(jquery) {
// do second module goodness here.
}};
app.registerModule({name: "foo", start: moduleStart })
And then at the bottom of the page,
var app = Application.Instance;
app.Start(); // loops through registered modules calling start() method.
Surely there must be a way to do this avoiding global scope?
The reason for me wanting to do this, is that I want the "Application" to manage the lifecycle for registered modules on the page - including starting / pausing / stopping them etc. I'd also like the Application to publish an event once ALL modules gave been started - as this is when I would typically stop displaying my "loading" animation, and actually display the DOM - as modules will often manipulate the DOM in their start() methods and I don't want the page to be visible before everything is started.
This will do it. If you make every object you are wanting an AMD module, which I think you should be doing if you have RequireJS in place anyway, then you'll just need an array of strings defining those AMD module names to pass as an argument to the app's init.
Application.js : -
define(function (require, exports, module) {
"use strict";
var modules = {};
var moduleNames = [];
var numberOfModules = 0;
var loadedModules = 0;
exports.init = function (dependencies) {
numberOfModules = dependencies.length;
for (var i = 0; i < numberOfModules; i++){
var name = dependencies[i];
moduleNames.push(name);
require([name], function (moduleRef) {
loadedModules++;
modules[name] = moduleRef;
if (numberOfModules === loadedModules) {
exports.start();
}
});
}
};
exports.start = function () {
// all modules available
// use modules.myModuleName to access the module.
modules.myModuleName.functionName();
// or if they all have start() function and it needs calling
for (var i = 0; i < moduleNames.length; i++) {
modules[moduleNames[i]].start();
}
};
});
USAGE Depending on how you are loading your app, assuming you have an Application reference somewhere, just call:
// names of modules RequireJS uses to require, can be changed for each page.
var dependencies = ['moduleOne', 'moduleTwo', 'myModuleName'];
app.init(dependencies);
CodePen of this code, slightly altered to work on one page... http://codepen.io/owenayres/pen/MyMJYa

When should I use factory or service in angular? [duplicate]

Please bear with me here. I know there are other answers such as:
AngularJS: Service vs provider vs factory
However I still can't figure out when you'd use service over factory.
From what I can tell factory is commonly used to create "common" functions that can be called by multiple Controllers: Creating common controller functions
The Angular docs seem to prefer factory over service. They even refer to "service" when they use factory which is even more confusing! http://docs.angularjs.org/guide/dev_guide.services.creating_services
So when would one use service?
Is there something that is only possible or much easier done with service?
Is there anything different that goes on behind the scenes? Performance/memory differences?
Here's an example. Other than the method of declaration, they seem identical and I can't figure out why I'd do one vs the other. http://jsfiddle.net/uEpkE/
Update: From Thomas' answer it seems to imply that service is for simpler logic and factory for more complex logic with private methods, so I updated the fiddle code below and it seems that both are able to support private functions?
myApp.factory('fooFactory', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo; }
return {
setFoobar: function(foo){
addHi(foo);
},
getFoobar:function(){
return fooVar;
}
};
});
myApp.service('fooService', function() {
var fooVar;
var addHi = function(foo){ fooVar = 'Hi '+foo;}
this.setFoobar = function(foo){
addHi(foo);
}
this.getFoobar = function(){
return fooVar;
}
});
function MyCtrl($scope, fooService, fooFactory) {
fooFactory.setFoobar("fooFactory");
fooService.setFoobar("fooService");
//foobars = "Hi fooFactory, Hi fooService"
$scope.foobars = [
fooFactory.getFoobar(),
fooService.getFoobar()
];
}
Explanation
You got different things here:
First:
If you use a service you will get the instance of a function ("this"
keyword).
If you use a factory you will get the value that is returned by
invoking the function reference (the return statement in factory).
ref: angular.service vs angular.factory
Second:
Keep in mind all providers in AngularJS (value, constant, services, factories) are singletons!
Third:
Using one or the other (service or factory) is about code style.
But, the common way in AngularJS is to use factory.
Why ?
Because "The factory method is the most common way of getting objects into AngularJS dependency injection system. It is very flexible and can contain sophisticated creation logic. Since factories are regular functions, we can also take advantage of a new lexical scope to simulate "private" variables. This is very useful as we can hide implementation details of a given service."
(ref: http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821).
Usage
Service : Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference. Could also be run with injectedArg.call(this) or similar.
Factory : Could be useful for returning a ‘class’ function that can then be new`ed to create instances.
So, use a factory when you have complex logic in your service and you don't want expose this complexity.
In other cases if you want to return an instance of a service just use service.
But you'll see with time that you'll use factory in 80% of cases I think.
For more details: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/
UPDATE :
Excellent post here :
http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html
"If you want your function to be called like a normal function, use
factory. If you want your function to be instantiated with the new
operator, use service. If you don't know the difference, use factory."
UPDATE :
AngularJS team does his work and give an explanation:
http://docs.angularjs.org/guide/providers
And from this page :
"Factory and Service are the most commonly used recipes. The only difference between them is that Service recipe works better for objects of custom type, while Factory can produce JavaScript primitives and functions."
allernhwkim originally posted an answer on this question linking to his blog, however a moderator deleted it. It's the only post I've found which doesn't just tell you how to do the same thing with service, provider and factory, but also tells you what you can do with a provider that you can't with a factory, and with a factory that you can't with a service.
Directly from his blog:
app.service('CarService', function() {
this.dealer="Bad";
this.numCylinder = 4;
});
app.factory('CarFactory', function() {
return function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
});
app.provider('CarProvider', function() {
this.dealerName = 'Bad';
this.$get = function() {
return function(numCylinder) {
this.numCylinder = numCylinder;
this.dealer = this.dealerName;
}
};
this.setDealerName = function(str) {
this.dealerName = str;
}
});
This shows how the CarService will always a produce a car with 4 cylinders, you can't change it for individual cars. Whereas CarFactory returns a function so you can do new CarFactory in your controller, passing in a number of cylinders specific to that car. You can't do new CarService because CarService is an object not a function.
The reason factories don't work like this:
app.factory('CarFactory', function(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
});
And automatically return a function for you to instantiate, is because then you can't do this (add things to the prototype/etc):
app.factory('CarFactory', function() {
function Car(numCylinder) {
this.dealer="Bad";
this.numCylinder = numCylinder
};
Car.prototype.breakCylinder = function() {
this.numCylinder -= 1;
};
return Car;
});
See how it is literally a factory producing a car.
The conclusion from his blog is pretty good:
In conclusion,
---------------------------------------------------
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------
| Factory | Yes | Yes | No |
---------------------------------------------------
| Service | Yes | No | No |
---------------------------------------------------
| Provider| Yes | Yes | Yes |
---------------------------------------------------
Use Service when you need just a simple object such as a Hash, for
example {foo;1, bar:2} It’s easy to code, but you cannot instantiate
it.
Use Factory when you need to instantiate an object, i.e new
Customer(), new Comment(), etc.
Use Provider when you need to configure it. i.e. test url, QA url,
production url.
If you find you're just returning an object in factory you should probably use service.
Don't do this:
app.factory('CarFactory', function() {
return {
numCylinder: 4
};
});
Use service instead:
app.service('CarService', function() {
this.numCylinder = 4;
});
The concept for all these providers is much simpler than it initially appears. If you dissect a provider you and pull out the different parts it becomes very clear.
To put it simply each one of these providers is a specialized version of the other, in this order: provider > factory > value / constant / service.
So long the provider does what you can you can use the provider further down the chain which would result in writing less code. If it doesn't accomplish what you want you can go up the chain and you'll just have to write more code.
This image illustrates what I mean, in this image you will see the code for a provider, with the portions highlighted showing you which portions of the provider could be used to create a factory, value, etc instead.
(source: simplygoodcode.com)
For more details and examples from the blog post where I got the image from go to: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/
Both the factory and the service result in singleton objects which are able to be configured by providers and injected into controllers and run blocks. From the point of view of the injectee, there is absolutely no difference whether the object came from a factory or a service.
So, when to use a factory, and when to use a service? It boils down to your coding preference, and nothing else. If you like the modular JS pattern then go for the factory. If you like the constructor function ("class") style then go for the service. Note that both styles support private members.
The advantage of the service might be that it's more intuitive from the OOP point of view: create a "class", and, in conjunction with a provider, reuse the same code across modules, and vary the behavior of the instantiated objects simply by supplying different parameters to the constructor in a config block.
There is nothing a Factory cannot do or does better in comparison with a Service. And vice verse. Factory just seems to be more popular. The reason for that is its convenience in handling private/public members. Service would be more clumsy in this regard.
When coding a Service you tend to make your object members public via “this” keyword and may suddenly find out that those public members are not visible to private methods (ie inner functions).
var Service = function(){
//public
this.age = 13;
//private
function getAge(){
return this.age; //private does not see public
}
console.log("age: " + getAge());
};
var s = new Service(); //prints 'age: undefined'
Angular uses the “new” keyword to create a service for you, so the instance Angular passes to the controller will have the same drawback.
Of course you may overcome the problem by using this/that:
var Service = function(){
var that = this;
//public
this.age = 13;
//private
function getAge(){
return that.age;
}
console.log("age: " + getAge());
};
var s = new Service();// prints 'age: 13'
But with a large Service constant this\that-ing would make the code poorly readable.
Moreover, the Service prototypes will not see private members – only public will be available to them:
var Service = function(){
var name = "George";
};
Service.prototype.getName = function(){
return this.name; //will not see a private member
};
var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'
Summing it up, using Factory is more convenient. As Factory does not have these drawbacks. I would recommend using it by default.
Even when they say that all services and factories are singleton, I don't agree 100 percent with that. I would say that factories are not singletons and this is the point of my answer. I would really think about the name that defines every component(Service/Factory), I mean:
A factory because is not a singleton, you can create as many as you want when you inject, so it works like a factory of objects. You can create a factory of an entity of your domain and work more comfortably with this objects which could be like an object of your model. When you retrieve several objects you can map them in this objects and it can act kind of another layer between the DDBB and the AngularJs model.You can add methods to the objects so you oriented to objects a little bit more your AngularJs App.
Meanwhile a service is a singleton, so we can only create 1 of a kind, maybe not create but we have only 1 instance when we inject in a controller, so a service provides more like a common service(rest calls,functionality.. ) to the controllers.
Conceptually you can think like services provide a service, factories can create multiple instances(objects) of a class
Services
Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided the actual function reference passed to module.service.
Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference. Could also be run with injectedArg.call( this ) or similar.
Factories
Syntax: module.factory( 'factoryName', function );
Result: When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.
Providers
Syntax: module.provider( 'providerName', function );
Result: When declaring providerName as an injectable argument you will be provided the value that is returned by invoking the $get method of the function reference passed to module.provider.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances but that requires some sort of configuration before being injected. Perhaps useful for classes that are reusable across projects? Still kind of hazy on this one.
Can use both the way you want : whether create object or just to access functions from both
You can create new object from service
app.service('carservice', function() {
this.model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
});
.controller('carcontroller', function ($scope,carservice) {
$scope = new carservice.model();
})
Note :
service by default returns object and not constructor function .
So that's why constructor function is set to this.model property.
Due to this service will return object,but but but inside that object will be constructor function which will be use to create new object;
You can create new object from factory
app.factory('carfactory', function() {
var model = function(){
this.name = Math.random(22222);
this.price = 1000;
this.colour = 'green';
this.manufacturer = 'bmw';
}
return model;
});
.controller('carcontroller', function ($scope,carfactory) {
$scope = new carfactory();
})
Note :
factory by default returns constructor function and not object .
So that's why new object can be created with constructor function.
Create service for just accessing simple functions
app.service('carservice', function () {
this.createCar = function () {
console.log('createCar');
};
this.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carservice) {
carservice.createCar()
})
Create factory for just accessing simple functions
app.factory('carfactory', function () {
var obj = {}
obj.createCar = function () {
console.log('createCar');
};
obj.deleteCar = function () {
console.log('deleteCar');
};
});
.controller('MyService', function ($scope,carfactory) {
carfactory.createCar()
})
Conclusion :
you can use both the way you want whether to create new object or
just to access simple functions
There won't be any performance hit , using one over the other
Both are singleton objects and only one instance is created per app.
Being only one instance every where their reference is passed.
In angular documentation factory is called service and also service is called service.
Factory and Service are the most commonly used method. The only difference between them is that the Service method works better for objects that need inheritance hierarchy, while the Factory can produce JavaScript primitives and functions.
The Provider function is the core method and all the other ones are just syntactic sugar on it. You need it only if you are building a reusable piece of code that needs global configuration.
There are five methods to create services: Value, Factory, Service, Provider and Constant. You can learn more about this here angular service, this article explain all this methods with practical demo examples.
.

Mocha - Accessing named functions with ti-mocha

I'm using a hybrid version of mocha, ti-mocha, to build unit test for a Titanium SDK-based app. I'm completely new to BDD and mocha, so the API learning curve is quite steep. Here's my issue with a stripped-down test harness. I can access the index.js module, its methods and properties. However, I don't know how to access the named functions, in this case doClick(), within that module.
I'm using mocha + should.js. In the test harness below, context "index" passes, but context "doClick" fails. I'm so new to this API, that I'm not sure if I even framed the question properly. How do I access the functions within the module?
index-mocha.js
// creates the "mocha" global necessary to run a test suite anywhere in your app
var should = require('should');
module.exports = function(index) {
// create the test suite
describe('mochatest', function() {
context('index', function() {
it('index exists', function() {
should.exist(index);
});
it('index.open function', function() {
should(index.open).be.a.Function;
});
it('id = index', function() {
index.id.should.equal('index');
});
});
context('doClick', function() {
it('doClick exists', function() {
should.exist(index.doClick);
// return;
});
it('doClick is a function', function() {
should(index.doClick).be.a.Function;
});
});
});
var outputFile = Ti.Filesystem.getFile(Ti.Filesystem.tempDirectory, 'results.json');
outputFile.createFile();
mocha.setup({
reporter: 'ti-spec', // the reporter to use with your tests
outputFile: outputFile, // write results to the given Ti.Filesystem.File file
quiet: false // if true, suppress all console logging
});
// run the tests
mocha.run();
};
index.js
function doClick(e) {
alert($.label.text);
}
if(runTests){
require('ti-mocha');
$.index.addEventListener('open', function(){
require('index-mocha')($.index);
});
}
$.index.open();
Nice to see someone playing around with testing in Titanium :)
Just to clarify a thing, the variable $ refers to an instance of your current controller. Also, Alloy gives you references to view elements for which you have defined an id via this variable; This may be seen as a little sugar as all those views are accessible through $.getViews().
Therefore, all functions defined inside your controller file are accessible only from within that controller. If you want them to be accessible from the outside, the easiest and cleanest way is to exports them.
This can be done in two ways:
By directly add them to the controller object
$.doClick = doClick;
By using the exports variable
exports.doClick = doClick;
The result will be exactly the same as, during the compilation, Alloy will merge the exports variable (which is, initially, only an empty object) with your controller a.k.a $.
Then, just pass your controller through your require instead of the index view, to have access to both views and newly added listeners.

Is it possible to declare global variables in Node/Express 4.0

I have multiple routes that need to access a database, for development I use a local database, and obviously production I use a hosted database
The only problem is every time I go to push a release I have to go through each route manually changing the database link
e.g.
var mongodb = require('mongojs').connect('urlhere', ['Collection']);
It would be nice if I could declare a variable in app.js like
app.set('mongoDBAddress', 'urlhere');
then in each file do something like
var mongodb = require('mongojs').connect(app.get('mongoDBAddress'), ['Collection']);
Does anybody know if this is achievable I've been messing around with it for about an hour googling and trying to include different things but I have no luck. thanks.
From the docs:
In browsers, the top-level scope is the global scope. That means that
in browsers if you're in the global scope var something will define a
global variable. In Node this is different. The top-level scope is not
the global scope; var something inside a Node module will be local to
that module.
You have to think a bit differently. Instead of creating a global object, create your modules so they take an app instance, for example:
// add.js
module.exports = function(app) { // requires an `app`
return function add(x, y) { // the actual function to export
app.log(x + y) // use dependency
}
}
// index.js
var app = {log: console.log.bind(console)}
var add = require('./add.js')(app) // pass `app` as a dependency
add(1, 2)
//^ will log `3` to the console
This is the convention in Express, and other libraries. app is in your main file (ie. index.js), and the modules you require have an app parameter.
You can add a global variable to GLOBAL, see this this question, although this is probably considered bad practice.
We have two methods in node.js to share variables within modules.
global
module.export
But your problem seems to be different, what I got is you want to connect your application to different databases without changing code. What you need to do is use command line params
For more ref
server.js
var connectTo = {
dev : "url1"
production : "url2"
}
var mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
Run your server.js as
node server.js dev
// for connecting to development database
or
node server.js production
// for connecting to prodiction database
To share connection across diffrent modules
//Method 1
global.mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
//Method 2
exports.mongodb = require('mongojs').connect(connectTo[process.argv[2]], ['Collection']);
exports.getMongoDBAddress = function() {
return connectTo[process.argv[2]]
}

Categories

Resources