Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typeUserAttrs - A new approach #346

Open
eradin opened this issue Dec 21, 2016 · 14 comments
Open

typeUserAttrs - A new approach #346

eradin opened this issue Dec 21, 2016 · 14 comments

Comments

@eradin
Copy link

eradin commented Dec 21, 2016

File this under enhancements.

I have a user who wants more styling control on headers and paragraphs. The typeUserAttrs feature is a really powerful feature in extending a field type in this manner. Although, it currently supports one value per attribute. I would like to control 2 (or more) styles using two user attributes in a similar manner as this. This code illustrates the point and will not work as is.

	typeUserAttrs: {
		header: {
			className: {
				label: 'Color',
				options: {
					'red header': 'Red',
					'green header': 'Green',
					'blue header': 'Blue'
				}
			},
			className: {
				label: 'Position',
				options: {
					'text-left': 'Left',
					'text-center': 'Center',
					'text-right': 'Right'
				}
			}
		}
	}

The problem here is the second overwrites the first and the user is only presented with the second set of options. It would be nice to be able to do something like this to provide better control of styling during form design.

I think the current structure is a bit backwards as it doesn't separate the concepts of design elements and rendering elements. Something like this would yield more flexibility:

typeUserAttrs: {
		text: {
			Min: {
				attribute: 'min',
			},
			Max: {
				attribute: 'max',
			},
			Color: {
				attribute: 'class',
				options: {
					'red': 'Red',
					'green': 'Green',
					'blue': 'Blue',
				},
			},
			Border: {
				attribute: 'class',
				options: {
					'border-single': 'Yes',
					'': 'No',
				},
				style: 'border: 1px solid red'
			},
			Style: {
				attribute: 'style',
			}
		}
}

The object names like Border and Style now define user attributes for that field (they will also be the labels for that attribute). Option 'attribute' indicates which html property this value should be applied to at rendering time. Everything else remains the same as the current implementation.

At rendering time, if that html attribute exists, the values will be appended to it (this could also be configurable). If not, the html attribute will be created whether the browser recognizes it or not.

I haven't yet looked at the code to see how much rework is involved. Please chime in with your thoughts and comments.

@eradin eradin changed the title typeUserAttrs - append vs replace vales typeUserAttrs -multiple fields for an attribute Dec 21, 2016
@eradin eradin changed the title typeUserAttrs -multiple fields for an attribute typeUserAttrs - A new approach Dec 21, 2016
@eradin
Copy link
Author

eradin commented Jan 17, 2017

After taking a fresh look at the this problem, I came up with an easy solution using the existing typeUserAttr. I use HTML's custom data-* atributes to create a custom formbuilder attribute. Here is an example:

typeUserAttrs: {
  header: {
    dataEmphasis: {
      label: 'Emphasis',
      options: {
        'alert': 'Important',
        'inform': 'Info',
        '': 'None'
      }
    }
  }
}

This will create a new attribute on the Header type called Emphasis and it has a couple of choices. alert an inform are classes I created to change the color. It's important to use camel case on the attribute name as data-emphasis will cause a javascript error. Enclosing in quotes doesn't work for the renderer.

Now, after loading the data into formRender

$('#form-data').formRender(formRenderOpts);

I add this simple jquery selector on the new attribute:

// process custom attributes
$('[data-emphasis]').each(function() {
	$(this).addClass($(this).data('emphasis'));
});

And presto, the class is added to the class attribute at run time and the color of the header will be changed.

This is simple and works great. It also provides you with all types of possibilities: validation types, styles, borders etc.

DOWNSIDE: It doesn't render in design mode. It would be nice if it did. Fortunately, I provide a preview button on my form designer so it's a very minor issue.

Hope this helps somebody. It's making my users very happy.

@kevinchappell
Copy link
Owner

@eradin This is excellent. I'm curious as to why the styling is not working in the editor though, perhaps adding specificity to the selector just in the editor would help that. ALso regarding formatting, there are new things coming in future versions:

formatting

@eradin
Copy link
Author

eradin commented Jan 17, 2017

The class nor style attribute will be set in the editor. Only the data attribute is set. How would the editor know the data-emphasis is a class?

There would need to be an attribute event handler like onchange that sets the class or style attribute in the editor. Not sure if that will also take effect on editor load.

@eradin
Copy link
Author

eradin commented Jan 18, 2017

Hey Kevin. By any chance is there an exposed global onOpen, onClose or onLoad event for the builder types? If there is, I think I have a solution to the editor styling. If not, perhaps there should be. It opens up a whole world of possibilities.
onOpen - fired when the type editor is opened
onClose - fired when the type editor is closed
onLoad - fired when the form-data is loaded
others while we're at it: Ondelete, onadd, onsave

