angular-schema-form: Add custom html to form fields - angularjs

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"
}
];

Related

Calendar Ant Design: How to show events with variable dates?

I am looking for a way to show events in an Ant Desing Calendar using dateCellRender with the dates from an variable object, like this one:
[
{
"id": 1,
"content": "Example",
"date": "01/05/2022",
"horario": [
"2022-05-26T06:00:00.925Z",
"2022-05-26T07:00:00.478Z"
],
},
{
"id": 2,
"content": "Example",
"date": "08/05/2022",
"horario": [
"2022-05-26T11:00:00.859Z",
"2022-05-26T14:00:00.976Z"
],
}
]
The normal way to show events is using a switch, like you can see in this CodeSandbox from AntD: https://codesandbox.io/s/ruj266
My object comes from the backend and will always change, there is a way to show dynamic events using that object?
Since antd calendar works with moment object, so when you try to render the calendar, you can covert the value of current date to string by using format method of moment object like this:
<Calendar dateCellRender={(value) => {
const stringValue = value.format("DD/MM/yyyy");
return (...);
};} />;
and compare the result of format method with date values in your data, I implemented an example by using of your data example here on codesandbox:
antd-calendar-example
is this what you are looking for?

RFJS validation show error message with key, not label

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}
.
.
.
/>

how to use custom fields in line items within commercetools platform

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

AngularJS custom directive within ng-repeat with dynamic attributes and two way binding

I'm banging my head on the wall over this for days and finally decided to post this question since I can't find an answer that matches what I'm trying to do.
Context: I'm building a dynamic form building platform that describes form elements in a JSON structure like this -
{
"name": "email",
"type": "email",
"text": "Your Email",
"model": "user.profile.email"
}
And then in the View I have a recursive ng-repeat that includes the field template like this -
<script type="text/ng-template" id="field.html">
<div ng-if="field.type === 'email'" class="{{field.class}}">
<p translate="{{field.text}}"></p>
<input type="{{field.type}}" name="{{field.name}}" class="form-control" dyn-model="{{field.model}}">
</div>
</script>
As you see, I use a custom directive dynModel to create the ng-model attribute with interpolated value of the model from the string value. So far do good.
Now I have a more complex scenario in which I have a collection of fields that can be added or removed by clicking on Add button or removeMe button. See below -
{
"name": "urls",
"type": "collection",
"text": "Your Profile URLs",
"model": "user.profile.urls",
"items": [
{
"name": "url",
"type": "url",
"text": "Facebook URL",
"model": "url"
},
{
"name": "url",
"type": "url",
"text": "Facebook URL",
"model": "url"
}
],
"action_button": {
"name": "add",
"type": "action",
"action": "addURL"
}
}
<div ng-if="field.type === 'collection'">
<button class="btn btn-info" dyn-click click-action="{{field.action_button.action}}" click-model="{{field.model}}">{{field.action_button.text}}</button>
<div dyn-ng-repeat="item in {{field.model}}" >
<div ng-repeat="field in field.items" ng-include src="'field.html'"></div>
</div>
</div>
As you'll notice, I have another custom directive that takes care of interpolation of {{field.model}} from the previous ng-repeat (not shown).
Now to the crux of the issue. As you see in the template, I have nested ng-repeats, the first one iterates through user.profile.urls and the second one iterates through the field parameters in JSON and creates the HTML tags, etc. One of those fields is a button (action_button) that is used to add more URLS to the list. When I click the button, I want it to trigger a function in my controller and effectively add a new child to the parent model (user.profile.urls). I then also want each URL, existing and new to have a remove button next to them that will be dynamic and will remove that particular item from the model.
If you see the code above, I have a custom directive dyn-click that reads in the
click-action="{{field.action_button.action}}"
That contains the function name (addURL) to be called that resides in my controller and the model
click-model="{{field.model}}"
(user.profile.urls) to which the new item is to be added. This is not working. The reason for this complexity is that I have multiple levels of nesting and at each level there are dynamic elements that need to be interpolated and bound. The directive dyn-click looks like this right now -
exports = module.exports = function (ngModule) {
ngModule.directive("dynClick",function() {
return {
restrict: 'A',
link: function(scope,element,attrs) {
$(element).click(function(e, rowid){
scope.clickAction(scope.clickModel, scope.$index);
});
}
};
});
};
With this code, when I click on the rendered form's Add button, the code in the $(element).click method above gets executed giving the following error -
Uncaught TypeError: undefined is not a function
I have tried a few different things with scope:{} in the dyn-click directive, with different errors and none of them have worked completely with two way binding of the model and calling the function as expected.
Help!
EDIT-1 - please see the comments:
$(element).click(function(e, rowid){
scope.$eval(attrs["clickAction"])(scope.$eval(attrs["clickModel"]), scope.$index);
});
EDIT-2: The plunker is here - http://plnkr.co/edit/DoacjRnO61g4IYodPwWu?p=preview. Still tweaking it to get it right, but you guys should be able to see the necessary pieces. Thanks!
EDIT-3: Thanks Sebastian. The new plunker is here - http://plnkr.co/edit/Z6ViT7scubMxa17SFgtx?p=preview . The issue with the field.items ng-repeat still exists. For some reason the inner ng-repeat is not being executed. Any ideas? Josep, Sebastian?

Association ExtJs MVC 4.2

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.

Resources