Merge two json objects on the server side - javascript

I have inherited an express application. In the application we pass to res.render a massive list of local variables. For every page we pass about 30 variables that do not change. If one does change it needs to be changed in a dozen places. This is obviously bad.
So what I want to do store the values locals that do not change separate from the truly local. So I placed these non-changing values in their own file and load the file at the start of each route, like so:
'use strict';
var locals =
{
indexName: 'Home',
...lots more of these...
};
module.exports = { locals : locals };
// in each route files
var local = require('../locals.js');
And I can use it via res.render('sensor', local.locals);
However I also need to add page specific values. So I tried local.locals + { ... }; which doesn't while it doesn't give an error doesn't even show the original values.
I then tried local.locals.concat({...}) but that does give an error (TypeError: Object #<Object> has no method 'concat'), likewise for extend and push.
Is there no methods to extend or merge two objects? Do I need to roll my own?
Also, is this the best way of making the an array global? I would prefer just to call it locals, and not local.locals as that is just cumbersome.

In addition to Object.assign from #mostruash, there are two JS libraries that are very similar, which both provide an object merge function (along with a lot of nice helper utilities). Pick one:
underscore
lodash
Edit: and as to your second question about local.locals...of course, just export the object itself, rather than an object that wraps it:
module.exports = locals;
...and in your routes:
var locals = require('../locals');
console.log(locals.indexName);

Related

Access the request object from Express inside a Mongoose Plugin

I have an API in ExpressJS and a middleware that gets executed before each endpoint controller:
app.use(segregationMiddleware);
app.get('/some-endpoint', controller1);
app.get('/some-endpoint-2', controller2);
The segregationMiddleware is used to look for some parameters in the request and then it calculates a value that then is stored in the request object as req.locals.domain so the controllers can access it.
In each Mongoose model, I define a field named domain using a Mongoose plugin (so I don't have to do it every time). That field is used to segregate my assets. This means that when the segregationMiddleware populates req.locals.domain = 'foo' for example, if I make a model.find({}) I want to get only assets that have { domain: 'foo' }. Same thing if I try to update, save, delete, and so.
Of course, I can just simply modify the query on each controller since I have accesso to req, but I need to do it every time and I need to remember it for finds, findAndUpdate, save, and soo... sooner or later I'm gonna forget it.
I can define some hooks in Mongoose that will modify the query using a plugin so it adds the domain constraint to the query so I don't have to do it in the controller BUT I don't have the current req object in the Mongoose plugin unless I pass it, and the only way that come to my mind is to abstract the DB methods in the plugin, so in the controller, I do something like this:
model.safeFind(req, query);
And in the plugin I define safeFind like:
safeFind = () => {
const theRealQuery = Object.assign({}, query, { domain: req.locals.domain });
return this.find(query);
}
BUT, in this way, I need to redefine each DB query function (find, findOne, update, save...) and I need to remember to use the safe methods. Then again, I'm going to forget it sooner or later.
Is there a way I can still use the regular Mongoose methods from the controller and have the plugin somehow modify the query for every method using the current req object?

Why use AngularJs .constant() if I can declare JS const?

I'm working on an AngularJS project where there is a .constant() provider to declare some basic information used across the whole project. For example, a definition of cookie name. Ex.:
.constant('appConst', {
cookie: 'CookieName',
...
});
But the same thing can be done by declaring a const, ex.:
const appConst = {
cookie: 'CookieName',
...
}
So, what is the advatage of using the .constant provider instead of just declaring a const? I know one of the reasons is because we don't expect the value to change. But isn't this the same objective of a const?
The new const keyword only makes it so you cannot reassign the variable, it doesn't make any object you initially assign to it immutable. So in your example with:
const appConst = {
cookie: 'CookieName',
...
}
You would still be able to change the value of cookie. You just wouldn't be allowed to do something like this:
appConst = { // My new object };
The values in the angular .constant() can also still be changed, so they're not constant in the common use of the word "constant". At least not when you use it like this:
.constant('appConst', {
cookie: 'CookieName',
...
});
So if you for instance do like this and change the value within a controller
app.controller('myController', function(appConst){
appConst.cookie = 'NewCookieName';
})
the change would be reflected anywhere you inject appConst after this controller was constructed.
You can't "reassign" appConst in this case though, that action would just be ignored, so it is constant in that sense.
1- const is new in ES6, so you may need to transpiler your code for supporting old browsers.
2- const is block-scoped, so within a scenario, you define a constant in A.js, will be not able to use it at B.js unless you're using a module bundler, so we went back to the topic 1-.
The main purpose of AngularJS having this native is to able you to share it between controllers, services, and directives, using its dependency injection system.

Load includes on existing model

I'm trying to load includes on an existing model in sequelize. In express we pre check the models to see if they exist in the middleware.
So once we're in the actual "controller" we want to run some includes on that existing model that is passed in.
req.models.item.incude([
{model: Post, as: 'posts'}
])
Is there any way to accomplish this?
EDIT:
I know we can do something like this.
return req.models.item.getThing()
.then(function (thing) {
req.models.item.thing = thing;
return req.models.item;
});
But:
My expansions for includes are a dynamic property that come via url parameters, so they are not know ahead of time.
It I return the above you will not see the "thing" in the response. I need it nicely built as part of the original instance.
Something like a .with('thing', 'other.thing'); notation would be nice. Or in the case of sequelize .with({include: ...}); or .include([{model: ...}]);
If the variable req.models.item is already an Instance but without its other related instances ("includes"), then you could include them using something like the following code:
Item.findAll({
where: req.models.item.where(),
include: [{
model: SomeAssociateModel,
}]
})
.then(function(itemWithAssoc) {
// itemWithAssoc is an Instance for the same DB record as item, but with its associations
});
See here for some documentation. See here for a script demo'ing this.
Update: Given the instance, how do I just get the associated models?
To do this just use the automatically generated "getAssociation" getter functions, e.g.:
function find_associations_of_instance(instance) {
return instance.getDetails();
}
I've updated the script to include this as an example. For more information on these functions, see the SequelizeJS docs.

Dependency Injection in a distributable Javascript library?

We are using Backbone to create reusable components. We create controllers in order to setup bindings between models and views. We wish to offer people the ability to replace the models and views with their own implementations.
Since the majority of people will use the the components we provide, I don't want to force developers to configure or create anything that isn't different from the defaults.
This means that someone should be able to pass an instance of an object they want to use as a model or view to the controller, all configured and setup and ready to go, or they can pass in some configuration to what the controller will use by default.
I am not sure what the best approach is.
// Idea #1
var controller = new Controller({
dependencyA: {
conf: { // config for depedencyA }
},
dependencyB: {
conf: { // config for dependencyB }
class: custom.implement.Class
}
});
In this approach, the user doesn't have control over how to instantiate the object. What's bad about this is, for example, Backbone models take two arguments in the constructor while views only take one.
// Idea #2
var controller = new Controller({
dependencyA: {
args: ['arg1',{
opt1: 'opt-value',
}]
},
dependencyB: {
args: ['a','b','c']
class: custom.implement.Class
}
});
Args would be the arguments passed to a constructor. This means the controller calls the constructor with the args array, and again this only really benefits you if you're passing in custom configuration for default dependencies. If you want to pass your own implementation it's more awkward.
// Idea #3
var controller = new Controller({
dependencyA: new outOfBoxModel({ // configuration }),
dependencyB: new custom.imeplement.Class('a','b','c')
});
In this approach, the user is forced to instantiate the out of box model. If the model's default settings are all appropriate though, then the user is doing unnecessary work. The only bit they HAVE to do is create an instance of their own custom implementation.
I am not sure what the best approach would be here?
Of the three approaches, I most prefer approach number 3. Here is why:
It is more consistent than the other approaches. In the 3rd approach, the user only has to learn to pass in constructed instances of dependencies into the controller. In the other approaches, the user has to pass in either args, or args and a class name.
It does not violate the Single Responsibility Principle. In the first two approaches, your controller is made responsible for constructing and configuring its dependencies. This doesn't feel like dependency injection at all! I think it's better, and simpler, to leave the construction of dependencies to the user or another part of your application. In my opinion, its not a terrible thing to force the user to construct their own implementations - it gives them the freedom to define their constructors however they want, rather than forcing you to define and maintain constructor APIs for the Controllers dependencies, and forcing the user to conform to them.
A different idea:
If you have this freedom in your application, I would consider putting your Controller construction logic in a factory class or method:
var createController = function(config) {
// Parse, validate, extract relevant config items
// var a = create dependency a
// var b = create dependency b
return new Controller(a, b);
}
This approach allows you to be as fancy as you want with your definition of config - you could support all three of the config definitions you provided in your original post - although I wouldn't recommend that :-). At a minimum, I would have the factory method support a zero args invocation (in which case it would return the default construction of Controller) and one of your preferred config definitions.

Ember.js views (unlimited number)

so I need to be able to support an (finitely) unlimited number of views in ember.
Basically, I'm creating a survey app. The survey can have an undefined number of steps, hence an undefined number of views/controllers. The number of steps is got from the server, along with the content and the handlebars template (there are only a finite number of possible content types for a step), and I need some way of being able to extend the survey for the different surveys. So basically one ember app handles the entire thing, I've managed to abstract my code for rendering the content types out enough that it doesn't matter for the ember step: i now just need to make it support an unlimited number of steps
Is it possible to have ember views and controllers, but instead of referencing them by name, reference them by array indice? Like normally you'd go App.TestView = …, and router.get('applicationController').connectOutlet('test'), but could I use App.AllView[0] = Ember.View.extend(); and router.get('applicationController').connectOutlet('test')[0] or something? Then I can have a for loop at the start, which grabs the survey data which contains the content types and number of steps, plug it in a view array, and we're away
There might be other ways to achieve this, so any solutions would be great. Creating a new ember app is not an option, the same app needs to service whatever is passed in as a survey object.
You could create an array of view classes that contains the different steps. You can add new views to the array using the handlebars template name.
App.surveyViews = [];
App.surveyControllers = [];
App.surveyViews['firstStep'] = Em.View.extend({ templateName: 'my-handlebars-template' });
App.surveyControllers['firstStep'] = Em.Controller.extend();
Your route can take in the step from the route and use that to look up the appropriate view class and controller to use for the connectOutlet.
step: Em.Route.extend({
route: '/:step',
connectOutlets: function(router, context) {
router.get('applicationController').connectOutlet({
viewClass: App.surveyViews[context.step],
controller: App.surveyControllers[context.step].create(),
context: {}
});
}
})
You can add any extra logic you need for the context, etc., but that would be the basic idea.

Categories

Resources