Aurelia - ValidationController always returns true - aurelia

I've made a wizard with aurelia and I want to check the input values when the user hits the next button.
#autoinject()
export class settingsWizard {
steps: Step[];
activeStep: Step;
valController: ValidationController;
constructor(private i18n: I18N, private http: HttpClient, public wizard: Wizard, private log: Logger, private router: Router, private controllerFactory: ValidationControllerFactory) {
this.steps = [
new Step(1, this.i18n.tr("route1"), PLATFORM.moduleName('./steps/step1')),
new Step(2, this.i18n.tr("route2"), PLATFORM.moduleName('./steps/step2')),
new Step(3, this.i18n.tr("route3"), PLATFORM.moduleName('./steps/step3')),
new Step(4, this.i18n.tr("route4"), PLATFORM.moduleName('./steps/step4')),
];
ValidationRules
.ensure('availableTotalTime').required().on(this.wizard.plannedTime);
//.ensureObject()
//.satisfies((x: IQualityRate) => x.numberOfProducedQuantity > x.rejects)
//.withMessage(this.i18n.tr('quality-rate.rejectsHigherThanProducedQuantity'))
//.on(wizard.qualityRate);
this.valController = controllerFactory.createForCurrentScope();
this.valController.validateTrigger = validateTrigger.manual;
}
here's the nextButton event:
nextStep() {
this.valController.validate().then(result => {
if (result.valid) {
if (this.activeStep.id !== this.steps.length) {
this.activeStep = this.steps[this.activeStep.id];
}
}
});
}
My aurelia ValidationController always returns result.valid = true even though availableTotalTime is undefined. What am I doing wrong?

You might be assuming that the ValidationRules api automatically causes objects to be validated, but it only stores the rules on the object's prototype.
The ValidationController only validates objects which are either explicitly (1) or implicitly (2) registered, or directly provided (3) to it.
1. Register "implicitly"
Any property in a view that has the & validate binding behavior on it will be validated whenever you call controller.validate() in the same viewmodel.
2. Register explicitly
Likewise, controller.addObject(this.wizard.plannedTime) will cause that object (and all its properties) to be validated on subsequent calls to .validate()
3. Provide a ValidateInstruction
this.valController.validate({
object: this.wizard.plannedTime,
// optional: propertyName: ...,
// optional: rules: ...
});
This gives you the highest degree of control. It will only validate the object you pass in, and nothing else. Also it won't register the object, so subsequent calls to .validate() will not automatically validate it again.
You'll probably either want to go with option 2 or 3, depending on other concerns.

Ended up here as I was getting the same problem. Fred Kleuver's answer is correct, but only when using .on to register your view model (or in this case, the object with the property to be validated) when creating your rules.
If you are like me and you're explicitly passing in the validation rules into the binding behavior, like & validate:myRules (this happens to be how most of the examples I've seen online doing it) you will need to follow the Entity Validation portion of the documentation.That way you can explicitly pass your validation rules into your validationController.addObject call in the same way you would pass your rules to your binding behavior in your view.
this.validationRules = ValidationRules
.ensure('availableTotalTime')
.required()
.rules;
this.validationController.addObject(this.wizard.plannedTime, this.validationRules);

Related

vuex-persistedstate not saving class methods

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.

Pass global Object/Model to custom element in Aurelia

