Angular ReactiveForm to Model Mapping
up vote
2
down vote
favorite
I've been developing an app for a month now. I have come across many problems and almost all of them I've found solutions instead of opening threads but there is one design problem I still haven't figured out.
Suppose I have a small component called MonkeyComponent, it just has a form for my model (Monkey)
export class Car {
model: string
}
export class Monkey {
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
name: string;
age: number;
car: Car; // another model (could be added to form later)
}
export class AppComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
// now I need to map my form value to my monkey model
// but they are mismatched (because doc can be used to populate
// either pubId or driversLicense)
}
}
This form mapping is common in many models of my project (one field of the form representing another field in the model)
Also I can't create multiple fields (client requirement)
How would you create this mapping? I am open to design suggestions (class model is not required if you have a better option)
Is there a Reactive-way to do this?
Is it avoidable to not have to use Object.assign and then manually mapping the divergent fields?
A clean solution would be to find a way to this.formGroup.value
be
{
pubId: '1234567890123',
name: 'Miwalkey',
age: 12,
}
or
{
driversLicense: '12345678',
name: 'Miwalkey',
age: 12,
}
depending on the value (length) of doc.
angular angular-reactive-forms angular-forms angular-formbuilder
|
show 3 more comments
up vote
2
down vote
favorite
I've been developing an app for a month now. I have come across many problems and almost all of them I've found solutions instead of opening threads but there is one design problem I still haven't figured out.
Suppose I have a small component called MonkeyComponent, it just has a form for my model (Monkey)
export class Car {
model: string
}
export class Monkey {
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
name: string;
age: number;
car: Car; // another model (could be added to form later)
}
export class AppComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
// now I need to map my form value to my monkey model
// but they are mismatched (because doc can be used to populate
// either pubId or driversLicense)
}
}
This form mapping is common in many models of my project (one field of the form representing another field in the model)
Also I can't create multiple fields (client requirement)
How would you create this mapping? I am open to design suggestions (class model is not required if you have a better option)
Is there a Reactive-way to do this?
Is it avoidable to not have to use Object.assign and then manually mapping the divergent fields?
A clean solution would be to find a way to this.formGroup.value
be
{
pubId: '1234567890123',
name: 'Miwalkey',
age: 12,
}
or
{
driversLicense: '12345678',
name: 'Miwalkey',
age: 12,
}
depending on the value (length) of doc.
angular angular-reactive-forms angular-forms angular-formbuilder
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
1
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
1
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' haslength===8
(set driversLicense) or 13 (set pubId)
– Gabriel Veloso
Nov 9 at 4:30
|
show 3 more comments
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I've been developing an app for a month now. I have come across many problems and almost all of them I've found solutions instead of opening threads but there is one design problem I still haven't figured out.
Suppose I have a small component called MonkeyComponent, it just has a form for my model (Monkey)
export class Car {
model: string
}
export class Monkey {
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
name: string;
age: number;
car: Car; // another model (could be added to form later)
}
export class AppComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
// now I need to map my form value to my monkey model
// but they are mismatched (because doc can be used to populate
// either pubId or driversLicense)
}
}
This form mapping is common in many models of my project (one field of the form representing another field in the model)
Also I can't create multiple fields (client requirement)
How would you create this mapping? I am open to design suggestions (class model is not required if you have a better option)
Is there a Reactive-way to do this?
Is it avoidable to not have to use Object.assign and then manually mapping the divergent fields?
A clean solution would be to find a way to this.formGroup.value
be
{
pubId: '1234567890123',
name: 'Miwalkey',
age: 12,
}
or
{
driversLicense: '12345678',
name: 'Miwalkey',
age: 12,
}
depending on the value (length) of doc.
angular angular-reactive-forms angular-forms angular-formbuilder
I've been developing an app for a month now. I have come across many problems and almost all of them I've found solutions instead of opening threads but there is one design problem I still haven't figured out.
Suppose I have a small component called MonkeyComponent, it just has a form for my model (Monkey)
export class Car {
model: string
}
export class Monkey {
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
name: string;
age: number;
car: Car; // another model (could be added to form later)
}
export class AppComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
// now I need to map my form value to my monkey model
// but they are mismatched (because doc can be used to populate
// either pubId or driversLicense)
}
}
This form mapping is common in many models of my project (one field of the form representing another field in the model)
Also I can't create multiple fields (client requirement)
How would you create this mapping? I am open to design suggestions (class model is not required if you have a better option)
Is there a Reactive-way to do this?
Is it avoidable to not have to use Object.assign and then manually mapping the divergent fields?
A clean solution would be to find a way to this.formGroup.value
be
{
pubId: '1234567890123',
name: 'Miwalkey',
age: 12,
}
or
{
driversLicense: '12345678',
name: 'Miwalkey',
age: 12,
}
depending on the value (length) of doc.
angular angular-reactive-forms angular-forms angular-formbuilder
angular angular-reactive-forms angular-forms angular-formbuilder
edited Nov 9 at 4:48
asked Nov 9 at 4:17
Gabriel Veloso
164
164
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
1
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
1
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' haslength===8
(set driversLicense) or 13 (set pubId)
– Gabriel Veloso
Nov 9 at 4:30
|
show 3 more comments
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
1
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
1
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' haslength===8
(set driversLicense) or 13 (set pubId)
– Gabriel Veloso
Nov 9 at 4:30
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
1
1
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
1
1
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' has
length===8
(set driversLicense) or 13 (set pubId)– Gabriel Veloso
Nov 9 at 4:30
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' has
length===8
(set driversLicense) or 13 (set pubId)– Gabriel Veloso
Nov 9 at 4:30
|
show 3 more comments
3 Answers
3
active
oldest
votes
up vote
1
down vote
accepted
I have created a sample example based on your need of model-based reactive form.
I have used @rxweb/reactive-form-validators to achieve model based reactive form binding and value changes can be applied non FormControl fields. Later, I will explain in detail why I have used @rxweb/reactive-form-validators.
Let me describe What I have done in the sample example.
Step 1: I have created two model Monkey and Car as per your fields.
In the Monkey Model I have applied some validation decorators(required, minLength,maxLength,propObject), those will mark FormControl is valid or not. If you see the property Doc of Monkey model, I have applied if/else clause to set the value based on your business requirement.
Here is the Monkey Model:
import { required,digit,prop,range,propObject,minLength,maxLength } from "@rxweb/reactive-form-validators"
import { Car } from './car.model'
export class Monkey {
private _docValue:string;
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
@required()
name: string;
@digit()
age: number;
@digit()
@minLength({value:8})
@maxLength({value:13})
set doc(value:string){
this._docValue = value;
if(value && value.length ==8)
this.driversLicense = value;
else if(value && value.length == 13)
{
this.driversLicense = undefined;
this.pubId = value;
}
}
get doc() :string {
return this._docValue;
}
@propObject(Car)
car: Car; // another model (could be added to form later)
}
In the Car Model I have applied required validation decorator, just for your reference:
Here is the Car Model:
import { required } from "@rxweb/reactive-form-validators"
export class Car {
@required()
model:string;
}
Step 2: In the component I have used ‘RxFormBuilder’ instead of Angular ‘FormBuilder’, because ‘RxFormBuilder’ provides model based reactive form binding. You don’t need to subscribe valueChange or don’t need to call setValue method each, this will automatically managed by rxweb validation framework.
Here is the Component Code:
export class AppComponent implements OnInit {
monkeyFormGroup:FormGroup
monkey:Monkey;
constructor(private formBuilder:RxFormBuilder){}
ngOnInit(){
this.monkey = new Monkey();
this.monkey.car = new Car();
this.monkeyFormGroup = this.formBuilder.formGroup(this.monkey)
}
}
If you see the above code I have created a model object and pass it to the formGroup method of RxFormBuilder to generate the Angular FormGroup object. If you don’t want to create a Nested FormGroup then don’t define Car object in the Monkey class object property.
Step 3: On the HTML side follow the standard angular practices to bind the form.
Step 4: While passing data to the server, try to use Monkey model object instead of FormGroup value, because you have two properties(driversLicense & pubId) which are not available in the FormGroup.
Here is the Filled Json of monkey Model Object
{ "car": { "model": "Ford" }, "_docValue": "1234567890123", "pubId": "1234567890123", "name": "Miwalkey", "age": "12" }
Why I have used @rxweb/reactive-form-validators?
This is the new concept of model-based reactive form validation in angular based application from rxweb validation framework. But I believe this is a more efficient way to design the form because your validation and business logic will be centralized in the class. You can use the same model in multiple components without writing the same code again and again.
For more information about rxweb validation decorators https://rxweb.io/validation-decorators/alpha
Steps I have followed to achieve this:
- npm install @rxweb/reactive-form-validators
- import 'RxReactiveFormsModule' in root module.
- Follow the above mentioned steps.
Please let me know if you have any question.
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
add a comment |
up vote
1
down vote
I think this would be the designed approach:
ngOnInit() {
this.formGroup.valueChanges.subscribe(val => {
if (val.doc.length === 13) {
monkey.pubId = val.doc;
} else {
monkey.driversLicense = val.doc;
}
});
}
or you could do
this.formGroup.get('doc').valueChanges.subscribe(val => {
if (val.length === 13) {
monkey.pubId = val;
} else {
monkey.driversLicense = val;
}
});
also if you're using ngModel you could put the same logic inside of an (ngModelChange)
callback.
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
add a comment |
up vote
-1
down vote
My current solution is this (I find this VERY ugly)
Base Form Model
export class FormModel {
constructor(input?: any) {
if (input) {
this.fromJSON(input);
}
}
fromJSON(input: any): this {
return Object.assign(this, input);
}
}
Car (model)
export class Car extends FormModel {
model: string;
}
Monkey (model)
export class Monkey extends FormModel {
pubId?: string;
driversLicense?: string;
car: Car;
name: string;
age: number;
fromJSON(input: any): this {
super.fromJSON(input);
this.setDoc(input.doc);
this.car = new Car(input.car);
return this;
}
setDoc(doc: string) {
if (doc.length === 8) {
this.driversLicense = doc;
} else if (doc.length === 13) {
this.pubId = doc;
}
delete this['doc'];
}
}
MonkeyComponent
export class MonkeyComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
const monkey = new Monkey(this.formGroup.value);
console.log(monkey );
}
}
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
I have created a sample example based on your need of model-based reactive form.
I have used @rxweb/reactive-form-validators to achieve model based reactive form binding and value changes can be applied non FormControl fields. Later, I will explain in detail why I have used @rxweb/reactive-form-validators.
Let me describe What I have done in the sample example.
Step 1: I have created two model Monkey and Car as per your fields.
In the Monkey Model I have applied some validation decorators(required, minLength,maxLength,propObject), those will mark FormControl is valid or not. If you see the property Doc of Monkey model, I have applied if/else clause to set the value based on your business requirement.
Here is the Monkey Model:
import { required,digit,prop,range,propObject,minLength,maxLength } from "@rxweb/reactive-form-validators"
import { Car } from './car.model'
export class Monkey {
private _docValue:string;
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
@required()
name: string;
@digit()
age: number;
@digit()
@minLength({value:8})
@maxLength({value:13})
set doc(value:string){
this._docValue = value;
if(value && value.length ==8)
this.driversLicense = value;
else if(value && value.length == 13)
{
this.driversLicense = undefined;
this.pubId = value;
}
}
get doc() :string {
return this._docValue;
}
@propObject(Car)
car: Car; // another model (could be added to form later)
}
In the Car Model I have applied required validation decorator, just for your reference:
Here is the Car Model:
import { required } from "@rxweb/reactive-form-validators"
export class Car {
@required()
model:string;
}
Step 2: In the component I have used ‘RxFormBuilder’ instead of Angular ‘FormBuilder’, because ‘RxFormBuilder’ provides model based reactive form binding. You don’t need to subscribe valueChange or don’t need to call setValue method each, this will automatically managed by rxweb validation framework.
Here is the Component Code:
export class AppComponent implements OnInit {
monkeyFormGroup:FormGroup
monkey:Monkey;
constructor(private formBuilder:RxFormBuilder){}
ngOnInit(){
this.monkey = new Monkey();
this.monkey.car = new Car();
this.monkeyFormGroup = this.formBuilder.formGroup(this.monkey)
}
}
If you see the above code I have created a model object and pass it to the formGroup method of RxFormBuilder to generate the Angular FormGroup object. If you don’t want to create a Nested FormGroup then don’t define Car object in the Monkey class object property.
Step 3: On the HTML side follow the standard angular practices to bind the form.
Step 4: While passing data to the server, try to use Monkey model object instead of FormGroup value, because you have two properties(driversLicense & pubId) which are not available in the FormGroup.
Here is the Filled Json of monkey Model Object
{ "car": { "model": "Ford" }, "_docValue": "1234567890123", "pubId": "1234567890123", "name": "Miwalkey", "age": "12" }
Why I have used @rxweb/reactive-form-validators?
This is the new concept of model-based reactive form validation in angular based application from rxweb validation framework. But I believe this is a more efficient way to design the form because your validation and business logic will be centralized in the class. You can use the same model in multiple components without writing the same code again and again.
For more information about rxweb validation decorators https://rxweb.io/validation-decorators/alpha
Steps I have followed to achieve this:
- npm install @rxweb/reactive-form-validators
- import 'RxReactiveFormsModule' in root module.
- Follow the above mentioned steps.
Please let me know if you have any question.
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
add a comment |
up vote
1
down vote
accepted
I have created a sample example based on your need of model-based reactive form.
I have used @rxweb/reactive-form-validators to achieve model based reactive form binding and value changes can be applied non FormControl fields. Later, I will explain in detail why I have used @rxweb/reactive-form-validators.
Let me describe What I have done in the sample example.
Step 1: I have created two model Monkey and Car as per your fields.
In the Monkey Model I have applied some validation decorators(required, minLength,maxLength,propObject), those will mark FormControl is valid or not. If you see the property Doc of Monkey model, I have applied if/else clause to set the value based on your business requirement.
Here is the Monkey Model:
import { required,digit,prop,range,propObject,minLength,maxLength } from "@rxweb/reactive-form-validators"
import { Car } from './car.model'
export class Monkey {
private _docValue:string;
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
@required()
name: string;
@digit()
age: number;
@digit()
@minLength({value:8})
@maxLength({value:13})
set doc(value:string){
this._docValue = value;
if(value && value.length ==8)
this.driversLicense = value;
else if(value && value.length == 13)
{
this.driversLicense = undefined;
this.pubId = value;
}
}
get doc() :string {
return this._docValue;
}
@propObject(Car)
car: Car; // another model (could be added to form later)
}
In the Car Model I have applied required validation decorator, just for your reference:
Here is the Car Model:
import { required } from "@rxweb/reactive-form-validators"
export class Car {
@required()
model:string;
}
Step 2: In the component I have used ‘RxFormBuilder’ instead of Angular ‘FormBuilder’, because ‘RxFormBuilder’ provides model based reactive form binding. You don’t need to subscribe valueChange or don’t need to call setValue method each, this will automatically managed by rxweb validation framework.
Here is the Component Code:
export class AppComponent implements OnInit {
monkeyFormGroup:FormGroup
monkey:Monkey;
constructor(private formBuilder:RxFormBuilder){}
ngOnInit(){
this.monkey = new Monkey();
this.monkey.car = new Car();
this.monkeyFormGroup = this.formBuilder.formGroup(this.monkey)
}
}
If you see the above code I have created a model object and pass it to the formGroup method of RxFormBuilder to generate the Angular FormGroup object. If you don’t want to create a Nested FormGroup then don’t define Car object in the Monkey class object property.
Step 3: On the HTML side follow the standard angular practices to bind the form.
Step 4: While passing data to the server, try to use Monkey model object instead of FormGroup value, because you have two properties(driversLicense & pubId) which are not available in the FormGroup.
Here is the Filled Json of monkey Model Object
{ "car": { "model": "Ford" }, "_docValue": "1234567890123", "pubId": "1234567890123", "name": "Miwalkey", "age": "12" }
Why I have used @rxweb/reactive-form-validators?
This is the new concept of model-based reactive form validation in angular based application from rxweb validation framework. But I believe this is a more efficient way to design the form because your validation and business logic will be centralized in the class. You can use the same model in multiple components without writing the same code again and again.
For more information about rxweb validation decorators https://rxweb.io/validation-decorators/alpha
Steps I have followed to achieve this:
- npm install @rxweb/reactive-form-validators
- import 'RxReactiveFormsModule' in root module.
- Follow the above mentioned steps.
Please let me know if you have any question.
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
I have created a sample example based on your need of model-based reactive form.
I have used @rxweb/reactive-form-validators to achieve model based reactive form binding and value changes can be applied non FormControl fields. Later, I will explain in detail why I have used @rxweb/reactive-form-validators.
Let me describe What I have done in the sample example.
Step 1: I have created two model Monkey and Car as per your fields.
In the Monkey Model I have applied some validation decorators(required, minLength,maxLength,propObject), those will mark FormControl is valid or not. If you see the property Doc of Monkey model, I have applied if/else clause to set the value based on your business requirement.
Here is the Monkey Model:
import { required,digit,prop,range,propObject,minLength,maxLength } from "@rxweb/reactive-form-validators"
import { Car } from './car.model'
export class Monkey {
private _docValue:string;
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
@required()
name: string;
@digit()
age: number;
@digit()
@minLength({value:8})
@maxLength({value:13})
set doc(value:string){
this._docValue = value;
if(value && value.length ==8)
this.driversLicense = value;
else if(value && value.length == 13)
{
this.driversLicense = undefined;
this.pubId = value;
}
}
get doc() :string {
return this._docValue;
}
@propObject(Car)
car: Car; // another model (could be added to form later)
}
In the Car Model I have applied required validation decorator, just for your reference:
Here is the Car Model:
import { required } from "@rxweb/reactive-form-validators"
export class Car {
@required()
model:string;
}
Step 2: In the component I have used ‘RxFormBuilder’ instead of Angular ‘FormBuilder’, because ‘RxFormBuilder’ provides model based reactive form binding. You don’t need to subscribe valueChange or don’t need to call setValue method each, this will automatically managed by rxweb validation framework.
Here is the Component Code:
export class AppComponent implements OnInit {
monkeyFormGroup:FormGroup
monkey:Monkey;
constructor(private formBuilder:RxFormBuilder){}
ngOnInit(){
this.monkey = new Monkey();
this.monkey.car = new Car();
this.monkeyFormGroup = this.formBuilder.formGroup(this.monkey)
}
}
If you see the above code I have created a model object and pass it to the formGroup method of RxFormBuilder to generate the Angular FormGroup object. If you don’t want to create a Nested FormGroup then don’t define Car object in the Monkey class object property.
Step 3: On the HTML side follow the standard angular practices to bind the form.
Step 4: While passing data to the server, try to use Monkey model object instead of FormGroup value, because you have two properties(driversLicense & pubId) which are not available in the FormGroup.
Here is the Filled Json of monkey Model Object
{ "car": { "model": "Ford" }, "_docValue": "1234567890123", "pubId": "1234567890123", "name": "Miwalkey", "age": "12" }
Why I have used @rxweb/reactive-form-validators?
This is the new concept of model-based reactive form validation in angular based application from rxweb validation framework. But I believe this is a more efficient way to design the form because your validation and business logic will be centralized in the class. You can use the same model in multiple components without writing the same code again and again.
For more information about rxweb validation decorators https://rxweb.io/validation-decorators/alpha
Steps I have followed to achieve this:
- npm install @rxweb/reactive-form-validators
- import 'RxReactiveFormsModule' in root module.
- Follow the above mentioned steps.
Please let me know if you have any question.
I have created a sample example based on your need of model-based reactive form.
I have used @rxweb/reactive-form-validators to achieve model based reactive form binding and value changes can be applied non FormControl fields. Later, I will explain in detail why I have used @rxweb/reactive-form-validators.
Let me describe What I have done in the sample example.
Step 1: I have created two model Monkey and Car as per your fields.
In the Monkey Model I have applied some validation decorators(required, minLength,maxLength,propObject), those will mark FormControl is valid or not. If you see the property Doc of Monkey model, I have applied if/else clause to set the value based on your business requirement.
Here is the Monkey Model:
import { required,digit,prop,range,propObject,minLength,maxLength } from "@rxweb/reactive-form-validators"
import { Car } from './car.model'
export class Monkey {
private _docValue:string;
// If doc contains 8 digits
driversLicense?: string;
// If doc contains 13 digits
pubId?: string;
@required()
name: string;
@digit()
age: number;
@digit()
@minLength({value:8})
@maxLength({value:13})
set doc(value:string){
this._docValue = value;
if(value && value.length ==8)
this.driversLicense = value;
else if(value && value.length == 13)
{
this.driversLicense = undefined;
this.pubId = value;
}
}
get doc() :string {
return this._docValue;
}
@propObject(Car)
car: Car; // another model (could be added to form later)
}
In the Car Model I have applied required validation decorator, just for your reference:
Here is the Car Model:
import { required } from "@rxweb/reactive-form-validators"
export class Car {
@required()
model:string;
}
Step 2: In the component I have used ‘RxFormBuilder’ instead of Angular ‘FormBuilder’, because ‘RxFormBuilder’ provides model based reactive form binding. You don’t need to subscribe valueChange or don’t need to call setValue method each, this will automatically managed by rxweb validation framework.
Here is the Component Code:
export class AppComponent implements OnInit {
monkeyFormGroup:FormGroup
monkey:Monkey;
constructor(private formBuilder:RxFormBuilder){}
ngOnInit(){
this.monkey = new Monkey();
this.monkey.car = new Car();
this.monkeyFormGroup = this.formBuilder.formGroup(this.monkey)
}
}
If you see the above code I have created a model object and pass it to the formGroup method of RxFormBuilder to generate the Angular FormGroup object. If you don’t want to create a Nested FormGroup then don’t define Car object in the Monkey class object property.
Step 3: On the HTML side follow the standard angular practices to bind the form.
Step 4: While passing data to the server, try to use Monkey model object instead of FormGroup value, because you have two properties(driversLicense & pubId) which are not available in the FormGroup.
Here is the Filled Json of monkey Model Object
{ "car": { "model": "Ford" }, "_docValue": "1234567890123", "pubId": "1234567890123", "name": "Miwalkey", "age": "12" }
Why I have used @rxweb/reactive-form-validators?
This is the new concept of model-based reactive form validation in angular based application from rxweb validation framework. But I believe this is a more efficient way to design the form because your validation and business logic will be centralized in the class. You can use the same model in multiple components without writing the same code again and again.
For more information about rxweb validation decorators https://rxweb.io/validation-decorators/alpha
Steps I have followed to achieve this:
- npm install @rxweb/reactive-form-validators
- import 'RxReactiveFormsModule' in root module.
- Follow the above mentioned steps.
Please let me know if you have any question.
edited Nov 9 at 6:20
answered Nov 9 at 5:43
Ajay Ojha
94027
94027
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
add a comment |
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
1
1
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Nice library! That's what I've been looking for. I haven't found the propObject() decorator in the docs. Where did you found info for that?
– Gabriel Veloso
Nov 9 at 11:51
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
Thanks, I have designed this framework :), all features of validation framework documentation are not available on rxweb.io site due to lots of APIs in the framework. maybe all APIs documentation will be available in the next week. till the time If you will not find anything on the rxweb.io site, then please refer this link : stackblitz.com/edit/… provided link nested FormGroup and FormArray example is included. if you have any question, While implementing this solution in your project then please let me know.
– Ajay Ojha
Nov 9 at 12:08
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
I had a few problems trying to solve other problems in my project. I have a few suggestions for the library.
– Gabriel Veloso
Nov 9 at 14:14
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
Please create a pull request on our github repo github.com/rxweb/rxweb/issues, I will get back ASAP. otherwise, you can discuss with me on our gitter gitter.im/rxweb-project/…
– Ajay Ojha
Nov 9 at 14:21
add a comment |
up vote
1
down vote
I think this would be the designed approach:
ngOnInit() {
this.formGroup.valueChanges.subscribe(val => {
if (val.doc.length === 13) {
monkey.pubId = val.doc;
} else {
monkey.driversLicense = val.doc;
}
});
}
or you could do
this.formGroup.get('doc').valueChanges.subscribe(val => {
if (val.length === 13) {
monkey.pubId = val;
} else {
monkey.driversLicense = val;
}
});
also if you're using ngModel you could put the same logic inside of an (ngModelChange)
callback.
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
add a comment |
up vote
1
down vote
I think this would be the designed approach:
ngOnInit() {
this.formGroup.valueChanges.subscribe(val => {
if (val.doc.length === 13) {
monkey.pubId = val.doc;
} else {
monkey.driversLicense = val.doc;
}
});
}
or you could do
this.formGroup.get('doc').valueChanges.subscribe(val => {
if (val.length === 13) {
monkey.pubId = val;
} else {
monkey.driversLicense = val;
}
});
also if you're using ngModel you could put the same logic inside of an (ngModelChange)
callback.
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
add a comment |
up vote
1
down vote
up vote
1
down vote
I think this would be the designed approach:
ngOnInit() {
this.formGroup.valueChanges.subscribe(val => {
if (val.doc.length === 13) {
monkey.pubId = val.doc;
} else {
monkey.driversLicense = val.doc;
}
});
}
or you could do
this.formGroup.get('doc').valueChanges.subscribe(val => {
if (val.length === 13) {
monkey.pubId = val;
} else {
monkey.driversLicense = val;
}
});
also if you're using ngModel you could put the same logic inside of an (ngModelChange)
callback.
I think this would be the designed approach:
ngOnInit() {
this.formGroup.valueChanges.subscribe(val => {
if (val.doc.length === 13) {
monkey.pubId = val.doc;
} else {
monkey.driversLicense = val.doc;
}
});
}
or you could do
this.formGroup.get('doc').valueChanges.subscribe(val => {
if (val.length === 13) {
monkey.pubId = val;
} else {
monkey.driversLicense = val;
}
});
also if you're using ngModel you could put the same logic inside of an (ngModelChange)
callback.
edited Nov 9 at 5:08
answered Nov 9 at 4:49
JBoothUA
825424
825424
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
add a comment |
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
1
1
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
This solves but adds business logic to component, which for me is highly undesired. By the way, the 'doc' field is the one that represents either pubId or driversLicense
– Gabriel Veloso
Nov 9 at 4:57
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
as far as I know if you want it "reactive" you'll have to add some logic to the formGroup property on your component
– JBoothUA
Nov 9 at 5:10
1
1
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
look at the accepted answer.
– Gabriel Veloso
Nov 9 at 11:49
add a comment |
up vote
-1
down vote
My current solution is this (I find this VERY ugly)
Base Form Model
export class FormModel {
constructor(input?: any) {
if (input) {
this.fromJSON(input);
}
}
fromJSON(input: any): this {
return Object.assign(this, input);
}
}
Car (model)
export class Car extends FormModel {
model: string;
}
Monkey (model)
export class Monkey extends FormModel {
pubId?: string;
driversLicense?: string;
car: Car;
name: string;
age: number;
fromJSON(input: any): this {
super.fromJSON(input);
this.setDoc(input.doc);
this.car = new Car(input.car);
return this;
}
setDoc(doc: string) {
if (doc.length === 8) {
this.driversLicense = doc;
} else if (doc.length === 13) {
this.pubId = doc;
}
delete this['doc'];
}
}
MonkeyComponent
export class MonkeyComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
const monkey = new Monkey(this.formGroup.value);
console.log(monkey );
}
}
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
add a comment |
up vote
-1
down vote
My current solution is this (I find this VERY ugly)
Base Form Model
export class FormModel {
constructor(input?: any) {
if (input) {
this.fromJSON(input);
}
}
fromJSON(input: any): this {
return Object.assign(this, input);
}
}
Car (model)
export class Car extends FormModel {
model: string;
}
Monkey (model)
export class Monkey extends FormModel {
pubId?: string;
driversLicense?: string;
car: Car;
name: string;
age: number;
fromJSON(input: any): this {
super.fromJSON(input);
this.setDoc(input.doc);
this.car = new Car(input.car);
return this;
}
setDoc(doc: string) {
if (doc.length === 8) {
this.driversLicense = doc;
} else if (doc.length === 13) {
this.pubId = doc;
}
delete this['doc'];
}
}
MonkeyComponent
export class MonkeyComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
const monkey = new Monkey(this.formGroup.value);
console.log(monkey );
}
}
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
add a comment |
up vote
-1
down vote
up vote
-1
down vote
My current solution is this (I find this VERY ugly)
Base Form Model
export class FormModel {
constructor(input?: any) {
if (input) {
this.fromJSON(input);
}
}
fromJSON(input: any): this {
return Object.assign(this, input);
}
}
Car (model)
export class Car extends FormModel {
model: string;
}
Monkey (model)
export class Monkey extends FormModel {
pubId?: string;
driversLicense?: string;
car: Car;
name: string;
age: number;
fromJSON(input: any): this {
super.fromJSON(input);
this.setDoc(input.doc);
this.car = new Car(input.car);
return this;
}
setDoc(doc: string) {
if (doc.length === 8) {
this.driversLicense = doc;
} else if (doc.length === 13) {
this.pubId = doc;
}
delete this['doc'];
}
}
MonkeyComponent
export class MonkeyComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
const monkey = new Monkey(this.formGroup.value);
console.log(monkey );
}
}
My current solution is this (I find this VERY ugly)
Base Form Model
export class FormModel {
constructor(input?: any) {
if (input) {
this.fromJSON(input);
}
}
fromJSON(input: any): this {
return Object.assign(this, input);
}
}
Car (model)
export class Car extends FormModel {
model: string;
}
Monkey (model)
export class Monkey extends FormModel {
pubId?: string;
driversLicense?: string;
car: Car;
name: string;
age: number;
fromJSON(input: any): this {
super.fromJSON(input);
this.setDoc(input.doc);
this.car = new Car(input.car);
return this;
}
setDoc(doc: string) {
if (doc.length === 8) {
this.driversLicense = doc;
} else if (doc.length === 13) {
this.pubId = doc;
}
delete this['doc'];
}
}
MonkeyComponent
export class MonkeyComponent {
formGroup: FormGroup;
constructor(private fb: FormBuilder, private store: MonkeyStore) {
this.formGroup = this.fb.group({
name: [''],
doc: [''],
age: [''],
});
}
save() {
const monkey = new Monkey(this.formGroup.value);
console.log(monkey );
}
}
answered Nov 9 at 4:54
Gabriel Veloso
164
164
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
add a comment |
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
I have created another example based on your code provide code with minor changes. I have removed FormModel and generate the FormGroup with RxFormBuilder. Here is the link stackblitz.com/edit/…
– Ajay Ojha
Nov 9 at 8:16
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53219808%2fangular-reactiveform-to-model-mapping%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I'm kind of confused with what youre exactly trying to do? and what you are currently experiencing?
– JBoothUA
Nov 9 at 4:21
1
@JBoothUA I added more info
– Gabriel Veloso
Nov 9 at 4:22
But basically as I said, I am trying to map my form fields to my monkey model. But, as you can see, the monkey model has 2 fields (pubId and driversLicense) both of them are documents. But the form has only 1 field (the user can specify any of these two document options), and I need to set to my model property (pubId or driversLicense) depending of what the 'doc' field represents on my model (I can know this based on the 'doc' field length, as commented on the model)
– Gabriel Veloso
Nov 9 at 4:26
You can dynamically add/remove form controls later after initialization. Is that what you are looking for?
– Amit Chigadani
Nov 9 at 4:28
1
@AmitChigadani nop, I am trying to set the correct field on my Monkey model. That depends on the length of the 'doc' field in the form. After the user submits I need to check either if 'doc' has
length===8
(set driversLicense) or 13 (set pubId)– Gabriel Veloso
Nov 9 at 4:30