Aurelia Validation Matches - aurelia

I am trying to work out how I would do a startsWith? This is a custom element, it needs to validate that the string starts with a "\"
<template>
<input disabled.bind="readonly" type="text" class="form-control" value.bind="value">
</template>
import {customElement, bindable, inject, bindingMode} from 'aurelia-framework';
import {activationStrategy} from 'aurelia-router';
import $ from 'jquery';
import {Validation} from 'aurelia-validation';
#customElement('url')
#bindable({name: 'value', attribute: 'value', defaultValue: '', defaultBindingMode: bindingMode.twoWay})
#bindable({name: 'readonly', attribute: 'disabled', defaultValue: false, defaultBindingMode: bindingMode.oneWay})
#inject(Element, Validation)
export class Url {
constructor(element, validation) {
this.element = element;
this.validation = validation.on(this)
.ensure(this.element)
.isNotEmpty()
.containsNoSpaces()
.matches('/^[\].*/');
}
bind(){
$('.input', this.element).val(this.value);
if(this.readonly){
$('.input', this.element).attr('readonly', 'readonly');
}
}
}
I've looked at http://aurelia.io/validation/#/logical-operators and I think Im doing it right but it throws an error: inner error: TypeError: path.split is not a function

The function ensure() accepts the name of validated field, not the element
No need to surround your regex with quotes
It should be something like
this.validation = validation.on(this)
.ensure('value')
.isNotEmpty()
.containsNoSpaces()
.matches(/^\\.*$/);

Related

Uncaught TypeError: Cannot read property 'firstname' of undefined. on loading a component that has an inner component

create.vue
<template>
<div class="content">
<base-input type="text" id="firstname" v-model="firstname"/>
</div>
</template>
<script>
import BaseInput from 'BaseInput.vue'
export default {
data () {
return {
firstname: ''
}
}
}
</script>
create.spec.js
import { shallowMount, createLocalVue } from '#vue/test-utils'
import Create from '/Create.vue'
import VueI18n from 'vue-i18n'
const wrapper = shallowMount(Create)
const vm = wrapper.vm
console.log(vm)
As you see, while loading the template using shallow Mount.
it throws the error,
Uncaught TypeError: Cannot read property 'firstname' of undefined at
webpack:///node_modules/#vue/test-utils/dist/vue-test-utils.js:5652:0
<- index.6fc62f9fc7f0f4a43161.js:9693
You need to add your BaseInput component to your export default. Now vue don't know what BaseInput is (info, if you are using such as Babel or Webpack) . I also changed the data line because there need to be a : after data and function before the () (example). If you do it like this it should work:
<script>
import BaseInput from 'BaseInput.vue'
export default {
components: {
BaseInput
}
data: function() {
return {
firstname: ''
}
}
}
</script>

How to pass value from template HTML to component to then be used in service

