Using https://react-jsonschema-form.readthedocs.io to render a form based on a json schema I can define validation for every field. This is great and easy, the only thing I am looking for is a way to create a more meaning full validation error.
E.g.
Schema:
{
"title": "Contextualized errors",
"type": "object",
"properties": {
"firstName": {
"type": "string",
"title": "First name",
"minLength": 8,
"pattern": "\\d+"
},
}
}
This provides validation and returns an error text like:
firstName: should NOT be shorter than 8 characters
firstName: should match pattern "\d+"
I want to change this first part, into 'First name' or even translate it. How am I possible to do this?
EDIT
I assume it would be possible to define firstName as First name, which would require some 'complex' remapping with formData object to actual keys.
Okay, so you can define your own Validation error for that.
validate = (formData, errors) => {
if(formData.firstName.length<8){
errors.firstName.addError('First name can be of 8 or more character long') // your custom error
}
else if(formData.firstName.search(regexPattern)){
errors.firstName.addError('First name should match your given pattern')
}
return errors;
};
and then just pass this function to your Form.
<Form
...
validate={this.validate}
showErrorList={false}
.
.
.
/>
Related
Still in my very first days with Angular and ran into a problem i can't get my head around.
What I am trying to accomplish is sort of creating a way to have a persons name added to a message template.
The templates are loaded from a file like this
this.http.get('../../assets/templatefiles/customtemplates.json').subscribe(data => {this.templateArray = data as any [];
The structure of the JSON file is as follows
[{
"Id": 1,
"Type": "SR Templates",
"Name": "Message 1",
"Body": "Some meaningful text here"
},
{
"Id": 2,
"Type": "SR Templates",
"Name": "Message 2",
"Body": "Some more meaningful text here"
},
{
"Id": 3,
"Type": "GTFO Templates",
"Name": "Message 3",
"Body": "Guess what? Exactly, some even more..blahhh"
}]
All good so far. Then, in my template I use ng-select to create the dropdown list to display the options grouped by Type
<ng-select [items]="templateArray"
bindLabel="Name"
bindValue="Body"
groupBy="Type"
[(ngModel)]="selectedTemplate"
>
<ng-template ng-optgroup-tmp let-item="item">
<strong>{{item.Id}}</strong>
</ng-template>
</ng-select>
So far...working it seems. Templates are grouped by Type and show up in the drop down just fine.
Below the selection is a textarea in which the "Body" value is supposed to be displayed. Works fine as well, when selecting a template from the drop down the text shows fine in the textarea.
The problem I am facing is that there is an input field for the persons name the message will be send to.
I get the name as follows:
<input type="text" [(ngModel)]="srcName" class="form-control" placeholder="Name">
The bit confusing me is how to get/add the persons name to the message using interpolation?
I was hoping for something like just having to change the text in the JSON and adding the interpolation to it but apparently that does not work hehe.
{
"Id": 1,
"Type": "SR Templates",
"Name": "Message 1",
"Body": "Dear {{srcName}, Some meaningful text here"
}
I've been searching up and down, but am ultimately stuck and am desperate for a nudge in the direction I would have to go to actually get that name inserted in the textarea together with the template from the array...
You can make a function that concatenates your selected template and the name in you input, like so:
onSubmit() {
this.message = `Dear ${this.srcName}, ${this.selectedTemplate}`;
}
And then you can add a button that executes this function:
<button (click)="onSubmit()">Submit</button>
Now whenever you select the template you want and add the name you want to the input and click on submit button, you will get a concatenated message with the info you want.
Here is a live demo if you want more explanation.
In the live demo a used a normal HTML select, but it should work the same with angular material select.
##EDIT
If you need to put your srcName inside of your templates body, you will have to create a place holder in your template's body, something like:
"Guess what? Exactly {srcName}, some even more..blahhh"
instead of:
"Guess what? Exactly, some even more..blahhh"
Then you will have to change the onSubmit function:
onSubmit() {
this.message = this.selectedTemplate.replace('{srcName}', this.srcName)
}
I also added the changes to to the live demo.
I have just started to look into angular-schema-form, so this might be something I've missed in the docs or description.
What I am trying to do is to add an icon next to the label of generated form fields and next to the field itself. Like so:
But out of the box angular-schema-form will generate:
I know I can make my own custom field types, but is that the way to go? That would require me to redefine all field types in a custom variant, because I need these two icons and their functionality on all my form fields.
I was hoping there were an easier way to add this functionality to generated html, and an easy way to add functionality (ng-click function) on them.
Edit: After reading through the docs again, I've figured out that I need to define my own custom field type (https://github.com/Textalk/angular-schema-form/blob/development/docs/extending.md)
From what I gather, I need to add the following to my modules config block:
schemaFormDecoratorsProvider.addMapping(
'bootstrapDecorator',
'custominput',
'shared/templates/customInput.tpl.html',
sfBuilderProvider.builders.sfField
);
I have also added the contents of shared/templates/customInput.tpl.html to $templatesCache.
But when I try to render a form, with a schema like
"schema": {
"type": "object",
"properties": {
"firstName": {
"title": "First name",
"type": "string"
},
"lastName": {
"title": "Last name",
"type": "custominput"
},
"age": {
"title": "Age",
"type": "number"
}
}
}
I only see the first field (firstName) and age. The custom type is just ignored.
I have tried to debug my way to the problem, but as far as I can see, the custom field is correctly added to the decorator. I've tried to console.log the schemaFormDecoratorsProvider.decorator() and there I can see my custom field type.
I've also tried to fire off a $scope.$broadcast('schemaFormRedraw') in my controller, but I still only see the built in field types.
As a test, I've tried to define my own decorator, overwriting the default Bootstrap decorator:
schemaFormDecoratorsProvider.defineDecorator('bootstrapDecorator', {
'customType': {template: 'shared/templates/customInput.tpl.html', builder: sfBuilderProvider.stdBuilders},
// The default is special, if the builder can't find a match it uses the default template.
'default': {template: 'shared/templates/customInput.tpl.html', builder: sfBuilderProvider.stdBuilders},
}, []);
I would expect to see all fields to be rendered the same, since I only define a default type and my own custom type. But still, I only see built in types rendered, my custominput is till just ignored.
What am I missing?
I've had this same problem, the problem is that you should not confuse the JSON schema with the form definition.
To render a custom component you have to change the form definition. I.e in your controller your standard form defintion might look something like:
$scope.form = [
"*",
{
type: "submit",
title: "Save"
}
];
You'll have to change this to:
$scope.form = [
"firstName",
"age",
{
key:"lastName",
type:"customInput"
},
{
type: "submit",
title: "Save"
}
];
I actually have to add some custom fields to every line item within the commercetools platform.
Line Item Docs => http://dev.sphere.io/http-api-projects-carts.html#line-item
There I found this: => http://dev.sphere.io/http-api-projects-custom-fields.html#custom-fields
But apparently the docs for custom-fields are way too less in terms of showing "how to use them". Does somebody has any experience with that? A json example would be wonderful, with a bit more explanation. Thanks in advance.
you can create a custom type for line items using the resource type ID "line-item" or "custom-line-item" (http://dev.sphere.io/http-api-projects-custom-fields.html#customizable-resource ) - example:
{
"key": "myLineItemType",
"name": { "en": "my line item type" },
"resourceTypeIds": ["line-item"],
"fieldDefinitions": [
{
"type":{
"name":"LocalizedString"
},
"name":"myField",
"label":{
"en":"my field",
"de":"mein feld"
},
"required":false,
"inputHint":"SingleLine"
}
]
}
Then there are 2 ways of using the new custom type and the new field.
You can set the custom type and a value at the time you create a line item using the "addLineItem" Update action on the cart resource - see this JSON example for instance:
{
"version": 19,
"actions": [{
"action": "addLineItem",
"productId": "9f19f37d-ec10-4ccf-9ff8-e5a295de0c3e",
"variantId": 1,
"quantity": 1
}],
"custom": {
"typeKey": "myLineItemType",
"fields": {
"myField": {
"en":"whats up",
"de":"was ist los"
}
}
}
}
You can set the custom type of the line item with the "setLineItemCustomType" update action on the cart to make the field available. This can work with existing line items.
http://dev.sphere.io/http-api-projects-carts.html#set-line-item-custom-type
We have a scenario in our application where we would like to use multiple instances of the same validator on the same breeze data property. However, when we enter multiple instances of the same validator on the same breeze property, only the last one affects the validation state of that property. This is because the key for breeze errors is propertyName + validatorName.
Example:
"dataProperties": [
{
"name": "fieldA",
"dataType": "String",
"validators": [
{
"name": "requiredCond",
"context": {
"messageTemplate": " fieldA is required if fieldB has a value.",
"dependencyName": "fieldB"
}
},
{
"name": "requiredCond",
"context": {
"messageTemplate": " fieldA is required if fieldC has a value.",
"dependencyName": "fieldC"
}
}
]
}
]
Is there any configuration or custom overriding to enable this behavior?
“one potential solution would be to create multiples of these
validators in breeze, like ‘requiredCond1’, ‘requiredCond2’,
‘requiredCond3’ etc. that all actually point to the same validator
code, that way the error key would be unique….but we would like to
avoid this as it seems pretty ‘hacky’ “
Thanks.
ExtJS 4.2 MVC: I have two models ServiceM and CommentsM. ServiceM has association(hasmany) with CommentsM. I DIDNOT forget to add the requires section ServiceM. Proxy is an ajax type defined in the model itself. I also created stores for each. Coming to the view, I have a grid for viewing all the services which are derived on loading the application. itemdblclick event is used to provide a detailed view about the service which is a window extending a form. The form is popullated by the below code:
var ServiceDetailV = Ext.widget('alias name of the service detail view');
ServiceDetailV.down('form').getForm().loadRecord(record);
I have two questions here.
When using developer tools in google chrome, in the above code I place debugger; at the end. I have highlighted the record, right clicked and evaluated that part. I see the data part and raw part. what is this raw part. It has all the data which the server is giving me(payload), even the nested comments section which is associated with the Service data.
I am able to popullate the fields in the form, but not the list of comments. the list of comments goes into a panel present in the form. How can I popullate the comments section.
JSON data:
{
"data": [
{
"id": 1,
"x": "some text",
"q": "some text",
"a": "some text",
"r":"some text",
"comments": [
{
"id": 87,
"commentDate": "date",
"description": "some text"
},
{
"id": 86,
"commentDate": "date",
"description": "some text"
}
]
} "total": 1,
"success": true}
Now, how can i access the comments field and poppulate the form with this data?
Please shed some knowledge on Associations ExtJs MVC.
Cheers!
Well, I took a step and got the solution for this. the raw parameter actually has the raw JSON payload. In the controller part I have handled it via a select event.
onSelectIssueShowComments : function(selection,record, index, eOpts) {
this.getComments().setRecord(record.raw);
}
I the view part
tpl : [ '<p>Previous Comments: ', '<tpl for="comments">',
'<p>{#}. {description} {commentDate}</p>', '</tpl></p>' ],
setRecord : function(record) {//this record here is record.raw
this.record = record;
if (record) {
this.update(record);
} else {
this.update(' ');
}
}
So it displays the array of comments in a Panel.