SOLVED

Callback for conditional field being added to form (placeholder converted into field)

Go to solution
cgrove
Level 2

Callback for conditional field being added to form (placeholder converted into field)

If there a function available to detect when say a new conditional select element or input has been added to a form? I am using the functions found here to strip all styles from the form but these dont apply to conditional elements added later. I also have some javascript on the form to add a class to the mktoFieldWrap of each element so i can target the labels by say label for checkbox vs label for input. These classes get added when form is ready, but not to the conditional conset checkboxes that appear after selecting values from select elements.

 

Another option would be to not use the <div class="mktoPlaceholder mktoPlaceholderconsenttoProcessing"></div> and instead just have the elements already inserted into the form, but I couldnt find any options for this?

 

Thank you in advance for any help!

 

 

            <form id="mktoForm_4312" class="dk-nobg-btm-2col center-form"></form>
            <script>
                MktoForms2.loadForm("//app-ab09.marketo.com", "291-IVM-952", 4312, function(form){

                    let formEl = form.getFormElem()[0];
                    let formElements = formEl.elements;

                    for (i=0; i<formElements.length; i++){
                        // Add the type of the input to the wrapper class
                        // so it can be targeted with css

                        let parentElem = getClosest(formElements[i], '.mktoFieldWrap');
                        if (parentElem != null) {
                            parentElem.classList.add("type-" + formElements[i].type);
                        }

                    }

                    let arrayFrom = Function.prototype.call.bind(Array.prototype.slice);

                    // remove element styles from <form> and children
                        var styledEls = arrayFrom(formEl.querySelectorAll("[style]")).concat(formEl);
                        styledEls.forEach(function (el) {
                            el.removeAttribute("style");
                        });

                        var styleSheets = arrayFrom(document.styleSheets);
                        styleSheets.forEach(function (ss) {
                            if ([mktoForms2BaseStyle, mktoForms2ThemeStyle].indexOf(ss.ownerNode) != -1 ||
                                formEl.contains(ss.ownerNode)
                            ) {
                                ss.disabled = true;
                            }
                        });

                        formEl.setAttribute("data-styles-ready", "true");
                });


                function getClosest(elem, selector) {

                    // Element.matches() polyfill
                    if (!Element.prototype.matches) {
                        Element.prototype.matches =
                            Element.prototype.matchesSelector ||
                            Element.prototype.mozMatchesSelector ||
                            Element.prototype.msMatchesSelector ||
                            Element.prototype.oMatchesSelector ||
                            Element.prototype.webkitMatchesSelector ||
                            function(s) {
                                var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                                    i = matches.length;
                                while (--i >= 0 && matches.item(i) !== this) {}
                                return i > -1;
                            };
                    }

                    // Get the closest matching element
                    for ( ; elem && elem !== document; elem = elem.parentNode ) {
                        if ( elem.matches( selector ) ) return elem;
                    }
                    return null;

                }

            </script>

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
SanfordWhiteman
Level 10 - Community Moderator

Re: Callback for conditional field being added to form (placeholder converted into field)

FormsPlus :: Tag takes care of this for you.

 

Just include the script after the form embed (pls download to your own server, though):

<script id="teknklFormsPlus-Tag-0.2.3" src="https://assets.codepen.io/250687/teknkl-formsplus-tag-0.2.3.js"></script>

 

View solution in original post

12 REPLIES 12
SanfordWhiteman
Level 10 - Community Moderator

Re: Callback for conditional field being added to form (placeholder converted into field)

FormsPlus :: Tag takes care of this for you.

 

Just include the script after the form embed (pls download to your own server, though):

<script id="teknklFormsPlus-Tag-0.2.3" src="https://assets.codepen.io/250687/teknkl-formsplus-tag-0.2.3.js"></script>

 

cgrove
Level 2

Re: Callback for conditional field being added to form (placeholder converted into field)

Hi! Thank you very much for the help, that is a nice little script to have, will be using that across my whole webiste!

Would you mind pointing out to me how it targets the new conditional elements once they appear? Ive tried to use it to remove inline styles of newly added fields after conditional logic is met, but it is not working. Is whenRendered supposed to fire when a new element appears in the dom as well? (such as the state select upon selection of United States in the country select - in my case!)

 

marketo-example.PNG

SanfordWhiteman
Level 10 - Community Moderator

Re: Callback for conditional field being added to form (placeholder converted into field)

whenRendered indeed should be fired when a new element is in the DOM, that's its main function. What's your URL?

cgrove
Level 2

Re: Callback for conditional field being added to form (placeholder converted into field)

it sure does and it works! Thank you!

Dave_Roberts
Level 10

Re: Callback for conditional field being added to form (placeholder converted into field)

...looks like you've got this moving in the right direction already, but here's an alternate approach to this issue that's worked for me, for anyone else who's running into a similar situation in the future...

 

While you can add layers of scripting to update classes, etc on the form elements, you should be able to achieve similar results with just plain ol' CSS that'd work for both cases here (for stuff shown at first, and stuff added later on). 

 

In the case of being able to target a checkbox label vs an input, it might look something like this:

form.mktoForm input[type=email], form.mktoForm input[type=text] ... {
 /* input styles here */
}

form.mktoForm label {
 /* target ALL labels on your form - use this to style the "Display Text" (aka label to the right of the checkboxes input) for your checkboxes field type specifically then override this basecoat with a more specific selector below */
}

