Service Portal Form Fields, Broken

“Well, if it can be thought, it can be done, a problem can be overcome.”
E.A. Bucchianeri

The snh-form-field tag has been around for a while in various incarnations, and has been used on quite a few projects for one thing or another, all with relative success. Several snh-form-fields make up the initial set-up screen for the Collaboration Store, which also worked out quite well for that particular effort. At least, it was working out quite well until I tried to set up a new instance that was running the new Tokyo release. Here is what the initial set-up screen is supposed to look like:

Collaboration Store initial set-up screen

Here is what it looks like on a Tokyo instance:

Collaboration Store initial set-up screen on Tokyo

As you can clearly see, a couple of very important input fields are not on the screen in the Tokyo version. This appears to be due to a flaw in the snh-form-field tag that did not reveal itself in the earlier versions of the Now Platform. At this point, I do not know the exact nature of the flaw, only that it appears that you can only have one snh-form-field tag in any given container. I would categorize this as a flaw in the tag rather than an issue with the new release of ServiceNow, mainly because of the first rule of programming. It may take me a while to figure out exactly what might be going on here, but in the interim, I was at least able to come up with a viable work around. If you are using the snh-form-field tag on a project running on a Tokyo instance and you run into this issue before the flaw in the tag has been corrected, you can simply surround each snh-form-field tag with a span. That places each snh-form-field tag in its own personal container, eliminating the issue.

Here is how I used this technique to work around the problem that I was having with the initial set-up screen for the Collaboration Store.

<div id="nav_message" class="outputmsg_nav" ng-hide="c.data.validScope">
  <img role="presentation" src="images/icon_nav_info.png">
  <span class="outputmsg_nav_inner">
    &nbsp;
    The <strong>Collaboration Store Set-up</strong> cannot be completed because <strong>Collaboration Store</strong> is not selected in your application picker.
    <a onclick="window.location.href='change_current_app.do?app_id=5b9c19242f6030104425fcecf699b6ec&referrer=%24sp.do%3Fid%3Dcollaboration_store_setup'">
      Switch to <strong>Collaboration Store</strong>
    </a>.
  </span>
</div>
<div class="row" ng-show="c.data.phase != 1 && c.data.phase != 2 && c.data.phase != 3">
  <div class="col-sm-12">
    <h4>
      <i class="fa fa-spinner fa-spin"></i>
      ${Wait for it ...}
    </h4>
  </div>
</div>
<div class="row" ng-show="c.data.phase == 1">
  <div style="text-align: center;">
    <h3>${Collaboration Store Set-up}</h3>
  </div>
  <div>
    <p>
      Welcome to the Collaboration Store set-up process.
      There are two ways that you can set up the Collaboration Store on your instance:
      1) you can be the Host Instance to which all other instances connect, or
      2) you can connect to an existing Collaboration Store with their permission.
      To become the Host Instance of your own Collaboration Store, select <em>This instance will be
      the Host of the store</em> from the Installation Type choices below.
      If you are not the Host Instance, then you will need to provide the Instance ID of the
      Collaboration Store to which you would like to connect and the Host instance will need to be
      available to complete the set-up process.
    </p>
  </div>
  <form id="form1" name="form1" novalidate>
    <div class="row">
      <div class="col-xs-12 col-sm-6">
        <span>
          <snh-form-field
            snh-model="c.data.instance_type"
            snh-name="instance_type"
            snh-label="${Installation Type}"
            snh-type="select"
            snh-required="true"
            snh-choices='[{"value":"host", "label":"This instance will be the Host of the store"},
                          {"value":"client", "label":"This instance will connect to an existing store"}]'/>
        </span>
        <span>
          <snh-form-field
            snh-model="c.data.host_instance_id"
            snh-name="host_instance_id"
            snh-label="${Host Instance ID}"
            snh-help="Enter the instance ID only, not the full URL of the instance (https://{instance_id}.servicenow.com))"
            snh-required="c.data.instance_type == 'client'"
            ng-show="c.data.instance_type == 'client'"/>
        </span>
        <span>
          <snh-form-field
            snh-model="c.data.store_name"
            snh-name="store_name"
            snh-label="${Store Name}"
            snh-required="c.data.instance_type == 'host'"
            ng-show="c.data.instance_type == 'host'"/>
        </span>
        <span>
          <snh-form-field
            snh-model="c.data.instance_name"
            snh-name="instance_name"
            snh-label="${Instance Label}"
            snh-required="true"/>
        </span>
      </div>
      <div class="col-xs-12 col-sm-6 text-center">
        <div class="row" style="padding: 15px;">
          <div class="avatar-extra-large avatar-container" style="cursor:default;">
            <div class="avatar soloAvatar bottom">
              <div class="sub-avatar mia" ng-style="instanceLogoImage"><i class="fa fa-image"></i></div>
            </div>
          </div>
        </div>
        <div class="row" style="padding: 15px;">
          <input ng-show="false" type="file" accept="image/jpeg,image/png,image/bmp,image/x-windows-bmp,image/gif,image/x-icon,image/svg+xml" ng-file-select="attachFiles({files: $files})" />
          <button ng-click="uploadInstanceLogoImage($event)"
                  ng-keypress="uploadInstanceLogoImage($event)" type="button"
                  class="btn btn-default send-message">${Upload Instance Logo Image}</button>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-sm-12">
        <span>
          <snh-form-field
            snh-model="c.data.email"
            snh-name="email"
            snh-label="${Email}"
            snh-help="A verification email will be sent to this address as part of the set-up process"
            snh-type="email"
            snh-required="true"/>
        </span>
        <span>
          <snh-form-field
            snh-model="c.data.description"
            snh-name="description"
            snh-label="${Instance Description}"
            snh-type="textarea"
            snh-required="true"/>
        </span>
      </div>
    </div>
  </form>
  <div class="row">
    <div class="col-sm-12" style="text-align: center;">
      <button class="btn btn-primary" ng-disabled="!(form1.$valid) || !c.data.validScope" ng-show="c.data.instance_type == 'host'" ng-click="save();">${Create New Collaboration Store}</button>
      <button class="btn btn-primary" ng-disabled="!(form1.$valid) || !c.data.validScope" ng-show="c.data.instance_type == 'client'" ng-click="save();">${Complete Set-up and Request Access}</button>
    </div>
  </div>
