Drupal fails to render correctly a webform block which is included in the computed token field on the main form.

Here are the steps to reproduce the issue:

1. Install Drupal 8: drush qd --no-server --account-pass=admin
2. Enable modules: cd *drupal*/drupal && drush -y en webform block_token
3. Enable sub-modules: drush -y en webform_ui webform_examples
4. Apply patch for block_token by: cd quick-drupal-*/drupal/modules/block_token; patch -p1 < <(curl -s https://www.drupal.org/files/issues/0001-2899439-by-kenorb-Fixes-rendering-issue-for-blocks.patch)
5. Run PHP builtin server: drush rs
6. Open: http://127.0.0.1:8888/ and login as admin/admin.
7. Go to /admin/structure/block and in Content (or anywhere else) - Place block, choose Webform, then select Contact Webform, in Pages select 'Hide for the listed pages' with empty list (to hide it by default), and tick 'Create the token for this block', then Save.
8. Import the following webform, or create a new one with Computed token field with block token: [block_token:webform:webform]

computed_webform:
  '#type': computed_token
  '#title': 'Computed Webform'
  '#display_on': form
  '#value': '[block_token:webform:webform]'

9. Verify the webform at: /form/computed-form

After above steps, you should see the form which includes Contact form which is rendered incorrectly (input elements are missing). See the screenshot. I've also tested different webforms, the html elements are always filtered out, despite there isn't any filter setup.

Although the form is rendered correctly at some point in Renderer.php by adding the following code in doRender:

1. Edit: core/lib/Drupal/Core/Render/Renderer.php and go to renderRoot()
2. Before final return, add this code:

echo($output); exit;

Here is the backtrace for this tokenized block, at above point when it's rendered correctly:

renderRoot()(block_token.module:60); // WORKS HERE
block_token_block_render()(block_token.module:148);
block_token_tokens()(:);
call_user_func_array()(ModuleHandler.php:402);
invokeAll()(Token.php:304);
generate()(Token.php:196);
replace()(WebformTokenManager.php:67);
replace()(WebformComputedBase.php:77);
replaceTokens()(WebformElementBase.php:661); // WORKS HERE
prepare()(WebformComputedBase.php:61);
prepare()(WebformElementManager.php:149);
invokeMethod()(WebformSubmissionForm.php:1560);
prepareElements()(WebformSubmissionForm.php:382);
form()(EntityForm.php:115);
buildForm()(WebformSubmissionForm.php:294);
buildForm()(:);
call_user_func_array()(FormBuilder.php:514);
retrieveForm()(FormBuilder.php:271);
buildForm()(EntityFormBuilder.php:48);
getForm()(Webform.php:895);
getSubmissionForm()(WebformController.php:83);
addForm()(:);
call_user_func_array()(EarlyRenderingControllerWrapperSubscriber.php:123);  // WORKS HERE
Drupal\Core\EventSubscriber\{closure}()(Renderer.php:584);
executeInRenderContext()(EarlyRenderingControllerWrapperSubscriber.php:124);
wrapControllerExecutionInRenderContext()(EarlyRenderingControllerWrapperSubscriber.php:97);
Drupal\Core\EventSubscriber\{closure}()(:);
call_user_func_array()(HttpKernel.php:144);
handleRaw()(HttpKernel.php:64);
handle()(Session.php:57);
handle()(KernelPreHandle.php:47);
handle()(PageCache.php:99);
pass()(PageCache.php:78);
handle()(ReverseProxyMiddleware.php:47);
handle()(NegotiationMiddleware.php:50);
handle()(StackedHttpKernel.php:23);
handle()(DrupalKernel.php:656);
handle()(index.php:19);
include()(d8-rs-router.php:67);

However in the final output, the block is rendered incorrectly as follow:

Computed form

Here is the generated incorrect html code:

<div id="block-webform" class="block block-webform block-webform-block">
  
      <h2>Webform</h2>
    
      <div class="content">
      






  
  




<div class="js-form-item form-item js-form-type-textfield form-type-textfield js-form-item-name form-item-name">
      




Your Name



        










        </div>








<div class="js-form-item form-item js-form-type-email form-type-email js-form-item-email form-item-email">
      




Your Email



        










        </div>








<div class="js-form-item form-item js-form-type-textfield form-type-textfield js-form-item-subject form-item-subject">
      




Subject



        










        </div>








<div class="js-form-item form-item js-form-type-textarea form-type-textarea js-form-item-message form-item-message">
      




Message



        




<div class="form-textarea-wrapper">
  
</div>




        </div>








<div data-drupal-selector="edit-actions" class="form-actions webform-actions js-form-wrapper form-wrapper" id="edit-actions">


















</div>
























  





    </div>
  </div>

which has missing input elements and lots of new line characters.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kenorb created an issue. See original summary.

kenorb’s picture

Issue summary: View changes
kenorb’s picture

Issue summary: View changes
kenorb’s picture

Issue summary: View changes
kenorb’s picture

Issue summary: View changes
kenorb’s picture

Issue summary: View changes
kenorb’s picture

Title: Renderer fails to render form in block » Computed field fails to render a form in block
Project: Drupal core » Webform
Version: 8.3.6 » 8.x-5.x-dev
Component: render system » Code

Confirmed it's the issue with Webform, will provide patch shortly.

kenorb’s picture

Attaching patch which fixes the rendering issue. Basically when '#markup', Drupal strips all the html tags (Xss), so it's not possible to use full features of html in computed field values such as block tokens.

The solution is based on suggestion from this post from Pass raw html to #markup thread.

Webform before applying the patch:
webform-before-patch

Webform after applying the patch:
webform-after-patch

kenorb’s picture

Issue summary: View changes

I'm not sure if any of the states needs to be updated.

As I'm testing on one page, but I've got these errors:

drupal.js?v=8.3.6:59 Uncaught SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at Object.attach (states.js?v=8.3.6:41)
    at Object.Drupal.attachBehaviors (drupal.js?v=8.3.6:160)
    at drupal.init.js?v=8.3.6:17
    at HTMLDocument.t (ready.min.js?v=1.0.8:4)

with the configuration described in the main thread, but it may not be related to this patch.

kenorb’s picture

Despite #9, I've tested on clean installation of Drupal by following below steps and it works fine:

1. Install Drupal 8: drush qd --no-server --account-pass=admin
2. Enable modules: cd *drupal*/drupal && drush -y en webform block_token
3. Enable sub-modules: drush -y en webform_ui webform_examples
4. Run this to apply the patch: (cd modules/block_token && patch -p1 < <(curl -s https://www.drupal.org/files/issues/0001-2899439-by-kenorb-Fixes-rendering-issue-for-blocks.patch))
5. Run PHP builtin server: drush rs
6. Open: http://127.0.0.1:8888/ and login as admin/admin.
7. Go to /admin/structure/block and in Content (or anywhere else) - Place block, choose Webform, then select Contact Webform, in Pages select 'Hide for the listed pages' with empty list (to hide it by default), and tick 'Create the token for this block', then Save.
8. Now go to /admin/structure/webform/manage/example_element_states, 'Add element' under 'Checkbox example' group of 'Computed token' type field with any title and use [block_token:webform:webform] as a value. Then under 'Conditional logic' add 'Visible/All/Please check this box/Checked' condition, then Save.
9. Now go to the form at /form/example-element-states to confirm the Contact form will appear when clicking on 'Checkbox example'. If it's not, make sure you've applied correctly the patch from point 4th.

kenorb’s picture

The error at #9 was related to the patch, since my form which was the value of computed token was wrongly encoded.

So I had this incorrect HTML code (part of computed token):

<fieldset data-drupal-selector="edit-tell-us-the-details" data-drupal-states="{"visible":{":input[name=\u0022confirm_not_emergency\u0022]":{"checked":true}}}" id="edit-tell-us-the-details--2" class="js-form-item form-item js-form-wrapper form-wrapper">

which has wrongly encoded double-quotes causing the parsing problem on web browser like data-drupal-states="{". In order to fix it, the double quote (") should be encoded as a &quot.

After applying this new patch, the HTML code is correctly encoded:

<div data-drupal-states="{&quot;visible&quot;:{&quot;:input[name=\u0022repair_problem_with\u0022]&quot;:{&quot;value&quot;:&quot;113&quot;}}}" class="form-row-container js-form-item form-item js-form-type-item form-type-item js-form-item-central-heating-gas form-item-central-heating-gas form-no-label">

I also removing processValue() method which it seems it's not used anymore in this class.

Status: Needs review » Needs work
kenorb’s picture

Re-attaching patch in the corrected format.

Status: Needs review » Needs work

The last submitted patch, 13: 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

kenorb’s picture

Re-testing updated patch.

Status: Needs review » Needs work

The last submitted patch, 15: 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

kenorb’s picture

Testing another patch with slight change.

Status: Needs review » Needs work

The last submitted patch, 17: 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

kenorb’s picture

Status: Needs work » Needs review
FileSize
949 bytes

Simplifies patch.

jrockowitz’s picture

@kenorb A webform can't be nested inside webform. More accurately an HTML form can't be nested in an HTML form.

@see https://stackoverflow.com/questions/379610/can-you-nest-html-forms

I am not going to be able to commit this patch.

jrockowitz’s picture

Status: Needs review » Closed (won't fix)
kenorb’s picture

FileSize
485.38 KB

The patch works in my case. I'm not using it exactly as form within form, but the main form isn't used for submit, it's just used as a AJAX trigger (selector with conditional logic) to display another subform. The main won't be used at all, because the main submit button is hidden, so only displayed webform (within computed token) can be submitted.

Here is the demo:

/files/issues/2901761-webform-demo.gif

The patch is very simple and without it, my triggered webform isn't rendered correctly, so I'll have to keep my patch anyway.

My Webform configuration:

Only local images are allowed.
Only local images are allowed.