I want to fetch id from component.html into component.ts to pass it to a service.
.ts file is;
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { HttpErrorResponse } from '#angular/common/http/src/response';
import { SendUsingApiService } from '../send-using-api.service';
import { Router, ActivatedRoute } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { setDefaultService } from 'selenium-webdriver/chrome';
#Component({
selector: 'app-org-info',
templateUrl: './org-info.component.html',
styleUrls: ['./org-info.component.css'],
providers: [SendUsingApiService]
})
export class OrgInfoComponent implements OnInit {
orgData: string[] = [];
Id = 1;
editRecord:FormGroup;
constructor(private httpService: HttpClient, private _serv: SendUsingApiService,
private fb: FormBuilder, private _ar:ActivatedRoute, private _r:Router) {
this.editRecord = this.fb.group({
Id:['1', []],
OrganisationName:['', []],
ContactPerson:['', []],
ContactPersonHPNo:['', []],
ContactPersonEmailId:['', []]
});
}
ngOnInit() {
console.log(this._ar.snapshot.params.Id, "+ve");
this._ar.params.subscribe(() => {
this._serv.getUsers(this._ar.snapshot.params.Id).subscribe((res)=>{
console.log(res);
this.setUser(res);
});
});
}
I am getting the value for console.log(this._ar.snapshot.params.Id); as undefined "+ve".
I want to get the Id value in console.
As per requests I am adding html part, though little adjusted;
<td style="text-align: center;">
<a class="btn btn-basic" [routerLink]="['/org-info',data['Id']]" role="button" (click)="getOrgData(data.Id)">View</a>
</td>
I defined a property instead of Id = 1; (above)
paramId = '';
then, within ngOnInit;
ngOnInit() {
this.paramId = this._ar.snapshot.params.Id;
console.log(paramId, "+ve");
}
Doing this, I got the Id value instead of undefined.

*ngIf works OK in some parts, but not in others. Angular 2.0.x

I am trying to use *ngIf in a simple component and angular is throwing an error on *ngIf.
Removing the "*ngIf="loggedIn" and it runs. {{loggedIn}} shows true after logging in and false before.
The main app uses the same div to enable menus, which works fine.
I must be doing some simple wrong but it escapes me.
thanks
First the error:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0
at TemplateParser.parse (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:8446:21)
at RuntimeCompiler._compileTemplate (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16824:53)
at eval (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:85)
at Set.forEach (native)
at compile (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:49)
at ZoneDelegate.invoke (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:203:28)
at Zone.run (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:96:43)
at http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:462:57
at ZoneDelegate.invokeTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:236:37)
at Zone.runTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:136:47)
Template:
<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
Shows Configuration {{loggedIn}}
</div>
</div>
Component:
import { Component, OnInit } from '#angular/core';
import { IShowConfig } from './iShowConfig';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';
#Component({
// selector: 'showconfig',
templateUrl: 'app/showMenu/showConfig/ShowConfig.component.html'
})
export class ShowConfigComponent implements OnInit {
pageTitle: string = 'Product List';
imageWidth: number = 50;
imageMargin: number = 2;
showImage: boolean = false;
listFilter: string = '';
errorMessage: string;
shows: IShowConfig[];
public isLoggedIn: boolean = true;
// constructor(private _productService: ProductService) {
constructor(public authSvc: AuthService) {
this.isLoggedIn = true;
console.log(`config loggedIn: `);
console.log(`${AuthService.isLoggedIn}`);
if (authSvc.user === undefined) {
console.log('islogin undefine');
} else {
console.log('config user: ' + authSvc.user);
}
console.log('show config count: ' + AuthService.count);
}
public get loggedIn(): boolean {
if (AuthService.isLoggedIn) {
return true;
} else {
return false;
}
}
toggleImage(): void {
this.showImage = !this.showImage;
}
ngOnInit(): void { }
onRatingClicked(message: string): void {
this.pageTitle = 'Show List: ' + message;
}
}
I found the solution! I think Nicu also guessed what it was.
I didn't import BrowserModule into my ShowConfig.module.ts ie: my #ngmodule.
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { ShowConfigComponent } from './ShowConfig.component';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';**
#NgModule({
imports: [
// The following line was missing
BrowserModule,
FormsModule
],
declarations: [
ShowConfigComponent
],
providers: [
]
})
export class ShowConfigModule { }

Binding complex object to a component