referring to the following post StackOverflow Question I have a quite different scenario where I want to know if Aurelia has a solution for.
Scenario:
I have a user model:
export class User{
#bindable name: string;
#bindable address: Address
As you can see, "Address" is a sub-model.
I have a main view-model "registration". In this view model I have a model "user":
export class RegistrationView{
#bindable user: User
public attached(){
this.user = userService.fetchUserFromApi();
}
In addition to that I have a custom-element "user-address" where I have a "user-address"-model (because I want to have dedicated encapsulated custom-elements).
export class userAddress{
#bindable userAddress: Address
Now I want to request the user model only once from the API and send the user address it to the custom-element:
<template>
<require from="user-address"></require>
<user-address user.address.bind="${dj.address}"></user-address>
Finally I would (to have dedicated encapsulated custom-elements that I can use everywhere) check in attached method if the user is already load and if not then the custom-element would load all needed data:
export class userAddress{
#bindable userId: string
#bindable address: Address
public attached(){
if(!(typeof this.address === "undefined")){
this.address = this.addressAPIService.getAddressByUserId(id)
}
}
Problem 1: I know, that the mentioned template dj.address.bind doesn't work. But now my question is, how can I handle that situation?
Problem 2: How do I assure, that the user object is only requested once?
Does my concept makes sense and does it is the idea of Aurelia?
If I understand your problem correctly, you simply need some form of client-side persistence.
If you need this persistence even after the user closed the browser, you'll want to use either localStorage or some encapsulation thereof. There are many good plugins available such as localForage, LokiJS and a recently developed (still in beta) aurelia plugin aurelia-store
You probably want to encapsulate the retrieval of your user in a UserService of some sort. This is nothing specific to Aurelia, just generally how you want to do this in most types of applications.
Example
So in your viewmodel you might have something like this (skipping some of the implementation details such as checking the params, configuring the router etc for brevity):
#autoinject()
export class UserViewModel {
public user: User;
constructor(private userService: UserService){}
// happens before bind or attached, so your child views will always have the user in time
public async activate(params: any): Promise<void> {
this.user = await this.userService.getUserById(params.id);
}
}
And in your userservice:
// singleton will ensure this service lives as long as the app lives
#singleton()
export class UserService {
// create a simple cache object to store users
private cache: any = Object.create(null);
constructor(private client: HttpClient) {}
public async getUserById(id: number): Promise<User> {
let user = this.cache[id];
if (user === undefined) {
// immediately store the user in cache
user = this.cache[id] = await this.client.fetch(...);
}
return user;
}
}
Let your view model just be dumb and call the UserService whenever it needs to load a user, and let your service be clever and only fetch it from the API when it's not already cached.
I'd also like to point out that attached() is not when you want to be grabbing data. attached() is when you do DOM stuff (add/remove elements, style, other cosmetic things). bind() is best restricted to grabbing/manipulating data you already have on the client.
So when to fetch data?
In your routed view models during the routing lifecycle. That'll be configureRouter, canActivate, activate, canDeactivate and deactivate. These will resolve recursively before any of the DOM gets involved.
Not in your custom elements. Or you'll soon find yourself in maintenance hell with notification mechanisms and extra bindings just so components can let eachother know "it's safe to render now because I have my data".
If your custom elements can assume tehy have their data once bind() occured, everything becomes a lot simpler to manage.
And what about API calls invoked by users?
More often than you think, you can let an action be a route instead of a direct method. You can infinitely nest router-views and they really don't need to be pages, they can be as granular as you like.
It adds a lot of accessibility when little sub-views can be directly accessed via specific routes. It gives you extra hooks to deal with authorization, warnings for unsaved changes and the sorts, it gives the user back/forward navigation, etc.
For all other cases:
Call a service from an event-triggered method like you normally would during activate(), except whereas normally the router defers page loading until the data is there, now you have to do it yourself for that element.
The easiest way is by using if.bind="someEntityThatCanBeUndefined". The element will only render when that object has a value. And it doesnt need to deal with the infrastructure of fetching data.

Durandal KO binding when data is fetched in activate

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.

Domain class auto validation in grails

I am fetching list of results from database but the list doesn't validates the constraints until i call "validate()" method for each objects.
def temp = ConfigInfo.where { projectId == project }.findAll()
//at this stage domain class is not validated
temp.each {
println "validate" + it.validate()
println "has error" + it.hasErrors()
}
//in the above code block validate() is called, I don't want to do this.
// is it possible to configure it happen automatically and i get the validated objects.
I don't want to invoke validate method.
is there any way or configuration in grails such that domain class get validated automatically.
Please help me in this.
Grails domain class objects get validated before save.
Use the following in your domain model to set the validation rules:
static constraints = {
// whatever you want to validate
}
Whenever you save an object it will be validated by the constraints you set. When the object is persistent in the database it has always been validated.
All you need to do is that just define all your validation in constraints closure.
e.g.
static constraints = {
id maxLength: 5
//etc...
}
at the time of saving object you just need to check object is validate or not!, it will return true/false.
look this: click here

Defining controller accessible variables from filters in Grails

I'm writing a small webapp in Grails, and to make sure all users are authenticated I'm using the following filter:
class LoginFilters {
static filters = {
loginCheck(controller:'*', action:'*') {
before = {
if (session.user_id) {
request.user = User.get(session.user_id)
} else if (!actionName.equals("login")) {
redirect(controller: "login", action: "login")
return false
}
}
}
}
}
And all controller methods start with reading the user property of the request object:
def actionName = {
def user = request.user
...
}
The code above works, but I'd rather avoid the duplicate code in the all controller methods. Would it be possible for the filter to bind the user object to a variable named "user" instead of "request.user", that will be accessible from all controllers?
I understand that there might be scoping issues that makes this impossible, but the Grails framework seems to be able to create quite some magic under the hood, so I figured it might be worth asking.
Using the beforeInterceptor in a controller may help:
class LoginController {
def user
def beforeInterceptor = {
user = request.user
}
def index = {
render text:"index: ${user}"
}
def test = {
render text:"test: ${user}"
}
}
I think it generally not a good idea insert the user object into the request object every time:
The request lifetime is very short, so you might end up making round trips to caches or even worse to the database on each http-request to retrieve an object, that you might not even need and that get's deleted immideately afterwards. So if you must, better store the whole object in the session instead of just the id.
Generally, I'd suggest you write a AuthenticationService with a method isLoggedIn() that returns true when the user is authenticated and a method getLoggedInUser() that returns this object.
class AuthenticationService {
def transactional = false
boolean isLoggedIn() { return session.user_id }
def getLoggedInUser() { return User.get(session.user_id) }
}
Then you use the Filter for redirection if not authenticated, and maybe the Interceptor for storing the local reference user = authenticationService.loggedInUser. But also I don't think this the best way to go. I suggest you'd create an abstract AuthenticationAwareController as base class for all your controllers in src/groovy and there have the convenience method like user
class AuthenticationAwareController {
def authenticationService
def getUser() { return authenticationService.loggedInUser() }
}
This way, you can later change you mind about storing the user however you like and don't have to change your code. Also you benefit from Caches in Hibernate, that share already retrieved user object instances between different sessions, so db roundtrips are avoided.
You still should check the retrieved user object for validity or throw an AuthenticationException in case the retrieval does not succeed. (Maybe something like AuthenticationService.getLoggedInUser(failOnError = false).)
You can even make this Service/ControllerBase a small plugin an reuse that on every application or go directly with the spring security plugin... ;-)
I think you can do this but is it really worth the trouble? It seems to me your only advantage is typing "user" instead of "request.user". Not a big gain. Anyway, I think you could follow the instructions in "12.7 Adding Dynamic Methods at Runtime" of the User Guide. I think that if you created a dynamic method "getUser() {return request.user}" that the Groovy JavaBeans getter/setter access would allow you to simply reference "user" the way you want.
If you do add a dynamic method you might want to skip the filter and do it all in the dynamic method.