I'm trying to use a "configured object" as a controller in ExpressJS so I can reuse a bunch of code.
Taken from the express configuration:
var ctrl = new CRUDServiceAdapter(serviceConfig);
// list
// this works: ctrl.load()
app.get(serviceURL, ctrl.load);
And separately this is part of the object definition:
function CRUDServiceAdapter(serviceConfig){
this.config = serviceConfig;
this.logger = logModule.logger("service.controller." + serviceConfig.modelName);
};
CRUDServiceAdapter.prototype.load = function(req, res, next){
this.logger.debug("Creating an object model for " + this.config.modelName);
res.json({"msg": "Hello World"});
};
What I observe is the object property this.config is undefined when the method is called through an expressJS request. But if I call it directly on the object like in the comments ctrl.load() - the config object is populated as expected.
Why is the object losing it's property values when it's executing as a route?
Is there a way to fix it?
The context is lost:
You are not passing the object ctrl as parameter, only a method, so that method is called as any regular function, so this is not pointing at ctrl (I guess it is undefined), so try to change your code for:
app.get(serviceURL, ctrl.load.bind(ctrl));
Related
I'd like to preference this by saying my backgrounds in in C# so I like declaring methods within my classes. I've created a user class that contains properties and methods and I've added this to my vuex-persistedstate. One of the methods is a logout() method which clears out the properties. When I tried to invoke this method I got the following error:
TypeError: this.$data.user.logout is not a function
I then reviewed local storage and noted the user did not have reference to the class method. So I went ahead and copied the logic from the method into my vue component and it worked so I'm assuming the issue is vuex-persistedstate does not save references to methods which is why the method call did not work.
I'd like to declare the logout method in one location rather than spreading it out across vue components, what is the best practice for accomplishing this? Is it possible to do this in the class declaration or do I need a user helper file?
Sure Berco! My code is also up on GitHub so you can review it there too, but basically it seems to me that vuex does not store methods. The first file you should review is my user.js file:
https://github.com/Joseph-Anthony-King/SudokuCollective/blob/master/SudokuCollective.WebApi/client/src/models/user.js
In this file I have a method called shallow clone which takes the info received from the API and assigns it to the user:
shallowClone(data) {
if (data !== undefined) {
this.id = data.id;
this.userName = data.userName;
this.firstName = data.firstName;
this.lastName = data.lastName;
this.nickName = data.nickName;
this.fullName = data.fullName;
this.email = data.email;
this.isActive = data.isActive;
this.isAdmin = data.isAdmin
this.isSuperUser = data.isSuperUser;
this.dateCreated = data.dateCreated;
this.dateUpdated = data.dateUpdated;
this.isLoggedIn = data.isLoggedIn;
}
}
You of course don't need to abstract this away but I've found it makes the code easier to maintain.
Then in the mounted() lifecycle hook I assign the user received from the API to the component user via the shallowClone method. Please bear in mind I've done additional work on this project and the login form is now it's own component which receives the user as a prop from the app:
https://github.com/Joseph-Anthony-King/SudokuCollective/blob/master/SudokuCollective.WebApi/client/src/components/LoginForm.vue
mounted() {
let self = this;
window.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
self.authenticate();
}
});
this.$data.user = new User();
this.$data.user.shallowClone(this.$props.userForAuthentication);
},
The full code can be reviewed here:
https://github.com/Joseph-Anthony-King/SudokuCollective
I found a solution... I'm working on improving it. Basically I use the values pulled from localstorage into vuex to create a new user object in the vue component that has reference to the methods located in my user class declaration. I recalled recommendations that we should create clones of objects pulled from vuex for use within the vue component. I'm still refining the code but that's basic idea.
I have the following code fragment and would like to strip the observer functionality from the user.accounts object. How would I do that? this.$cookies is a reference to my vue-cookies instance
setUserAccount(user, account){
// var accounts = Object.assign({},user.accounts)
this.$cookies.set('AUTH_TOKEN', user.authHash);
this.$cookies.set('CURRENT_ACCOUNT', user.id);
this.$cookies.set('ACCOUNTS', user.accounts);
console.log(user.accounts);
},
Convert the object to a JSON string. That will remove all the Vue observer mechanisms.
const strAccounts = JSON.stringify(user.accounts)
this.$cookies.set('ACCOUNTS', strAccounts);
And to convert it back (without the observer functionality).
JSON.parse(strAccounts);
The only caveat is you need to watch out for circular references in your object, and functions will not get serialized.
A parameter governs what data is to be displayed. The parameter is retrieved from activationData in the activate method of the view model and used in a call to a Web Api method. Data is returned, and added to the view model like this
define(['durandal/app', 'knockout', 'moment'],
function (app, config, ko, moment) {
var vm = {
app: app
};
vm.activate = function (activationData) {
vm.ChecklistInstanceId = activationData.ChecklistInstanceId;
$.ajax({
url: "api/ChecklistInstance/" + vm.ChecklistInstanceId,
headers: { Authorization: "Session " + app.SessionToken() }
}).done(function (data) {
$.extend(vm, ko.mapping.fromJS(data));
});
};
return vm;
});
Inspecting the viewmodel immediately after it is extended reveals that it is decorated with observables exactly as expected. For example, vm.Caption() exists and returns the string I expect, and vm.Section() is an appropriately populated observable array, and so on down a fairly elaborate object graph.
The problem is the binding phase has already occurred, and at that time the view model lacks all the observables to which I'm trying to bind.
Two possible strategies suggest themselves:
obtain the parameter earlier
re-bind
I don't know how to do either of those things. Can anyone tell me how to re-organise my code to allow binding to parametrically fetched data?
A third possibility occurred to me:
define(['durandal/app', 'knockout', 'moment'],
function (app, config, ko, moment) {
var vm = {
app: app,
Caption: ko.observable(),
Section: ko.observableArray()
};
vm.activate = function (activationData) {
vm.ChecklistInstanceId = activationData.ChecklistInstanceId;
$.ajax({
url: "api/ChecklistInstance/" + vm.ChecklistInstanceId,
headers: { Authorization: "Session " + app.SessionToken() }
}).done(function (data) {
var foo = ko.mapping.fromJS(data);
vm.Caption(foo.Caption());
vm.Section(foo.Section());
});
};
return vm;
});
This works because all the observables exist in the binding phase. This might seem surprising given that I describe only the root of a potentially deep object graph, but the fact that the observable array is empty causes the binding phase to exit without a hitch.
Later in the activate handler, values are added to the observable array after ko.mapping has its way with the data, and binding succeeds.
I have a sense of dèja vu from this: it is eerily reminiscent of problems solved using forward declarations in TurboPascal back in the eighties. La plus ça change...
In order to work on a fully-constructed view, you will need to move your logic to either the attached handler or the compositionComplete handler. As you said, at the activate stage, the DOM isn't yet fully constructed. You can read about these lifecycle callbacks here.
Typically, what we do is pass the activationData in through the activate handler, store the activationData locally (if your viewModel is instance-based, then on a property in the constructor), and then reference that activationData in the attached or the compositionComplete handler.
You can fetch the data in the activate handler, and then store the data locally. But that's all you should do there. Reserve view-related logic for later in the cycle. In this case, you may need to return a promise from activate, and then resolve upon receiving your data. You can read about it here.
UPDATE
Take a look at this post, and the conversation there.
I am trying to duplicate an object every time I click it in Verold. I have attached the Object Picker to the scene and successfully triggered a function which prints to the console.
I've tried this code but I get a Type Error - can't read property of undefined.
var xxx = this.getEntity().clone();
var threeDataxxx = xxx.getThreeData();
threeDataxxx.position.x += Math.random() * 5;
The clone() method is asynchronous (because the same method would be used if you were creating persistent copies of your objects on the server). This function, like many functions in the Verold API, takes an 'options' object as a parameter. In here, you need to specify the 'success' callback method like in the following example. Once you have the clone, you then need to add it to the scene hierarchy using the addChild() method. This will automatically trigger the cloned object to load.
var parent = this.getEntity().getParentObject();
this.getEntity().clone( {
success: function( newEntity ) {
parent.addChild( newEntity );
var position = newEntity.getPosition();
position.x += Math.random() * 10;
newEntity.setPosition( position.x, position.y, position.z );
}
});
The multiple steps are useful because you may want to clone several objects and have them ready to add to the scene at a later time.
And, of course, if you don't require the cloned object to have components or any of the other functionality of a VeroldObject, you can always just get the threeData and then use Three.JS's clone() method.
Hope that helps.
I have a Document class that loads variables from Facebook with the use of stage.loaderInfo
var connect:FacebookConnectObject = new FacebookConnectObject( facebook, API_KEY, this.stage.loaderInfo );
But when I change the Document class (with another one responsible for the layout of my app), and try call the above from a movieclip that exists in my application with the use:
var facebook_class:FacebookAp = new FaceBppkApp
addChild(facebook_class) I get error
TypeError: Error #1009: Cannot access a property or method of a null object reference.
I believe the error comes fro this line
this.stage.loaderInfo
since I changed the scope...
How I am supposed to fix that?
According to a post by Devonair: Seems 99 times out of a 100 when people have a problem with a 1009 error, it's because the stage property is inaccessible.
so I used this snippet
public function start() {
if
{(stage) init();}
else
{ addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(event:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// everything else...
}
In case sb has the same problem...