Introduction
My goal is to create custom element in aurelia so that I can reuse it across the application.
In this context I've created component called operator-detail (operator-detail.html and operator-detail.js) which will holds information about operator and my plan is to reuse it in several places in application.
In this use case I have electornicRegistrationForm object which holds reference to operatorDetails and legalRepresentative. Both instances are injected into electornicRegistrationForm module and will be used as part of wizard allowing user to create a document which will be printed later on.
This electronicRegistraionForm is injected into operatorStep component.
operator-detail.html component I've included in operatorStep.html and confirm that component has been rendered correctly.
Problem
How to pass (bind) property operator from operatorStep.js to operator-detail.html component so that values from object operator are displayed (binded) in a two way binding manner.
In following example, value from this.operator.firstName 'First name from operator step' don't get displayed in operator-detail.html component.
Source code
electronicRegistrationForm.js:
import { OperatorDetail } from 'common/operator-detail';
import { LegalRepresentative } from 'common/legalRepresentative';
import { inject } from 'aurelia-framework';
#inject(OperatorDetail, LegalRepresentative)
export class ElectronicRegistrationForm {
constructor(operatorDetail, legalRepresentative) {
this.operator = operatorDetail;
this.legalRepresentative = legalRepresentative;
}
}
operator-detail.js
import {inject, NewInstance} from 'aurelia-framework';
import {ValidationRules, ValidationController} from 'aurelia-validation';
#inject(NewInstance.of(ValidationController))
export class OperatorDetail {
constructor(validationController) {
this.validationController = validationController;
this.firstName = '';
}
attached() {
ValidationRules
.ensure('firstName').displayName('Ime').required()
.on(this);
}
}
operator-detail.html
<template bindable="operatorvalue">
<div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="firstName" t='first_name'></label>
<input type="text" class="form-control" id="firstName" value.bind="operatorvalue.firstName ">
</div>
</div>
</div>
</template>
operatorStep.js
import { ElectronicRegistrationForm } from 'model/electronicRegistrationForm';
import { inject, NewInstance } from 'aurelia-framework';
import { RegistrationWizard } from 'registration/registrationWizard';
import { WizardStep } from 'registrationSteps/wizardStep';
import { ValidationController } from 'aurelia-validation';
import {bindable, bindingMode} from 'aurelia-framework';
#inject(ElectronicRegistrationForm, RegistrationWizard, NewInstance.of(ValidationController))
export class OperatorStep extends WizardStep {
#bindable({ defaultBindingMode: bindingMode.twoWay }) operator;
constructor(electronicRegistrationForm, regWiz, validationController) {
super(electronicRegistrationForm, regWiz, validationController);
this.operator = electronicRegistrationForm.operator;
this.operator.firstName='First name from operator step';
this.representative = electronicRegistrationForm.legalRepresentative;
}
}
operatorStep.html
<template>
<require from="common/operator-detail"></require>
<form validation-renderer="bootstrap-form">
<operator-detail operatorvalue.bind="operator"></operator-detail>
</form>
</template>
Declaring a bindable property on a template is for when you have a View without a ViewModel.
The bindable="operatorvalue" in your operator-detail.html doesn't work because you also have a ViewModel defined for this element. If you want to keep it this way then simply remove the bindable="operatorvalue" from the template and instead declare it in your ViewModel like so:
import {inject, NewInstance, bindable} from 'aurelia-framework';
import {ValidationRules, ValidationController} from 'aurelia-validation';
#inject(NewInstance.of(ValidationController))
export class OperatorDetail {
#bindable operatorvalue;
constructor(validationController) {
this.validationController = validationController;
this.firstName = '';
}
attached() {
ValidationRules
.ensure('firstName').displayName('Ime').required()
.on(this);
}
}
operator-detail.html would then become:
<template>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="firstName" t='first_name'></label>
<input type="text" class="form-control" id="firstName" value.bind="operatorvalue.firstName ">
</div>
</div>
</div>
</template>
Alternatively, you could make the bindable property declaration in the template work by simply deleting operator-detail.js and putting the validation stuff elsewhere. Then, rather than injecting OperatorDetail into the registration form you could new up the operator object like so:
import { LegalRepresentative } from 'common/legalRepresentative';
import { inject } from 'aurelia-framework';
#inject(LegalRepresentative)
export class ElectronicRegistrationForm {
constructor(legalRepresentative) {
this.operator = {};
this.legalRepresentative = legalRepresentative;
}
}
Both ways will work.
Working without ViewModels means putting the validation logic in electronicRegistrationForm.js for instance, which also means less code to write.
Working with ViewModels gives you more encapsulation, which is generally preferable if your view-specific logic is more complex than what you've shown here.
EDIT
In case you're using Google Chrome, I highly recommend using the aurelia context extension. You could then inspect the html and see that operator was defined in operator-step, but operatorvalue was undefined in operator-detail. This would tell you that the operatorvalue bindable declaration must be wrong, rather than something else.

