When i click to logout, i send my route to the module (logout.js), he gets there and it will execute with no problem all the commands. it does even logout and destroys all the data (Which is good).
import { noView } from 'aurelia-framework';
import authService from 'services/authService';
import uiService from 'services/uiService';
@noView()
export class LogoutPage {
activate() {
// uiService.impersonate(null, false);
// authService.logout();
}
}
But there is an error which have been bothering me:
ERROR [app-router] TypeError: "this.view is null" <
automatewebpack-internal:///./node_modules/aurelia-templating/dist/native-modules/aurelia-templating.js:3718:5readywebpack-internal:///./node_modules/aurelia-templating-router/dist/native-modules/router-view.js:168:7swapwebpack-internal:///./node_modules/aurelia-templating-router/dist/native-modules/router-view.js:197:12_commitChangeswebpack-internal:///./node_modules/aurelia-router/dist/native-modules/aurelia-router.js:285:16_commitChangeswebpack-internal:///./node_modules/aurelia-router/dist/native-modules/aurelia-router.js:284:7tryCatcherwebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:4954:16_settlePromiseFromHandlerwebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3095:13_settlePromisewebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3152:13_settlePromise0webpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3197:5_settlePromiseswebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3277:13_fulfillwebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3221:13_resolvewebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3487:5_promiseFulfilledwebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3505:9_settlePromisewebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3157:17_settlePromise0webpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3197:5_settlePromiseswebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:3277:13_drainQueueStepwebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:190:9_drainQueuewebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:183:9_drainQueueswebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:199:5drainQueueswebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:69:9owebpack-internal:///./node_modules/bluebird/js/browser/bluebird.js:4208:17 aurelia-logging-console.js:47
error
aurelia-logging-console.js:47
logFactory/<
aurelia-logging.js:38
processResult
aurelia-router.js:1869
_dequeueInstruction/</<
aurelia-router.js:1821
tryCatcher
bluebird.js:5276
[22]</module.exports/Promise.prototype._settlePromiseFromHandler
bluebird.js:3297
[22]</module.exports/Promise.prototype._settlePromise
bluebird.js:3354
[22]</module.exports/Promise.prototype._settlePromise0
bluebird.js:3399
[22]</module.exports/Promise.prototype._settlePromises
bluebird.js:3479
[22]</module.exports/Promise.prototype._fulfill
bluebird.js:3423
[22]</module.exports/Promise.prototype._settlePromise
bluebird.js:3367
[22]</module.exports/Promise.prototype._settlePromise0
bluebird.js:3399
[22]</module.exports/Promise.prototype._settlePromises
bluebird.js:3479
[22]</module.exports/Promise.prototype._fulfill
bluebird.js:3423
[22]</module.exports/Promise.prototype._resolveCallback
bluebird.js:3239
[22]</module.exports/Promise.prototype._settlePromiseFromHandler
bluebird.js:3309
[22]</module.exports/Promise.prototype._settlePromise
bluebird.js:3354
[22]</module.exports/Promise.prototype._settlePromise0
bluebird.js:3399
[22]</module.exports/Promise.prototype._settlePromises
bluebird.js:3475
_drainQueueStep
bluebird.js:190
_drainQueue
bluebird.js:183
[2]</Async.prototype._drainQueues
bluebird.js:199
Async/this.drainQueues
bluebird.js:69
schedule/o<
bluebird.js:4530
<
import { inject, customAttribute, templateController, BoundViewFactory, ViewSlot } from 'aurelia-framework';
import userService from 'services/api/userService';
@customAttribute('if-permission')
@inject(BoundViewFactory, ViewSlot)
@templateController
export class IfPermission {
constructor(viewFactory, viewSlot) {
this.viewFactory = viewFactory;
this.viewSlot = viewSlot;
this.showing = false;
this.view = null;
this.bindingContext = null;
this.overrideContext = null;
}
/**
* Binds the if to the binding context and override context
* @param bindingContext The binding context
* @param overrideContext An override context for binding.
*/
bind(bindingContext, overrideContext) {
// Store parent bindingContext, so we can pass it down
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
this.valueChanged(this.value);
}
valueChanged(newValue) {
if (this.__queuedChanges) {
this.__queuedChanges.push(newValue);
return;
}
let maybePromise = this._runValueChanged(newValue);
if (maybePromise instanceof Promise) {
let queuedChanges = this.__queuedChanges = [];
let runQueuedChanges = () => {
if (!queuedChanges.length) {
this.__queuedChanges = undefined;
return;
}
let nextPromise = this._runValueChanged(queuedChanges.shift()) || Promise.resolve();
nextPromise.then(runQueuedChanges);
};
maybePromise.then(runQueuedChanges);
}
}
_runValueChanged(newValue) {
newValue = userService.hasPermission(newValue);
if (!newValue) {
let viewOrPromise;
if (this.view !== null && this.showing) {
viewOrPromise = this.viewSlot.remove(this.view);
if (viewOrPromise instanceof Promise) {
viewOrPromise.then(() => this.view.unbind());
} else {
this.view.unbind();
}
}
this.showing = false;
return viewOrPromise;
}
if (this.view === null) {
this.view = this.viewFactory.create();
}
if (!this.view.isBound) {
this.view.bind(this.bindingContext, this.overrideContext);
}
if (!this.showing) {
this.showing = true;
return this.viewSlot.add(this.view);
}
}
/**
* Unbinds the if
*/
unbind() {
if (this.view === null) {
return;
}
this.view.unbind();
if (!this.viewFactory.isCaching) {
return;
}
if (this.showing) {
this.showing = false;
this.viewSlot.remove(this.view, true, true);
}
this.view.returnToCache();
this.view = null;
}
}
import { inject, customAttribute, templateController, BoundViewFactory, ViewSlot } from 'aurelia-framework';
import userService from 'services/api/userService';
@customAttribute('if-user-role')
@inject(BoundViewFactory, ViewSlot)
@templateController
export class IfUserRole {
constructor(viewFactory, viewSlot) {
this.viewFactory = viewFactory;
this.viewSlot = viewSlot;
this.showing = false;
this.view = null;
this.bindingContext = null;
this.overrideContext = null;
}
/**
* Binds the if to the binding context and override context
* @param bindingContext The binding context
* @param overrideContext An override context for binding.
*/
bind(bindingContext, overrideContext) {
// Store parent bindingContext, so we can pass it down
this.bindingContext = bindingContext;
this.overrideContext = overrideContext;
this.valueChanged(this.value);
}
valueChanged(newValue) {
if (this.__queuedChanges) {
this.__queuedChanges.push(newValue);
return;
}
let maybePromise = this._runValueChanged(newValue);
if (maybePromise instanceof Promise) {
let queuedChanges = this.__queuedChanges = [];
let runQueuedChanges = () => {
if (!queuedChanges.length) {
this.__queuedChanges = undefined;
return;
}
let nextPromise = this._runValueChanged(queuedChanges.shift()) || Promise.resolve();
nextPromise.then(runQueuedChanges);
};
maybePromise.then(runQueuedChanges);
}
}
_runValueChanged(newValue) {
newValue = userService.hasRole(newValue);
if (!newValue) {
let viewOrPromise;
if (this.view !== null && this.showing) {
viewOrPromise = this.viewSlot.remove(this.view);
if (viewOrPromise instanceof Promise) {
viewOrPromise.then(() => this.view.unbind());
} else {
this.view.unbind();
}
}
this.showing = false;
return viewOrPromise;
}
if (this.view === null) {
this.view = this.viewFactory.create();
}
if (!this.view.isBound) {
this.view.bind(this.bindingContext, this.overrideContext);
}
if (!this.showing) {
this.showing = true;
return this.viewSlot.add(this.view);
}
}
/**
* Unbinds the if
*/
unbind() {
if (this.view === null) {
return;
}
this.view.unbind();
if (!this.viewFactory.isCaching) {
return;
}
if (this.showing) {
this.showing = false;
this.viewSlot.remove(this.view, true, true);
}
this.view.returnToCache();
this.view = null;
}
}
Hi. I tried to simplify the html needed to create a form with fields+validation+error display by creating a custom component.
validated-input.html
<template>
<div class="form-input ${class}">
<slot name="icon"></slot>
<label if.bind="!floatingLabel">${label}</label>
<div>
<div class="ui input primary-input">
<input type="text" ref="field" class="${errors.length > 0 ? 'has-errors': ''}"
keydown.delegate="keyDownHandler($event)" value.bind="value" blur.trigger="blur()" input.trigger="input()" autocomplete="off">
<div if.bind="floatingLabel" class="floating-label"><span class="floating-label-focus">${label}</span></div>
</div>
<div if.bind="errors.length > 0" class="validation-error">
<i class="exclamation triangle icon"></i>
<span repeat.for="e of errors">${e.message}</span>
</div>
</div>
</div>
</template>
validated-input.ts
import { ValidationController, ValidateResult, validateTrigger } from "aurelia-validation";
import { customElement, bindable, containerless, autoinject, bindingMode, DOM } from "aurelia-framework";
@autoinject
@containerless
@customElement("validated-input")
export class ValidatedInput {
@bindable field: HTMLInputElement;
@bindable label: string;
@bindable class: string = "";
@bindable({ defaultBindingMode: bindingMode.twoWay }) value: string;
@bindable name: string;
@bindable floatingLabel: boolean = false;
@bindable validationTrigger: string = "change";
@bindable maxlength: string | null = null;
@bindable pattern: string | null = null;
errors: ValidateResult[];
private controller: ValidationController;
constructor(private element: Element) {
}
bind(bindingContext: any) {
this.field.setAttribute("value", this.value || "");
this.controller = bindingContext.controller;
if (this.maxlength) {
this.field.setAttribute("maxlength", this.maxlength);
}
if (this.pattern) {
this.field.setAttribute("pattern", this.pattern);
}
this.controller.subscribe((e) => this.errors = e.results.filter((x) => x.propertyName === this.name && !x.valid));
}
blur() {
if (this.validationTrigger === "blur") {
this.validate();
}
}
input() {
if (this.validationTrigger === "change") {
this.validate();
}
}
private validate() {
this.field.setAttribute("value", this.value || "");
this.controller.validate().then((validate) => {
this.errors = validate.results.filter((x) => x.propertyName === this.name && !x.valid);
});
}
private keyDownHandler(e: KeyboardEvent) {
if (e.key === "Enter") {
this.element.dispatchEvent(DOM.createCustomEvent("enter"));
}
return true;
}
}
The problem I have is that I need (I think) to have each field subscribe to the validation callback to perform their logic to filter the errors
collection. This is because a validation can be triggered by the page that contains the submit button. But by having each field subscribe to the validation callback this also means that as soon as I validate one of the fields in the blur
or change
handlers all of the fields are validated. I only want this full form validation when you try to submit the form.
The ValidationController and the ValidationRules are created and defined in the containing page.
I feel that I have over complicated this solution and that there must be something simpler?
FluentRules
from a duplicate package
node_modules/aurelia-validation/dist/commonjs/property-info.d.ts(3,11): error TS2451: Cannot redeclare block-scoped variable 'getContextFor'.
Does aurelia-validation require that every "property" referred to in .ensure(...)
is not null? I have the following piece of code
editinfoChanged(newEditInfo: any, oldValue: any) : void {
if (this.domainobject && newEditInfo) {
this.editinfo.forEach((field: { requisiteness: string; name: string | number; label: string }) => {
if (this.isMandatory(field.requisiteness)) {
ValidationRules.ensure(this.domainobject[field.name]).displayName(field.label).required().on(this.domainobject);
};
});
}
}
which fails and produces the following error message:
Uncaught TypeError: Cannot read property 'toString' of null
at PropertyAccessorParser.parse (aurelia-validation.js?f0d7:91)
at FluentEnsure.ensure (aurelia-validation.js?f0d7:1700)
at Function.ValidationRules.ensure (aurelia-validation.js?f0d7:1767)
at eval (new-item-view.ts?c01b:112)
at Array.forEach (<anonymous>)
at NewItemView.editinfoChanged (new-item-view.ts?c01b:110)
When I look at the value of this.domainobject[field.name]
(in the first iteration) it is null and this makes me wonder if that's the cause of the error?
hello guys can someone help me with "form-field-validation" i'm trying to validate a checkbox table the validation works but the red border css not working
in the noop.bind i passe the validated list
<div class="box stackpanel vertical fit form-field-validation" noop.bind="posteUFDTOList & validate:validationController">
<div class="box-header bg-primary stackpanel horizontal fit">
<input id="chx_all" class="form-control colSelection" type="checkbox" change.delegate="cocherDecocherTout()" />
<label for="chx_all" class="box-title" i18n="sante:ui.fwm.gestionutilisateur.postes.postedetail.cocherdecocher"></label>
</div>
</div>
if (this.posteUFDTOList) {
this.validationController.validate({ object: this.posteUFDTOList });
}
Hi,
I am a newbie in aurelia.
Aurelia Validation Demo - Nested object properties
https://gist.github.com/jsobell/d81428170f1572ae916e3fbf67779014
BootstrapFormRenderer example
https://gist.github.com/y2k4life/8adacec7627d792a304f62a899f21049
I am getting correct validation when using controller.validate() method
Problem is that in BootstrapFormRenderer
In render method, elements are always empty.
render(instruction: RenderInstruction) {
debugger;
for (let { result, elements } of instruction.unrender) {
for (let element of elements) {
this.remove(element, result);
}
}
for (let { result, elements } of instruction.render) {
for (let element of elements) {
this.add(element, result);
}
}
}