I would like to see these at the builder level although onopen and onclose could be useful on the userTypeAttr's.

Perhaps I missed something in the docs.

@kevinchappell
Copy link
Owner

@eradin There are some events but none for the ones you mentioned. There are a number of improvements coming in this area though and they are exposed to an api.

@gilsoneasysoft
Copy link

Hi I want to change the name of the text field that we drag into the builder using dropdown(Where dropdown is equipped with few names like email phone). Current typeUserAttrs has that facility but only 3 values can be used. How can i insert more values to it

@riverofjanuary
Copy link

Hi - is there way to make an extra attribute be a textarea? I tried forcing 'type: textarea' but it still gave me a text field. Thank you for this handy feature!

@kevinchappell
Copy link
Owner

@riverofjanuary is there a reason you cant use the textarea type?

@eradin you probably already saw it but there is now onOpenFIeldEdit and onCloseFieldEdit options. https://formbuilder.readthedocs.io/en/latest/formBuilder/options/onOpenFieldEdit/

To your original issue, I think we could could make style a special attribute that concats its values instead of overwriting then take the final value and generate some scoped css that targets the generated field. This should allow it to work in formBuilder and formRender and prevent polluting the markup with a style attribute.

@kevinchappell kevinchappell self-assigned this Nov 3, 2018
@eradin
Copy link
Author

eradin commented Nov 7, 2018

Kevin. I finally had a chance to play with the onCloseFieldEdit event. By implementing this event, I was able to get the editor to change styles based on my userTypeAttr. But there is a strange occurrence. Here is the scenario:
I have a typeAtrr called emphasis and it has 2 settings, Important (red) and Info (blue). You can change the headings (H1,H2 etc) to a different color. If you go back into the previous threads here, you can see the configuration. I set the onCloseFieldEdit to a function that searches all dataEmphasis attributes and adds the appropriate class. This works just fine mostly. The odd situation is when you change the attribute, lets say from Red to Blue. When you close the drawer, the color reverts to black (default). If you open and close the drawer again, you get the right color. Adding a console.log call to the event function says its being called each time. I think formbuilder is removing the class after my function runs. This does not occur unless you change the current value of the attribute. Other than this quirk, it's an easy solution to updating the editor.

@kevinchappell
Copy link
Owner

@eradin It sounds like the editor might not be internally saving custom attributes typeUserAttrs I'll look into that.

@eradin
Copy link
Author

eradin commented Nov 13, 2018

Looking at the code, it appears formbuilder on Field Edit Close click event does some attribute processing and then calls the onCloseFieldEdit function and then updates the editor. If that is true, the update overrides anything done in onCloseFieldEdit. This only occurs when a change has been made to any of the attributes. It's not apparent to me what this block of code is doing but it appears it's happening here.

toggleEdit(fieldId, animate = true) {
    ......
    this.updatePreview($(field))
    if (field.classList.contains('editing')) {
      this.formBuilder.currentEditPanel = $editPanel[0]
      config.opts.onOpenFieldEdit($editPanel[0])
      document.dispatchEvent(events.fieldEditOpened)
    } else {
      config.opts.onCloseFieldEdit($editPanel[0])
      document.dispatchEvent(events.fieldEditClosed)
    }
}

@EizEddin
Copy link

@riverofjanuary is there a reason you cant use the textarea type?

@kevinchappell, I have the same enquiry as @riverofjanuary. We want to add a custom attribute to an element, but we want that attribute to be a textarea where we can type multiple-line values. I cannot find a way to make that attribute field as a textarea. It either shows as a textfield, or a select field when it has options.

@Ciao121
Copy link

Ciao121 commented May 9, 2021

Looking at the code, it appears formbuilder on Field Edit Close click event does some attribute processing and then calls the onCloseFieldEdit function and then updates the editor. If that is true, the update overrides anything done in onCloseFieldEdit. This only occurs when a change has been made to any of the attributes.

Landed here 3 years and I'm having the same problem 😝

@lucasnetau
Copy link
Collaborator

lucasnetau commented Oct 26, 2023

I know this is an old ticket, however with recent updated to custom controls you can override this behaviour with a template

You could hook into the build stage and convert the fieldData.data* to a classname, alternatively you can also add in a onRender and make your changes there.

templates: {
            header: function(fieldData) {
                const { type, ...attrs } = fieldData
                
                return {
                    field: this.markup(fieldData.subtype, fieldData.label, attrs),
                    layout: 'noLabel',
                    onRender: function() {
                        console.log('header was rendered')
                    }
                }
            },
        },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants