Edit or Remove BreezeJS EntityManager Once Instance Reference Lost - javascript

I'm constructing a CRM application with a SPA structure, using BreezeJS and AngularJS, and I'm utilizing a dynamically-generated tabbed environment to display what I'll refer to here on out as modules. When a user clicks a side menu item, a new tab is created, and an HTML template (aka module) is loaded into the new content area. While some of the module types are to be opened only once at a time (a grid of Accounts), others, such as an Account Editor module, can be opened many times. That way, the user can modify many accounts at any given time throughout the day, but always be doing so from a single Accounts grid instance.
So far, I have a working system for the Account Editor module, in that I create a master Breeze EntityManager with appropriate configuration parameters (service name, save options, etc.) and then make a copy of it any time a new Account Editor is created, using masterManager.createEmptyCopy() (as per the code outlined at http://www.breezejs.com/documentation/multiple-managers#CreateMultipleManagers):
var serviceName = "/breeze/accounts";
var ds = new breeze.DataService({
serviceName: serviceName,
hasServerMetadata: true
});
var masterManager = new breeze.EntityManager({
dataService: ds,
saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false })
});
function createManagerCopy() {
// same configuration as master; no entities in cache.
var sandboxManager = masterManager.createEmptyCopy();
return sandboxManager;
}
Then, I call an EntityQuery, by passing in the copied EntityManager and entity Id (key), in order to get the appropriate Account and populate each open editor with apparently all the benefits of Breeze.
function queryAccountByKey(mgr, key) {
var keyPredicate = breeze.Predicate.create('id', 'eq', key);
var query = new breeze.EntityQuery('AccountsBase')
.expand('ContactsBase')
.where(keyPredicate);
var promise = mgr.executeQuery(query)
.catch(queryFailed);
return promise;
function queryFailed(error) {
console.log('Query Account by Id Failed', error);
return $q.reject(error); // so downstream promise users know it failed
}
}
There does not appear to be any conflict with the other open editors and their respective entity managers, so long I maintain the copied EntityManager in the module's Angular scope. Editing and saving this way is, well…a breeze! :P (sorry)
The problem I’m having is when I switch to another Angular route, such as a login screen, and then come back to the home screen. Due to the complexities of each tabbed module, any Account Editor module I had opened before the routing took place must be reloaded from stored settings (even if the layout is stored in the cache). However, then there are two Breeze entity managers handling that account. The effect is that saving changes for a single Account Editor now commits twice (or however many times you’ve gone away and back from the home layout).
What I’m trying to figure out is how to get access to a specific EntityManager instance, from the client, once I navigate back to the home layout and the original instance reference (in the scope, in my case) is lost. In other words, is there an EntityManager collection that I can query to reuse or delete an instance? If I can grab a manager instance by name or other Id, I can simply reassign it to my scope without removing and recreating it.
In the event that I do need to remove the EntityManager, I can’t find anything anywhere to describe implementing something like a destroy() method…just a clear() method, which only clears the entities and does not remove the EntityManager from the client. Of course, if I'm going about this all wrong, please advise as to a better approach. Hopefully I've explained things clearly enough that someone can lend a possible solution.
SOLUTION
So, thanks to PW Kad's answer, I was able to reuse the entity managers instead of deleting and re-creating them, by adding them to an empty object collection on the $rootScope when they're initialized (still using the createEmptyCopy() method outlined above). This allows for access throughout the Angular app, without polluting the global namespace. I had already implemented a unique ID to be associated with each tab - and thus the modules in the content areas - so I appended that ID to create a name, such as 'EM_' + instanceId, for storage in the $rootScope.entityManagers object. Later, I can retrieve the EntityManager instance in the $rootScope, using this ID, which is found in each Account Editor's Angular Controller.
Here's the new code:
// NEW: Add an 'entityManagers' object to the $rootScope of my main app module
angular.module('app', [])
.run(['$rootScope', function($rootScope) {
$rootScope.entityManagers = {};
$rootScope.entityManagers.count = 0;
}]);
// In the dataServices factory for the main app module
var serviceName = "/breeze/accounts";
var ds = new breeze.DataService({
serviceName: serviceName,
hasServerMetadata: true
});
var masterManager = new breeze.EntityManager({
dataService: ds,
saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false })
});
function createManager(instanceId) {
// make a copy of the above EntityManager (with no cached entities)
var sandboxManager = masterManager.createEmptyCopy();
// NEW: Save the EntityManager instance to the $rootScope
$rootScope.entityManagers['EM_' + instanceId] = sandboxManager;
$rootScope.entityManagers.count++;
return sandboxManager;
}
// In the event that you want to delete the EntityManager from the $rootScope
function deleteManager(instanceId) {
var manager = $rootScope.entityManagers['EM_' + instanceId];
manager.clear();
delete $rootScope.entityManagers['EM_' + instanceId];
$rootScope.entityManagers.count--;
}
// And lastly, inside any Angular controller
$scope.instanceId = '1234'; // Dynamically-assigned at runtime
$scope.init = function() {
var manager = $rootScope.entityManagers['EM_' + $scope.instanceId];
if (manager === undefined) {
$scope.entityManager =
entityManagerService.createManager($scope.instanceId);
} else {
$scope.entityManager = manager;
}
}
$scope.getEntityById = function(id){
//use $scope.entityManager here to query database via Breeze
}
While I would still like to know where BreezeJS keeps its EntityManager collection, I have a valid solution. I hope it helps someone!