Using Aurelia validation in model

This is a similar to this but we want to define validation logic in model level but the following doesn't show validation message.
user-model.js (not working)
import {transient, inject} from 'aurelia-framework';
import {ensure} from 'aurelia-validation';
#transient()
export class UserModel {
#ensure(function(it) { it.isNotEmpty().hasLengthBetween(3,10) })
firstName = "";
constructor() {
this.firstName = "";
}
}
user.js (not working)
import {inject} from 'aurelia-framework';
import {Validation} from 'aurelia-validation';
import {UserModel} from 'models/user-model';
#inject(Validation, UserModel)
export class User {
constructor(validation, userModel) {
this.userModel = userModel;
this.validation = validation.on(this);
}
}
user.html (not working)
<form role="form" validate.bind="validation">
<div class="form-group">
<label>First Name</label>
<input type="text" validate="model.firstName" value.bind="model.firstName" class="form-control" >
</div>
</form>
Notice that validate="model.firstName" is used in user.html, which kind of makes the validation work, meaning I see 'has-success' class gets added to form-group div when user input is valid, but it doesn't display message when it's NOT valid input.
But, if I take out the validation logic outside of the user-model.js and put it in user.js like below, it works just fine.
user-model.js (working)
import {transient, inject} from 'aurelia-framework';
#transient()
export class UserModel {
constructor() {
this.firstName = "";
}
}
user.js (working)
import {inject} from 'aurelia-framework';
import {Validation} from 'aurelia-validation';
import {UserModel} from 'models/user-model';
#inject(Validation, UserModel)
export class User {
constructor(validation, userModel) {
this.model = userModel;
this.validation = validation.on(this)
.ensure('model.firstName')
.isNotEmpty()
.hasLengthBetween(3,10);
}
}
user.html (working)
<form role="form" validate.bind="validation">
<div class="form-group">
<label>First Name</label>
<input type="text" value.bind="model.firstName" class="form-control" >
</div>
</form>
We are trying to define validation logic in user model itself so that when we need to use it in other UIs, we have the centralized location to validate it instead of copy & paste the logic everywhere. It's possible that I am doing something wrong, but if anyone knows how to accomplish this, any help is appreciated!
From the aurelia-validation docs,
As your viewmodels become more complex or if you start using binding
converters, the binding path you used to set up the validation rules
might be different than the binding path you used in your view, so
you'll need to give the validate custom attribute some extra clues as
to which elements should be matched against which validation rules.
Consider this more complex example...
Basically, the validation rule was created against the firstName property in your UserModel, but the binding for the input element has a different binding path: value.bind="userModel.firstName". Because of this, you need to add a validate="firstName" attribute onto the input element to help aurelia-validation know which HTML element to match on for the validation messages.
Here's how you can do it (with Plunkr)
user-model.js
import {transient} from 'aurelia-framework';
import {ensure} from 'aurelia-validation';
#transient()
export class UserModel{
#ensure(function(it) { it.isNotEmpty().hasLengthBetween(3,10) })
firstName = "";
constructor() {
this.firstName = "";
}
}
user.js
import {inject} from 'aurelia-framework';
import {Validation} from 'aurelia-validation';
import {UserModel} from 'user-model';
#inject(Validation, UserModel)
export class User {
constructor(validation, userModel) {
this.userModel = userModel;
this.validation = validation.on(this.userModel);
}
}
user.html
<template>
<form role="form" validate.bind="validation">
<div class="form-group">
<label>First Name</label>
<input type="text" value.bind="userModel.firstName" validate="firstName" class="form-control">
</div>
</form>
</template>