Node.js classes as modules - javascript

I am trying to make my application more object orientated. for this i want to create the following class (object):
in the file Media.js
//Media object
var Media = function (file, targetDirectory) {
this.file = file;
this.targetDir = targetDirectory;
this.fileName = this.getName();
};
Media.prototype.isVideo = function () {
return this.file.mimetype.indexOf('video') >= 0;
};
Media.prototype.isAudio = function () {
return this.file.mimetype.indexOf('audio') >= 0;
};
Media.prototype.getName = function () {
return this.file.originalname.substr(0, this.file.originalname.indexOf('.'))
};
I wish to use this object in serveral places of my application however im not quite sure how to include it. Also is this a good idea or should i use Modules instead?

You can export your Media object as follows in Media.js
module.exports = Media;
then simply require Media.js when you need it
const Media = require('pathtofile/Media.js')
Media.isAudio(a, b);

Related

Node.js: Exported function "is not a function" in one js file, but not another

So one of my files has a function that I need two of my other files to access. I am exporting this function with module.exports = {}. For some reason, one of my files is able to call this function, while I get a commands.commandRouter is not a function error when trying to call it from the other file. Here's basically what I've got going on:
commands.js
function commandRouter(commandName, commandType) {
if (commandType == 'sound') {
console.log(`${commandName} is a sound command, executing sound function`)
playAudio.playAudio(commandName.substring(1));
}
}
module.exports = {commandRouter}
main.js
const commands = require('./modules/commands.js');
const secondary = require('./modules/secondary.js');
client.on('message', (channel, tags, message, self) => {
if(message.charAt(0) == '!'){
console.log('Trigger character identified');
if(commands.commandList.hasOwnProperty(message.toLowerCase())) {
console.log('Valid command identified')
if (commands.commandList[`${message}`] == 'random' ) {
console.log('Random-type command identified')
secondary.randomSelectPropery(message.toLowerCase().substring(1));
}
else
{
console.log('Regular command identified')
commands.commandRouter(message, commands.commandList[`${message}`]);
}
}
}
}
commands.commandRouter(paramA, paramB); works just fine in this instance
secondary.js
const commands = require('./commands.js');
var randomSelectPropery = function (commandObject) {
randomObject = eval(commandObject);
var keys = Object.keys(randomObject);
console.log(randomObject)
console.log(`This object has ${keys.length} commands to choose from`);
var newCommandName = Object.getOwnPropertyNames(randomObject)[keys.length * Math.random() << 0];
console.log(newCommandName)
var newCommandType = randomObject[`${newCommandName}`]
console.log(newCommandType);
commands.commandRouter(newCommandName, newCommandType);
};
const perfect = {
"!perfectqube": "sound",
"!perfectsf2": "sound",
};
module.exports = { perfect, randomSelectPropery }
Here, commands.commandRouter(paramA, paramB); give the commands.commandRouter is not a function error.
File structure is as follows:
.\folder\main.js
.\folder\modules\commands.js
.\folder\modules\secondary.js

Converting AVVideoComposition initializer to Nativescript

Looking for some help on porting this objective-c class method to JS/nativescript.. every variation I've tried has resulted in a TypeError: undefined is not a function...
https://developer.apple.com/documentation/avfoundation/avvideocomposition/1389556-init
Which I've tried to write in JS as:
const videoComp = AVVideoComposition.alloc().initWithAssetApplyingCIFiltersWithHandler(asset, (request) => { ... });
//OR
const videoComp = AVVideoComposition.alloc().initAssetApplyingCIFiltersWithHandler(asset, (request) => { ... });
//OR
const videoComp = AVVideoComposition.alloc().initAssetApplyingCIFiltersWithHandlerApplier(asset, (request) => { ... });
//OR
const videoComp = new AVVideoComposition(asset, (request) => { ... });
to name a few. essentially, I am trying to port this code to nativescript/JS:
let blurRadius = 6.0
let asset = AVAsset(url: streamURL)
let item = AVPlayerItem(asset: asset)
item.videoComposition= AVVideoComposition(asset: asset) { request in
let blurred = request.sourceImage.clampedToExtent().applyingGaussianBlur(sigma: blurRadius)
let output = blurred.clampedToRect(request.sourceImage.extent)
request.finish(with: output, context: nil)
}
found in this blog post: https://willowtreeapps.com/ideas/how-to-apply-a-filter-to-a-video-stream-in-ios
It should look something like this with JavaScript / Typescript,
let blurRadius = 6.0;
let asset = AVAsset.assetWithURL(streamURL);
let item = AVPlayerItem.alloc().initWithAsset(asset);
item.videoComposition = AVVideoComposition.videoCompositionWithAssetApplyingCIFiltersWithHandler(asset, request => {
let blurred = request.sourceImage.imageByClampingToExtent().imageByApplyingGaussianBlurWithSigma(blurRadius);
let output = blurred.imageByClampingToRect(request.sourceImage.extent);
request.finishWithImageContext(output, null);
});
Note: The code is untested and merely a translation of given native code. Make use of tns-platform-declarations for IntelliSense support.

load different module on preferences

I would like to process an array of image files. When selecting them I can choose between selecting them randomly or one by one (queue). The decision is hold by the config.json.
First I initialize the processor and select the right image selection module by calling processImages and pass in the array of image files.
function processImages(images) {
const imageSelector = getImageSelector();
imageSelector.init(images); // initialize the module
console.log(imageSelector.getImage()); // test
}
function getImageSelector() {
const { random } = config;
const selector = random ? 'randomSelector' : 'queueSelector';
return require(`./imageSelectors/${selector}.js`);
}
The modules itself have their own logic to return the next image. For the random module I go for
let images;
module.exports = {
init: images => {
init(images);
},
getImage: () => {
return getImage();
}
};
function init(images) {
this.images = images;
}
function getImage() {
const index = getRandomIndex();
return images[index];
}
function getRandomIndex() {
const indexValue = Math.random() * images.length;
const roundedIndex = Math.floor(indexValue);
return images[roundedIndex];
}
and for the queue module I go for
let images;
let currentImageCounter = 0;
module.exports = {
init: images => {
init(images);
},
getImage: () => {
return getImage();
}
};
function init(images) {
this.images = images;
currentImageCounter = 0;
}
function getImage() {
const index = getNextIndex();
return images[index];
}
function getNextIndex() {
if (currentImageCounter > images.length)
currentImageCounter = 0;
else
currentImageCounter++;
return currentImageCounter;
}
When I run the code and random is true I get this error
C:...\imageSelectors\randomSelector.js:22
const indexValue = Math.random() * images.length;
TypeError: Cannot read property 'length' of undefined
When calling imageSelector.init(images) some image items are available so they just are undefined within the modules.
I think I missunderstood how to work with modules correctly. Could someone tell me how to setup the code correctly?
In your module, you declare a local variable images and use it as an object field this.images which is not right. Try this approach and do not shadow the upper-level variables with deeper-level variables with the same names to not be misled (i.e. use images as outer variable and something like imgs as function parameters). I've also a bit simplified your module code to avoid some unneeded duplication.
let images;
module.exports = {
init(imgs) {
images = imgs;
},
getImage() {
const index = getRandomIndex();
return images[index];
}
};
function getRandomIndex() {
const indexValue = Math.random() * images.length;
const roundedIndex = Math.floor(indexValue);
return images[roundedIndex];
}

How to get utility function from helper file on node.js server?

I have a node/express server and I'm trying to get a function from a helper file to my app.js for use. Here is the function in the helper file:
CC.CURRENT.unpack = function(value)
{
var valuesArray = value.split("~");
var valuesArrayLenght = valuesArray.length;
var mask = valuesArray[valuesArrayLenght-1];
var maskInt = parseInt(mask,16);
var unpackedCurrent = {};
var currentField = 0;
for(var property in this.FIELDS)
{
if(this.FIELDS[property] === 0)
{
unpackedCurrent[property] = valuesArray[currentField];
currentField++;
}
else if(maskInt&this.FIELDS[property])
{
//i know this is a hack, for cccagg, future code please don't hate me:(, i did this to avoid
//subscribing to trades as well in order to show the last market
if(property === 'LASTMARKET'){
unpackedCurrent[property] = valuesArray[currentField];
}else{
unpackedCurrent[property] = parseFloat(valuesArray[currentField]);
}
currentField++;
}
}
return unpackedCurrent;
};
At the bottom of that helper file I did a module.export (The helper file is 400 lines long and I don't want to export every function in it):
module.exports = {
unpackMessage: function(value) {
CCC.CURRENT.unpack(value);
}
}
Then in my app.js I called
var helperUtil = require('./helpers/ccc-streamer-utilities.js');
and finally, I called that function in app.js and console.log it:
res = helperUtil.unpackMessage(message);
console.log(res);
The problem is that the console.log gives off an undefined every time, but in this example: https://github.com/cryptoqween/cryptoqween.github.io/tree/master/streamer/current (which is not node.js) it works perfectly. So I think I am importing wrong. All I want to do is use that utility function in my app.js
The unPackMessage(val) call doesn't return anything:
module.exports = {
unpackMessage: function(value) {
CCC.CURRENT.unpack(value);
}
}
you need to return CCC.CURRENT.UNPACK(value);
module.exports = {
unpackMessage: function(value) {
return CCC.CURRENT.unpack(value);
}
}

AngularJS service inheritance issues

I have a base service which looks like this:
.service('BaseImageService', ['$q', 'ApiHandler', 'UploadService', function ($q, api, uploadService) {
// Get our api path
var apiPath = 'logos';
// Creates our logo
var _createLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.post(apiPath, model);
});
};
// Edit our logo
var _editLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.put(apiPath, model);
});
};
// Handles our files
var _handleUploads = function (model) {
// Create a promises array
var promises = [];
// Get our file
var file = model.file,
old = model.old;
// If we have a file
if (file) {
// Try to upload the file
promises.push(uploadService.upload(model.file).then(function (response) {
// Update our model
model.path = response.path;
model.thumbnail = response.thumbnail;
}));
// If we have an old model
if (old) {
// Delete both our files
promises.push(uploadService.delete(old.path));
promises.push(uploadService.delete(old.thumbnail));
}
}
// After all promises have completed
return $q.all(promises);
};
// Create our service
var service = {
// Update our api path
updateApiPath: function (path) {
// Set the api path
apiPath = path;
},
// Gets a list of logos
list: function (t) {
if (t) {
console.log(apiPath);
}
// Get our logo
return api.get(apiPath);
},
// Get a single logo
get: function (id) {
// Get our logo
return api.get(apiPath, { id: id });
},
// Create our logo
save: function (model) {
// If we are editing
if (model.id) {
// Edit our logo
return _editLogo(model);
// If we are creating
} else {
// Create our logo
return _createLogo(model);
}
},
// Deletes our logo
delete: function (id) {
// Delete our logo
return api.delete(apiPath, { id: id });
},
// Prepare for editing
prepareForEditing: function (model) {
// Create our old object
model.old = {
path: model.path,
thumbnail: model.thumbnail
};
}
};
// Return our service
return service;
}])
and then I have a few services which "inherit" this service, like this:
.service('ImageService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'images';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
.service('LogoService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'logos';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
.service('PlayerTextService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'playerText';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
I thought that this was working fine. But I have this page that calls all 3 services (ImageService, LogoService and PlayerTextService) sequentially. On the first view of the page everything is fine, if I navigate away and then come back the images service actually pulls back thing from the player text service. Now I know this is because of services being singletons but I am not sure how to fix my issue.
Can anyone give me a hand?
I have added a codepen with an attempted solution:
http://codepen.io/r3plica/pen/ONVBJO
Attempt 2
http://codepen.io/r3plica/pen/jqPeMQ?editors=1010
The solution you tried doesn't work because the BaseService is a singleton. So you inject exactly the same instance into all three service registration functions and all of them configure the same object. So basically the last one wins.
Looks like you want to have separate services with different configurations. This is what providers are used for. They allow a two-step process of building a service instance. Please see this great Stackoverflow answer on the topic:
AngularJS: Service vs provider vs factory
For reference, Restangular is a library that needs to achieve exactly the same as you want. You could use this as a blueprint and see how Restangular handles this requirement:
https://github.com/mgonto/restangular#how-to-create-a-restangular-service-with-a-different-configuration-from-the-global-one
Please be aware that these concepts are based on AngularJS 1 and you need to handle this differently when you want to use AngularJS 2 later on.
After a lot of messing around; I finally found a solution adapting this bit of code
My base service looks like this:
.factory('BaseImageService', ['$q', 'ApiHandler', 'UploadService', 'vectorExtensions', function ($q, api, uploadService, vectorExtensions) {
// Creates our logo
var _createLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.post(BaseImageService.apiPath, model);
});
};
// Edit our logo
var _editLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.put(BaseImageService.apiPath, model);
});
};
// Handles our files
var _handleUploads = function (model) {
// Create a promises array
var promises = [];
// Get our file
var file = model.file,
old = model.old;
// If we have a file
if (file) {
// Try to upload the file
promises.push(uploadService.upload(model.file).then(function (response) {
// Update our model
model.path = response.path;
model.thumbnail = response.thumbnail;
model.fileName = response.fileName;
}));
// If we have an old model
if (old) {
// Delete both our files
promises.push(uploadService.delete(old.path));
promises.push(uploadService.delete(old.thumbnail));
}
}
// After all promises have completed
return $q.all(promises);
};
// Addes a property to the image array to state if they are vector images or not
var _addVectorProperties = function (images) {
// Loop through our images
for (var i = 0; i < images.length; i++) {
// Get our current image
var image = _addVectorProperty(images[i]);
}
// Return our images
return images;
};
// Adds a property to the image to state if it is vector or not
var _addVectorProperty = function (image) {
// Vector flag
var vector = false;
// Get our file extension
var parts = image.path.split('.');
// If we have any parts
if (parts.length) {
// Get our last part
var ext = parts[parts.length - 1],
index = vectorExtensions.indexOf(ext);
// If our extension exists in our vector array
if (index > -1) {
// Change our vector property
vector = true;
}
}
// Update our image with the new property
image.vector = vector;
// Return our image
return image;
};
// Create our service
var BaseImageService = function (path) {
// Set our apiPath
this.apiPath = path;
// Update our api path
this.updateApiPath = function (path) {
// Set the api path
apiPath = path;
};
// Gets a list of logos
this.list = function () {
// Get our logo
return api.get(this.apiPath).then(_addVectorProperties);
};
// Get a single logo
this.get = function (id) {
// Get our logo
return api.get(this.apiPath, { id: id }).then(_addVectorProperty);
};
// Create our logo
this.save = function (model) {
// If we are editing
if (model.id) {
// Edit our logo
return _editLogo(model);
// If we are creating
} else {
// Create our logo
return _createLogo(model);
}
};
// Deletes our logo
this.delete = function (id) {
// Delete our logo
return api.delete(this.apiPath, { id: id });
};
// Set our active image
this.setActive = function (images, image) {
// Loop through our images
for (var i = 0; i < images.length; i++) {
// Get our current image
var current = images[i];
// Set whether we are active or not
current.active = image.id === current.id ? true : false;
}
};
// Prepare for editing
this.prepareForEditing = function (model) {
// Create our old object
model.old = {
path: model.path,
thumbnail: model.thumbnail
};
};
};
// Return our service
return BaseImageService;
}])
and the child services look like this:
.service('ImageService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('images');
// Return our new service
return child;
}])
.service('LogoService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('logos');
// Return our new service
return child;
}])
.service('PlayerTextService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('playerText');
// Return our new service
return child;
}])
That works fine.
Yes it append because it's singleton. You have to perform inheritance if you want to do this.
Here is a code that i use and append to angular :
angular.baseResourceServiceMaker = function(service){
return ['$injector', '$resource', 'TypeService', '$http', '_', 'BackEndpoint',
function($injector, $resource,TypeService, $http, _, BackEndpoint){
//skipping not interesting code
// sample fields to inherits
this.sample = "test";
this.sampleFN = function(){[...]}
// THE line that does the magic
$injector.invoke(service, this);
}
Now time of usage
.service('MyService',angular.baseResourceServiceMaker(['$http', function($http){
// overriding fields
this.sample="inherits";
this.sampleFN = function(){[...]}
}]));
So basically what do we have here ? A function baseResourceServiceMaker which represent a generic particular service. The $injector that call the service we want to instantiate and set the scope to the generic service, so the this on the child class will bind to the same reference than the generic class. The generic service will be instantiated as many times you call it, no confict.
I personally use this code for the resource module of angular to define some basic methods having a custom serializer / deserializer than handle dates and some other stuffs. In your case the baseResourceServiceMaker will be your baseImageService with ending with the $injector.invoke(service, this).
EDIT : found a link with something probably cleaner : AngularJS service inheritance
It becomes very easy if you use (or switch to) ES6 or TypeScript.
export class Base {
// . . .
}
Then:
import {app} from '../app';
import {Base} from './base';
export class Child extends Base {
// . . .
}
app.service('child', Child);
From your Attempt 1:
your BaseService looking for apiPath at global level,
while angular preparing dependency your last dependency is ImageService,
first it will prepare dependency then it will execute list() method,
all ways your apiPath will refer global level declared value, i.e apiPath = 'images'; from step2
Solution: use this operator in front of apiPath under BaseService and list().
working Plunker

Categories

Resources