It seems like a poor design choice to reinstantiate a new entity manager every time you change pages as in effect you are losing the caching mechanism and sharing the entities across pages but if you must do so you can always do so fairly trivially with something like -
var manager = {};
manager = manager ? manager.clear() : new breeze.EntityManager();
or
manager = manager ? (function () { delete manager; return new breeze.EntityManager(); })() : new breeze.EntityManager();
or many other ways really.
I would recommend not doing that though and just doing something like this -
var manager = {};
// Some route activation logic
if (!manager) {
manager = new breeze.EntityManager();
}
Edit
Well the short answer is I am not 100% sure how the breeze object in the global namespace is referencing the entity manager. I don't think there is a collection of entity managers that the breeze object keeps, but I may be wrong. I don't see why calling delete on the entity manager isn't working but this should do what you are trying to do -
Somewhere in either one of your closures or in the global namespace create an object called entityManagers. Example -
window.entityManagers = {};
window.entityManagers.count = 0;
Then tack the manager while it is created onto that namespace. There is probably a more dynamic way to do this just giving some pseudo-code -
window.entityManagers.createNewManager = function (name) {
window.entityManagers[name] = new breeze.EntityManager();
}
window.entityManagers.createNewManager('ManagerNumber1');
And then when you want to dispose of a specific instance just clear it then delete it. Get the instance you want either by a variable reference or if you can't do that for some crazy reason just grab it off the affected entity -
window.entityManagers.deleteManager = function (name) {
window.entityManagers[name].clear();
delete window.entityManagers[name];
}
window.entityManagers.deleteManager('ManagerNumber1');
For all intents and purposes, as long as there no other references to that instance of the manager in other modules / controllers / whatever than this should delete the entityManager from the world. I still don't fully understand the use case so take it with a grain of salt.

Related

JavaScript: Is the nesting of constructor instances inside a constructed 'wrapper' problematic?

