I created a module in nodejs where I wish to expose it's constants too. But this particular module contains a dependency which is provided at construction time i.e. dependency injection.
this is module1
const STORE_TYPE = {
STORE1: 1,
STORE2: 2
};
function service(dependency1) {
this.dep = dependency1;
}
service.prototype.doSomething = function(param1, store) {
if (STORE_TYPE.STORE1 == store) {
return this.dep.get(param1);
} else {
return "something";
}
};
module.exports = service;
I'm using module1 here:
var dep = require('./dep');
var dep1 = new otherService(dep);
var service = require('./service')(dep1);
function getData() {
return service.doSomething(id, /*this is module1 constant*/1);
}
How do I refere to module1's constants if module1 has a constructor.
I don't wish to add separate method only to create service since callee needs to perform multiple steps.
Try this:
service.js
exports.STORE_TYPE = {
STORE1: 1,
STORE2: 2
};
exports.service = function service(dependency1) {
this.dep = dependency1;
}
service.prototype.doSomething = function(param1, store) {
if (STORE_TYPE.STORE1 == store) {
return this.dep.get(param1);
} else {
return "something";
}
};
Using that module
app.js
const service = require('./service').service;
const STORE_STYLE = require('./service').STORE_TYPE;
Related
I know it's a duplicate but I don't understand the other posts: I'm doing an exercise on freeCodeCamp that I don't understand, it's about modules: What's the advantage of doing this:
const motionModule = (function() {
return {
isCuteMixin: function(obj) {
obj.isCute = function() {
return true;
};
},
singMixin: function(obj) {
obj.sing = function() {
console.log("Singing to an awesome tune");
};
}
};
})();
instead of this:
const motionModule = {
isCuteMixin: function(obj) {
obj.isCute = function() {
return true;
};
},
singMixin: function(obj) {
obj.sing = function() {
console.log("Singing to an awesome tune");
};
}
};
One advantage is you can emulate private variables and methods which are not accessible from outside the returned object. This helps keeping the data and functionality together and avoids corruption of global namespace.
const motionModule = (function() {
let song = 'My song'; // private variable
function singTheSong() {
// private method
}
return {
isCuteMixin: function(obj) {
obj.isCute = function() {
return true;
};
},
singMixin: function(obj) {
obj.sing = function() {
console.log("Singing to an awesome tune" + song);
singTheSong();
};
}
};
})();
// cannot call singTheSong from here
Within a module, you would often want the methods to be able to access each other and shared variables. To do this in your 2nd example, you need to attach them to the object and access them via the this keyword, and also (within the mixin creating functions) use arrow functions to ensure this refers to the right object.
const motionModule = {
song: "La La La",
sing: function() {
console.log(this.song);
},
singMixin: function(obj) {
obj.sing = () => {
console.log(`Singing ${this.song}`);
};
}
};
const a = {};
motionModule.sing();
motionModule.singMixin(a);
a.sing();
Modern ES6 class declarations also require you to work in this way.
class MotionModule {
song = "La La La";
sing() {
console.log(this.song);
}
singMixin(obj) {
obj.sing = () => {
console.log(`Singing ${this.song}`);
};
}
}
const motionModule = new MotionModule();
motionModule.sing();
const a = {};
motionModule.singMixin(a);
a.sing();
As shown in another answer, the first example (an immediately invoked function expression) allows you to access other variables and methods defined within the module without using this, and gives you greater control over which methods and variables are accessible from outside the module.
I am trying to get object from api.json but it throws error , based on typescript i have added declare module "*.json" into the project , Any idea how can i achieve this task ?
api.json
{
"Refills": {
"getPatientInfo": "Refills/patientInfo/GetPatientInfo"
}
}
index.ts
import {ModuleExecutor} from "./common/ModuleExecutor";
import {Identity} from "./common/Enums";
export class Index {
private executor: ModuleExecutor = null;
// Any string prepended with # is handled by grunt before building the project
// grunt dynamically reads the config/api.json and loads only the apis that are listed there
// api.json consists of the API name and the folder path for grunt
private _apisConfig: string = '#api'
constructor(identity: string) {
this.executor = new ModuleExecutor(Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
Error
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
Compiled index.js file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ModuleExecutor_1 = require("./common/ModuleExecutor");
const Enums_1 = require("./common/Enums");
class Index {
constructor(identity) {
this.executor = null;
this._apisConfig = '';
this.executor = new ModuleExecutor_1.ModuleExecutor(Enums_1.Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
exports.Index = Index;
//# sourceMappingURL=index.js.map
I've managed to get a fairly complex setup (though that's a question for Code Review) for my mixins that looks like this:
TooManyCaps.js
module.exports = {
labelCopyCaps: () => {
if (this.release.tracks.length > 1) {
if (_this._notEnoughLowercase(this.release.title)) {
this._recordError(release, 'LABELCOPYCAPS');
} else {
this.release.tracks.some( (track) => {
if (this._lowerCaseCount(track.label_copy)) {
this._recordError(release, 'LABELCOPYCAPS');
return true;
}
});
}
}
},
_notEnoughLowercase: (str) => {
if ((str.match(/[a-zA-Z]/g)||[]).length > 3
&& str.length - str.replace(/[a-z]/g, '').length) {
return true;
}
return false;
}
};
I then have an Object that would use this as a mixin:
Rule.js
class Rule {
constructor(release) {
this.release = release;
this.errors = [];
}
_recordError(error, options) {
this.errors.push({
release_id: this.release.id,
rule: error,
options: options,
});
}
}
module.exports = Rule;
i then have an index page that joins them together
index.js
const TooManyCaps = require('./TooManyCaps');
const Rule = require('./Rule');
Object.assign(Rule.prototype, [TooManyCaps]);
module.exports = Rule;
And then my main start of the program that does some instantiating of things:
'use strict';
const RuleValidator = require('./job/validation/RuleValidatorMixin');
const Rule = require('./job/validation/rulesmixins/rules/index');
// some logic that's a loop
arr.forEach((value) => {
new RuleValidator(new Rule(value)).validate();
}
and within validate() I have:
validate() {
console.log('VALIDATE');
this.rule.labelCopyCaps();
// console.log(this.rule);
}
But then when I run this, I get:
this.rule.labelCopyCaps is not a function
So where have i gone wrong?
Object.assign does not take an array:
Object.assign(Rule.prototype, [TooManyCaps]);
// ^ ^
should be just
Object.assign(Rule.prototype, TooManyCaps);
Im reading an url of the app http://localhost/?config=preprod
Im trying to create a Singleton service which reads UrlParameters.js and exposes get(key) method. Which stores config=preprod
Similar below (from my Angular 1.x singleton service)
get: function (key) {
if (!params) {
params = {};
var queryString = window.location.search.substring(1);
_(queryString.split('&')).each(function (param) {
var val = param.split('=');
params[val[0]] = val[1];
});
}
return params[key];
}
Now, I think I also will need access to Route params inside this service in Angular 2, since I cannot do the in Angular 2.
Also, I need to share this UrlParams singleton with another Singleton service called Flag. Which reads Flag.get('config')
Something like below (extracted from my Angular 1.x project)
Flag.js
set: function (flag) {
if (UrlParameter.get(flag)) {
localStorage.setItem(flag, UrlParameter.get(flag));
}
},
get: function (flag) {
return localStorage.getItem(flag);
}
As suggested by #JordanFrankfurt I used Location service, and fits my purpose. Also Thanks to #Günter Zöchbauer for the efforts.
Below is my UrlParams Service which is been also added in NgModule under providers
url-parameter.service.ts
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/filter';
import {LocationStrategy} from '#angular/common';
#Injectable()
export class UrlParameterService {
public params = null;
constructor(private location: LocationStrategy) {}
get(key:string):String {
debugger;
if (!this.params) {
this.params = {};
var queryString = this.location.path();
queryString.split('&').forEach((param) => {
var val = (param.indexOf('?') ? param.slice(param.indexOf('?')+1).split('=') : param.split('='));
this.params[val[0]] = val[1];
});
}
return this.params[key] || false;
}
}
I would try to stay within the Angular 2 conventions, but if you simply want an instance of something you've instantiated outside of Angular 2 conventions, it's pretty simple.
var UrlParameters = function() {
this.instance = this;
this.params = null;
this.get = function(key) {
if (!this.params){
params = {};
var queryString = window.location.search.substring(1);
_(queryString.split('&')).each(function (param) {
var val = param.split('=');
params[val[0]] = val[1];
});
this.params = params;
}
return this.params[key];
};
this.set = function() {
}
}
var Flag = {
set: function (flag) {
var urlParams = UrlParameter.getInstance();
if (urlParams.get(flag)) {
localStorage.setItem(flag, UrlParameter.get(flag));
}
}
}
TypeScript version
class UrlParameter {
static instance:UrlParameter;
constructor() {
UrlParameter.instance = this;
}
get( key: string) : string {
// ...
}
}
class Flag {
set(key:string) : string {
if (UrlParameter.instance.get(key)){
// you have it
}
}
}
This might do what you want:
#Injectable()
class MyService {
constructor(router:Router) {
this.router.events
.filter(e => e instanceof NavigationEnd)
.forEach(e => {
var config = router.routerState.root.snapshot.param['config'];
console.log(config);
});
}
}
I'm currently designing an application and have some classes I'm extending. Below is a brief sample code of how it looks today, as well as where I want to go (aka one file, multiple classes and export them + consume them in main.js - or any other)..
TODAY
main.js
const UrgentTask = require('./urgentTask');
const Task = require('./task');
var ut = new UrgentTask({ name: "Some task", priority: "URGENT" });
var nt = new Task({ name: "Normal task" });
console.log(ut.toString());
console.log(nt.toString());
task.js
'use strict'
class Task {
constructor(data) {
this.name = data.name;
this.completed = false;
}
complete() {
console.log('completing task: ' + this.name);
this.completed = true;
}
save() {
console.log('Saving task: ' + this.name);
}
toString() {
return this.name + ' ' + this.completed;
}
}
module.exports = Task;
urgentTask.js
'use strict'
var Task = require('./task');
// Decorate "TASK"
class UrgentTask extends Task {
constructor(data) {
super(data);
this.priority = data.priority;
}
toString() {
return `[${this.priority}] ${super.toString()}`;
}
}
module.exports = UrgentTask;
WHAT I WOULD LIKE
main.js
const { Task, UrgentTask } = require('./task');
var ut = new UrgentTask({ name: "Some task", priority: "URGENT" });
var nt = new Task({ name: "Normal task" });
console.log(ut.toString());
console.log(nt.toString());
task.js
=> this would ideally export the two classes, but I don't know how to?
What I already tried:
module.exports = Task;
module.exports = UrgentTask;
But this blows up in node.
WHAT I WOULD LIKE
const { Task, UrgentTask } = require('./task');
That's a destructuring assignment, which assigns object properties to discrete bindings (constants, in this case).
So you need to export an object:
ES2015+ syntax (but using Node modules, not ES2015 modules):
module.exports = {Task, UrgentTask};
ES5 and earlier syntax:
module.exports = {Task: Task, UrgentTask: UrgentTask};
Actually, by default, exports already is an object so you can also do this:
module.exports.Task = Task;
module.exports.UrgentTask = UrgentTask;
But replacing it with a new object is fine too.
Simple non-Require example:
function getMyStuff() {
class Task { }
class UrgentTask extends Task { }
return {Task, UrgentTask};
}
const {Task, UrgentTask} = getMyStuff();
const ut = new UrgentTask();
console.log(ut instanceof UrgentTask); // true
console.log(ut instanceof Task); // true
NodeJS example:
mymodule.js:
class Task { }
class UrgentTask extends Task { }
module.exports = {Task, UrgentTask};
myapp.js:
const {Task, UrgentTask} = require("./mymodule.js");
const ut = new UrgentTask();
console.log(ut instanceof UrgentTask); // true
console.log(ut instanceof Task); // true