form.mktoForm label.mktoLabel {
 /* target field labels that are NOT inside a checkboxes (or radio) field type - this will override the basecoat above an apply instead to ONLY the labels that appear above or to the left of your inputs */
}

 

If you look at the elements on a form, you'll notice that the labels for the checkbox and radio field types are a bit different than the rest of the labels which usually appear above or to the left of the input (based on the setting in the form editor). The difference is that the "Display Text" (what shows up to the right of the input) is a <label> but it lacks the class ".mktoLabel". By isolating this difference you can independently target the labels differently to do something like hide the "actual" labels but still show the Display text for checkbox and radio field types. 
Alternatively, you can accomplish something similar (create a difference between ANY two fields) by placing one of them into a fieldset and writing the CSS selectors to something like "label.mktoLabel" and "fieldset label.mktoLabel" -- this would create a set of styles for ALL labels and a set for labels INSIDE a  fieldset.

 

Let me know if there's anything else you're having trouble targeting, as far as Im aware there is a way to specifically target any input type or label on a Marketo Form without needing to maintain an add'l layer of scripting to modify the form elements (although it does make writing the CSS easier if you're more comfortable with scripting than styling). If not, I'd love to see what I'm missing to see if there is a way to figure it out. Overall, the page's performance might be slightly better in terms of consistency and speed using CSS compared to firing another script once the form loads, renders, submits, etc.

 

 

 

 

cgrove
Level 2

Re: Callback for conditional field being added to form (placeholder converted into field)

Hi Dave - good catch there about the label class, I definitely did not catch that distinction on the radio/checkbox vs everything else! For organization it would be nice if the element wrappers came with the type in a class. I did actually want to do different label styling for labels of select elements vs input elements as well and I didn't see a way to target that do you?

Dave_Roberts
Level 10

Re: Callback for conditional field being added to form (placeholder converted into field)

This is a case where you'd probably want to create a division between ALL field labels and then field labels inside a fieldset. For example, if you had 1 select and 10 text inputs, you could put the one with fewer (select) into a fieldset and then write the CSS to style all labels and then override that with a more specific selector (fieldset > label.mktoLabel) to target the labels inside a fieldset. This does require that you setup the form structure differently, but that's all available to the Marketer to configure which lowers the overall bar to entry to put something like this into play or maintain the solution as new forms and conditions are created down the road.

 

Using this type of approach, you could even have some select fields inside a fieldset and others outside a fieldset and the same field type would have 2 "sets" of styles depending upon the context in which it appeared rather than just 1 set of styles for both (eg not using a fieldset as a selector).

 

Alternately, you can add HTML into the label for the select fields on your form and then tap into a new class to style your labels as many different ways as you'd like.

Dave_Roberts_0-1600112035666.png

For example, you could add the highlighted HTML into the select field "Label" input and then write some CSS against that class on the form's Custom CSS or a global stylesheet or something like that.

 

Both of these solutions do require a bit more setup on the form itself (using native features), for some folks that's a better solution b/c it's easier to manage in house and for others it's a pain b/c there's alot to do and it'd be easier to have a script(s) to handle this kinda stuff. 

 

Generally when Im troubleshooting someone else's code I find that it's much more confusing for classes to be appended/removed from the form elements b/c what you see and setup in Marketo isn't necessarily what you get on the other end which means looking for a script that's doing "something" in the middle. Another reason I prefer a CSS approach (especially if your form styles are contained on a global stylesheet) is that the styles are available before the form renders so you don't get any kind of "blink" on a slower connection between when the form loads on the page and the script runs to strip/change the classes where you can observe the difference between the old and new css based on the selectors changing in the background once the form is rendered on the page.

 

If you're comfortable using the script Sanford put together (and it looks like that did the trick) that's probably the most straight-forward solution here to be sure.

 

SanfordWhiteman
Level 10 - Community Moderator

Re: Callback for conditional field being added to form (placeholder converted into field)


Let me know if there's anything else you're having trouble targeting, as far as Im aware there is a way to specifically target any input type or label on a Marketo Form without needing to maintain an add'l layer of scripting to modify the form elements


Not the rows, columns, and/or fieldset that wrap a given field. That's the critical gap... yes, you can target an individual input by name or (if you deliberately restructure the form) by its sibling elements. But CSS doesn't support parent/reverse selectors.

 


Overall, the page's performance might be slightly better in terms of consistency and speed using CSS compared to firing another script .

We're talking microseconds here to add attributes. Performance isn't a real-world concern.

Dave_Roberts
Level 10

Re: Callback for conditional field being added to form (placeholder converted into field)

I definitely agree that it's easier to style a label inside a row or column or fieldset where you can append a selector to the parent element. In the case of having different label styles for different field types, you shouldn't need to target rows, columns or fieldset specifically, albeit easier to do something like that if you can. 

 

In terms of performance, speed may not be the only factor worth considering - I'd agree they're pretty close in terms of that. If you looked at something like what happens where there's an error (ie "future proofing") I think there are some significant trade offs with a script which modifies the form and a set of styles in terms of what could go wrong to "break" the functionality of the form submission process compared to the aesthetic. Sure, you could screw up the CSS pretty bad and break the UI but it'd be harder to actually "break" it with CSS. FWIW, issues with future proofing probably aren't something you've got to consider very often b/c your stuff is legendary but I see quite a few things come across in the support space that aren't so carefully considered.