Hopefully this question won't be flagged as too subjective but I'm newish to OOP and struggling a bit when it come to sharing data between parts of my code that I think should be separated to some extent.
I'm building a (non-geo) map thing (using leaflet.js which is superduper) which has a map (duh) and a sidebar that basically contains a UI (toggling markers both individually and en masse, searching said marker toggles as well as other standard UI behaviour). Slightly confused about organisation too (how modular is too modular but I can stumble through that myself I guess). I am using a simple JSON file for my settings for the time being.
I started with static methods stored in objects which is essentially unusable or rather un-reusable so I went for nested constructors (kinda) so I could pass the parent scope around for easier access to my settings and states properties:
function MainThing(settings) {
this.settings = options;
this.states = {};
}
function SubthingMaker(parent) {
this.parent = parent;
}
SubthingMaker.prototype.method = function() {
var data = this.parent.settings.optionOne;
console.log(data);
this.parent.states.isVisible = true;
};
MainThing.prototype.init = function() {
this.subthing = new SubthingMaker(this);
// and some other fun stuff
};
And then I could just create and instance of MainThing and run MainThing.init() and it should all work lovely. Like so:
var options = {
"optionOne": "Hello",
"optionTwo": "Goodbye"
}
var test = new MainThing(options);
test.init();
test.subthing.method();
Should I really be nesting in this manner or will it cause me problems in some way? If this is indeed okay, should I keep going deeper if needed (maybe the search part of my ui wants its own section, maybe the map controls should be separate from DOM manipulation, I dunno) or should I stay at this depth? Should I just have separate constructors and store them in an object when I create an instance of them? Will that make it difficult to share/reference data stored elsewhere?
As regards my data storage, is this an okay way to handle it or should I be creating a controller for my data and sending requests and submissions to it when necessary, even if that data is then tucked away in simple JSON format? this.parent does really start to get annoying after a while, I suppose I should really be binding if I want to change my scope but it just doesn't seem to be an elegant way to access the overall state data of the application especially since the UI needs to check the state for almost everything it does.
Hope you can help and I hope I don't come across as a complete idiot, thanks!
P.S. I think the code I posted works but if it doesn't, its the general idea I was hoping to capture not this specific example. I created a much simpler version of my actual code because I don't want incur the wrath of the SO gods with my first post. (Yes, I did just use a postscript.)
An object may contain as many other objects as are appropriate for doing it's job. For example, an object may contain an Array as part of its instance data. Or, it may contain some other custom object. This is normal and common.
You can create/initialize these other objects that are part of your instance data in either your constructor or in some other method such as a .init() method whichever is more appropriate for your usage and design.
For example, you might have a Queue object:
function Queue() {
this.q = [];
}
Queue.prototype.add = function(item) {
this.q.push(item);
return this;
}
Queue.prototype.next = function() {
return this.q.shift();
}
var q = new Queue();
q.add(1);
q.add(2);
console.log(q.next()); // 1
This creates an Array object as part of its constructor and then uses that Array object in the performance of its function. There is no difference here whether this creates a built-in Array object or it calls new on some custom constructor. It's just another Javascript object that is being used by the host object to perform its function. This is normal and common.
One note is that what you are doing with your MainThing and SubthingMaker violates OOP principles, because they are too tightly coupled and have too wide access to each other internals:
SubthingMaker.prototype.method = function() {
// it reads something from parent's settings
var data = this.parent.settings.optionOne;
console.log(data);
// it changes parent state directly
this.parent.states.isVisible = true;
};
While better idea could be to make them less dependent.
It is probably OK for the MainThing to have several "subthings" as your main thing looks like a top-level object which will coordinate smaller things.
But it would be better to isolate these smaller things, ideally they should work even there is no MainThing or if you have some different main thing:
function SubthingMaker(options) {
// no 'parent' here, it just receives own options
this.options = options;
}
SubthingMaker.prototype.method = function() {
// use own options, instead of reading then through the MainThing
var data = this.options.optionOne;
console.log(data);
// return the data from the method instead of
// directly modifying something in MainThing
return true;
this.parent.states.isVisible = true;
};
MainThing.prototype.doSomething = function() {
// MainThing calls the subthing and modifies own data
this.parent.states.isVisible = this.subthing.method();
// and some other fun stuff
};
Also to avoid confusion, it is better not to use parent / child terms in this case. What you have here is aggregation or composition of objects, while parent / child are usually used to describe the inheritance.

namespacing a JavaScript class but retaining the same 'this'

I'm building a fairly large node.js client library and I'd like to be able to 'namespace' portions of it to keep it more organized. For example:
var client = new Client(config);
client.activities.get(activityId, function(activity) {
...
});
...
client.user.get(userId, function(user) {
...
});
I'm currently trying to do something like this in the module:
function Client(config) {
this.config = config;
}
Client.prototype.activities = require('./activities');
Client.prototype.user = require('./user');
module.exports = Client;
but when 'get' is called in the activities 'submodule', the "this" is for the module, of course, and not the outer Client function. Basically, both of the submodules need access to the outer configuration information ('config' in this example). What is the best practice around doing this in node.js?
I think a modeling issue with the plan you have is that new X() copies each property reference of X.prototype to the new item; for instance, X.myFunction is the exact same reference as X.prototype.myFunction; but does NOT create a new copy of myFunction.
It sounds like if activities is a part of a Client (the same way StreetAddress might be), you actually want activities to be a Class, not a module, and for Client to create a new instance of it when it's constructed. That's not really something that prototype is useful for. If I'm wrong, maybe you could show an example of a basic operation activities would be used for.

javascript best practice to use one instance of a module globally

I have the javascript modules Node and user.
Node is a class:
define(["underscore", "user"], function(_, User) {
class Node {
// one of the Node attributes needs to access user.prefs in order to figure out what style to output its output in. user should already be initialized at that point, and it is this initialized version of user that Node must access.
}
return Node
}) // end of define
user is not a class:
define(['underscore'], function(_) {
user = {}
function init({username, password}) {
user.username = username
// open oauth stuff with username and password
user.prefs = _.defaults(this._initPrefs(), {
display_name_capitalization: "title", // bla
underline_definitions: false, // blablabla
show_description_on_hover: false, // blabla
})
}
return user
}) // end of define
Then I run everything in main, which grabs the dependencies via RequireJS, initializes user, then creates some Nodes, and then calls that Node attribute which depends on user:
require(["node", "user"], function(Node, user) {
user.init({
username: 'Tim',
password: 'TinyButMighty!',
})
for (n of retrieved_nodes) {
n = new Node(n)
doSomethingWith(n.attribute_that_depends_on_user)
}
}) // end of require
There are some very specific questions that come out of this.
Even though there will only be ONE instance of user, is there a good reason to make it a class? (this is a less important question, and mostly it's importance depends upon its connection to the following question...)
Both Node and main import user. Does that mean there will be TWO copies of user? If I initialize user in main, and then try to access it from Node, will I access that SAME INITIALIZED user?
What is the "best practice" for getting this behavior where there is only one user object that is shared across multiple modules (main, Node, and possibly others)? I was thinking of using window.user = user instead of using return user, but I want to make sure I do things the right way. (It is also important to consider that I am currently using RequireJS, but will soon switch to Browserify. A solution to specific to any one tool could be a bad thing. I am open to using ES6 features that are supported by Babel, and therefore will work today and in the future.)
The answer to question 2 is that only one instance of user will exist. AMD loaders (and CommonJS environments alike) load and execute each module once, then cache its return value.
It follows that the answer to question 3 is that you don't need to do anything special. Exposing a global would be counter-productive (one of the takeaways of modules is that you shouldn't need to pollute the global namespace).
As for question 1, there's no reason to make something a class if it doesn't need to be one, and especially if it's supposed to represent a single instance anyway. Why create a class with a singleton pattern when you can just return a single object anyway? You can already achieve "private" functions simply by defining functions within the closure of the module's factory function, that aren't exposed on the return value.