</div>
<div class="row" ng-show="c.data.phase == 2">
  <div style="text-align: center;">
    <h3>${Email Verification}</h3>
  </div>
  <div>
    <p>
      A verification email has been sent to {{c.data.email}} with a one-time security code.
      Please enter the code below to continue.
    </p>
    <p>
      Cancelling this process will terminate the set-up process.
    </p>
  </div>
  <form id="form2" name="form2" novalidate>
    <div class="row">
      <div class="col-sm-12">
        <span>
          <snh-form-field
            snh-model="c.data.security_code"
            snh-name="security_code"
            snh-label="Security Code"
            snh-required="true"
            placeholder="Enter the security code sent to you via email"/>
        </span>
      </div>
    </div>
  </form>
  <div class="row">
    <div class="col-sm-12" style="text-align: center;">
      <button class="btn btn-default" ng-disabled="!(form2.$valid)" ng-click="cancel();">${Cancel}</button>
      <button class="btn btn-primary" ng-disabled="!(form2.$valid)" ng-click="verify();">${Submit Verification Code}</button>
    </div>
  </div>
</div>
<div class="row" ng-show="c.data.phase == 3">
  <div style="text-align: center;">
    <h3>${Set Up Complete!}</h3>
  </div>
  <div>
    <p>${Congratulations!}</p>
    <p ng-if="c.data.instance_type == 'client'">
      The Collaboration Store set-up is now complete. Your instance has been successfully registered with the
      <b class="text-primary">{{c.data.registeredHostName}}</b> ({{c.data.registeredHost}})
      Host and is now ready to utilize the Collaboration Store features.
    </p>
    <p ng-if="c.data.instance_type == 'host'">
      The Collaboration Store set-up is now complete. Your instance has been successfully set up as a
      Host instance and is now ready to accept client registrations and utilize the Collaboration
      Store features.
    </p>
  </div>
</div>

It’s not the best, but it does work. If you are one of those kind souls helping out with the testing of the Collaboration Store, and you happen to be doing your testing on a Tokyo instance, you can just grab the code above and overlay the HTML for the set-up widget with this version. That should get you up and running again. This will definitely be included in the next early release for testing purposes, but if you don’t want to wait for that, just snag the code above.

The best solution, of course, is to continue digging until we find the source of the true problem here and release a new version of SNH Form Fields that does not contain this issue. Hopefully, it won’t be too long before we can make that happen.

3 thoughts on “Service Portal Form Fields, Broken”

      • When I did a view source on the Tokyo version, there was absolutely nothing there where the remaining fields in the DIV were supposed to be, yet in later DIVs the fields would show up again. The pattern appeared to be one successful tag per DIV, with all of the remaining ones failing to generate any code, so it seemed like it might be worthwhile to put each tag in its own container. I decided to use the SPAN instead of the DIV, because it is an inline element, but with the layout of that page, DIV probably would have worked as well. Anyway, it was the first thing that I tried, and it worked, so I did not try anything else. That still does not solve the problem with the tag, but it does provide a way to get around the issue until the actual problem is diagnosed and corrected.

Comments are closed.