How does the Pebble watch sandbox user javascript/expose api's?

I'm wondering how one would go about sandboxing user javascript and exposing interfaces without allowing modification of those interfaces? Specifically in a nodejs env. Example:
//public class you can interface (should be immutable)
function InterfaceClass () {
this.x = 0;
thix.y = 0;
}
//executing users code (in a sandbox of some sort)
function userCode () {
//disallow this:
InterfaceClass = function () {
};
//allow this:
var interface = new Interface();
interface.x = 1;
}
The only part of a sandbox that is straightforward to implement is the protection of your interfaces and your own custom Javascript functions.
You can create a situation where there are not any globals of your own that can be modified and the only variables that the user code receives from the outside world are copies.
To do this, put the user code inside a function of your creation (similar to how a node module is loaded) and then pass copies of your API to the user code as arguments to that master function you wrap the user code in (probably passing it an object with properties on the object). Then, all the user code can do is modify the copies, not modify any of the originals so it won't affect any other code.
Using your example:
// interfaces created inside some private scope
(function() {
//public class you can interface (should be immutable)
function InterfaceClass () {
this.x = 0;
thix.y = 0;
}
var api = {Interface: InterfaceClass};
launchUsercode(api);
})();
// user code is wrapped in your own function creating a private scope
function launchUsercode(api) {
//executing users code (in a sandbox of some sort)
function userCode () {
//allow this:
var interface = new api.Interface();
interface.x = 1;
// mucking with api.Interface does not do anything other than
// mess up their own environment
}
userCode();
};
FYI, the only thing this protects is the redefinition of your own functions. This user code is free to do anything any node.js application could do, start up servers, read/write to the file system, shut down the process, fire up child processes, etc... This is not even close to generally secure. That is a much, much harder problem that probably needs full-on firewalled VMs with their own file system and separate processes and lots of process management to solve. That is not an easy task at all.

How to organize models in a node.js website?

I have just started experimenting with building a website using node.js, and I am encountering an issue when organizing the models of my project.
All the real world examples I have found on the Internet are using Mongoose. This library allows you to define your models in a static way. So you can write this:
// models/foo.js
module.exports = require('mongoose').model('Foo', ...);
// app.js
mongoose.connect(...);
// some_controller_1.js
var Foo = require('./models/foo');
Foo.find(...);
// some_controller_2.js
var Foo = require('./models/foo');
Foo.find(...);
But since I don't want to use MongoDB, I need another ORM. And all the other ORMs I have found don't allow this. You first need to create an instance, and then only you can register your models. Also they don't seem to allow access to the list of registered models.
So I tried doing this:
// models/user.js
var registrations = [];
module.exports = function(sequelize) {
var result = null;
registrations.forEach(function(elem) {
if (elem.db == sequelize)
result = elem.value;
});
if (result) return result;
// data definition
var user = sequelize.define("User", ...);
registrations.push({ db: sequelize, value: user });
return user;
};
Which I can use this like:
// some_controller_1.js
var Foo = require('./models/foo')(app.get('database'));
Foo.find(...); // using Foo
But these small header and footer that I have to write on every single model file are a bit annoying and directly violate the "don't repeat youself" principle. Also, while not a huge issue, this is kind of a memory leak since the "sequelize" object will never be freed.
Is there a better way to do, which I didn't think about?
You can find an article about handling models with sequelize here: http://sequelizejs.com/articles/express#the-application
You basically just create a models/index.js as described here: http://sequelizejs.com/articles/express#block-3-line-0
Afterwards you just put your model definitions within files in the models folder as pointed out here: http://sequelizejs.com/articles/express#block-4-line-0

Categories

Resources