The CreatorCon Call for Content is officially open! Get started here.

Changing widget-form template to be tabbed

davilu
Mega Sage

I have cloned the ootb widget-form and am attempting to make edits to the template in order to make the widget-form tabular.  I am running into an issue where form sections and any splits within a section are considered the same thing.  For example, in the system view, I have a form section that looks like this:

find_real_file.png

Notice that in my form section called "Name" I have two fields in 1 column format, then I split, and have 6 remaining fields in a two column format.  When I pull up the formModel for the widget-form, I see this:

   "_sections":[  
      {  
         "_bootstrap_cells":12,
         "_count":1,
         "visible":true,
         "columns":[  
            {  
               "fields":[  
                  {  
                     "name":"name",
                     "type":"field"
                  },
                  {  
                     "name":"favorite_fruit",
                     "type":"field"
                  },
                  {  
                     "name":"birth_date",
                     "type":"field"
                  }
               ]
            }
         ],
         "caption":"Name",
         "id":"136ae5c5db030300b11c771c8c9619a0",
         "scope_name":"x_82643_my_custom"
      },
      {  
         "_bootstrap_cells":6,
         "_count":2,
         "visible":true,
         "columns":[  
            {  
               "fields":[  
                  {  
                     "name":"name.phone",
                     "type":"field"
                  },
                  {  
                     "name":"name.city",
                     "type":"field"
                  },
                  {  
                     "name":"name.country",
                     "type":"field"
                  }
               ]
            },
            {  
               "fields":[  
                  {  
                     "name":"name.email",
                     "type":"field"
                  },
                  {  
                     "name":"name.employee_number",
                     "type":"field"
                  },
                  {  
                     "name":"name.gender",
                     "type":"field"
                  }
               ]
            }
         ],
         "caption":"",
         "id":"",
         "scope_name":"x_82643_my_custom"
      }
   ]

Even though they appear on the same form section, the formModel recognizes both as individual sections.  This matters because when I change the template to be tabular, I'm creating the tabs via ng-repeat on containers:

<uib-tabset active="active" justified="true">
  <uib-tab index="$index+1" ng-init="$last ? execItemScripts() : null" ng-show="isContainerVisible(container)" ng-repeat="container in containers" heading="{{$index+1}}. {{container.captionDisplay || container.caption}}">

When this runs, the widget-form creates two tabs: 1 with a tab name of "Name" and a subsequent one is just blank:

find_real_file.png

  I want all that information to be in one tab, like it appears in the system view.  

I've found the code in the spModel directive where I think this problem stems from, but am unsure how to alter it so that all the fields appear under one section:

function getNestedFields(fields, containers) {
				if (!containers)
					return;
				for (var _container in containers) {
					var container = containers[_container];
					if (container.columns) {
						for (var _col in container.columns) {
							var col = container.columns[_col];
							for (var _field in col.fields) {
								var field = col.fields[_field];
								if (field.type == "container")
									getNestedFields(fields, [field]);
								else if (field.type == "checkbox_container")
									getNestedFields(fields, field.containers);
								else if (field.type == "field")
									fields.push(formModel._fields[field.name]);
							}
						}
					}
				}
			}

Any suggestions on how to change this code so that _sections without a "caption" or "id" gets appended to the previous _section?

Thanks.

1 ACCEPTED SOLUTION

jamesmcwhinney
Giga Guru

Ok ive got it.

Here is the template XML:

<div>
  <uib-tabset active="active" justified="true">
	<uib-tab index="$index+1" ng-repeat="titleContainer in containers | titledFormSectionFilter" heading="{{titleContainer.captionDisplay}}">
		<fieldset ng-repeat="container in containers | currentFormSectionFilter : titleContainer.captionDisplay" ng-show="isContainerVisible(container)" ng-init="$last ? execItemScripts() : null">
			<legend class="h4" ng-if="(container.caption || container.captionDisplay)">{{container.captionDisplay || container.caption}}</legend>
			<div class="row">
				<div ng-repeat="column in container.columns" class="col-md-{{12 / container.columns.length }}">
					<div ng-switch="f.type" ng-repeat="f in column.fields" id="{{getVarID(f)}}" ng-class="{'form-inline': isInlineForm === true }">
						<div ng-switch-when="label" ng-if="formModel._fields[f.name]" ng-show="formModel._fields[f.name].visible">
							<label ng-bind-html="::f.label"></label>
							<span ng-if="::formModel._fields[f.name].instructions" ng-bind-html="::formModel._fields[f.name].instructions"></span>
							<p ng-if="::formModel._fields[f.name].help_text" title="{{::formModel._fields[f.name].help_tag}}" class="help-block" ng-bind-html="::formModel._fields[f.name].help_text"></p>
							<hr class="sp_label_hr"></hr>
						</div>
						<sp-form-field ng-switch-when="field" ng-if="formModel._fields[f.name]" form-model="formModel" field="formModel._fields[f.name]" glide-form="getGlideForm()" ng-show="formModel._fields[f.name].visible"></sp-form-field>
						<sp-variable-layout ng-switch-when="container" ng-init="containers=[f]"></sp-variable-layout>
						<sp-variable-layout ng-switch-when="checkbox_container" ng-init="containers=f.containers"></sp-variable-layout>
						<sp-widget ng-switch-when="formatter" ng-if="formModel._formatters[f.id].widgetInstance" widget="formModel._formatters[f.id].widgetInstance" page="{g_form: getGlideForm()}"></sp-widget>
						<hr ng-switch-when="break"></hr>
					</div>
				</div>
			</div>
		</fieldset>
	</uib-tab>
  </uib-tabset>
</div>


	


and here is the UI script for the custom AngularJS formatters (there are two):

(function() {
	angular.module('myTabbedFormFilters', []).filter('titledFormSectionFilter', function() {
		return function(input) {
			var output = [];
			console.log('JMM: input.length: '+ input.length);
			for (var i = 0; i < input.length; i++) {
				if (input[i].captionDisplay.length > 0) {
					console.log('JMM: captionDisplay:' + input[i].captionDisplay);
					output.push(input[i]);
				}	

			}
			return output;
		};
	}).filter('currentFormSectionFilter', function() {
		return function(input, startingCaptionDisplay) {
			var output = [];
			var include = false;
			for (var i = 0; i < input.length; i++) {
				if (input[i].captionDisplay == startingCaptionDisplay) {
					include = true;
					output.push(input[i]);
				} else if((include)&&(input[i].captionDisplay == '')){
					output.push(input[i]);
				} else {
					include = false;
				}
			}
			return output;
		};
	});
	
})();

 

And here is the result:

find_real_file.png

 

find_real_file.png

 

 

 

 

View solution in original post

27 REPLIES 27

robhaas
Tera Contributor

@davilu @jamesmcwhinney

 

So I am trying to fully understand what was done here as I am trying to accomplish the same thing. Can you all guide me in the right direction?

 

So far I have:

1. Cloned the widget 'widget-form'

2. Cloned the page 'Form' and add my cloned widget to the page (Assuming this is the correct step)

3. Updated my custom 'widget-form' to refer to a custom template :

 

So the template XML above would need to go into 

I am then lost on where the UI script code goes... is it just a new UI Script and does it need a specific name?

Last but not least, where does the below code go? I'm guessing in the widget html?

 

<!-- form -->
      <div>
        <sp-model form_model="data.f" mandatory="mandatory" template-url="smse-tabbed-sp-model-xml"></sp-model>
      </div>

Or maybe if someone could put this into an update set, that would be amazing. Thanks in advance!

hey robhaas, it's a pretty complicated process.  once you've cloned the widget-form,scroll down to the bottom of the page where other menus are located and create a new Angular Provider with the following code:

Create Directive, give it a name using camel case (ex. spModalTabbed)

function (spModelDirective){
	return angular.extend({}, spModelDirective[0], {
		templateUrl:'tabbed_custom_template.xml'
	});
}

Then create a new ng-Template, give it a name and paste in the following code (btw, this code is available if you open your console > Element > sp_model.xml and sp_variable_layout.xml.  there's obviously modifications made in order to make it tabbed):

<div>
  <div ng-if="::formModel._sections == null || formModel._sections.length == 0" ng-init="execItemScripts()"></div>


  <scrollable-tabset auto-recalculate='true'>
    <uib-tabset active="active" justified="true">
      <uib-tab index="$index+1" ng-repeat="titleContainer in containers | titledFormSectionFilter" heading="{{$index+1}}. {{titleContainer.captionDisplay}}">
        <!--<fieldset style="margin-top: 20px;"> -->
        <fieldset style="margin-top: 20px;" ng-repeat="container in containers | currentFormSectionFilter : titleContainer.captionDisplay" ng-show="paintForm(container)" ng-init="$last ? execItemScripts() : null">
          <div ng-repeat="column in container.columns" class="col-md-{{::12 / container.columns.length }}">
            <div ng-switch="::f.type" ng-repeat="f in ::column.fields" id="{{::getVarID(f)}}" ng-class="::{'form-inline': isInlineForm === true }">
              <div ng-switch-when="label" ng-if="formModel._fields[f.name]" ng-show="formModel._fields[f.name].isVisible()">
                <label ng-bind-html="f.label"></label>
                <span ng-if="formModel._fields[f.name].instructions" ng-bind-html="formModel._fields[f.name].instructions"></span>
                <p ng-if="formModel._fields[f.name].help_text" title="{{formModel._fields[f.name].help_tag}}"
                   class="help-block" ng-bind-html="formModel._fields[f.name].help_text"></p>
                <hr class="sp_label_hr"/>
              </div>
              <sp-form-field ng-switch-when="field" ng-if="formModel._fields[f.name]" form-model="formModel" field="formModel._fields[f.name]" glide-form="getGlideForm()" ng-show="formModel._fields[f.name].isVisible()"></sp-form-field>
              <sp-variable-layout ng-switch-when="container" ng-init="containers=[f]"></sp-variable-layout>
              <sp-variable-layout ng-switch-when="checkbox_container" ng-init="containers=f.containers" class="checkbox-container"></sp-variable-layout>
              <sp-widget ng-switch-when="formatter" ng-if="formModel._formatters[f.id].widgetInstance" widget="formModel._formatters[f.id].widgetInstance" page="{g_form: getGlideForm()}"></sp-widget>
              <hr ng-switch-when="break"/>
            </div>
          </div>
        </fieldset>
      </uib-tab>
    </uib-tabset>
  </scrollable-tabset>
</div>

Once that's done, you have to tie it all together by pasting this on top of your HTML, where the id is the name you provided in your templateURL in your angular provider and the ng-include name is the name you gave your ng-template:

<script type="text/ng-template" id="tabbed_custom_template.xml">
	<div ng-include="'custom-template-tabbed-form-scoped.xml'"></div>
</script>

Last step is to change your directive name in the HTML from sp-model to whatever you named your directive using camel case.  Do a ctrl-F for <!-- form --> and make sure the directive name matches what you named your new directive.  

As for the tabbed UI Script graciously provided by @jamesmcwhinney, you need to add that as a Dependency for that widget.  

robhaas
Tera Contributor

davilu,

Thanks for the help thus far! I'm good until the last portion. I'm sure it is just oversight here... Here is what I have in a test instance:

cloned the widget-form and the form page.

create a new Angular Provider with the code above, named 'spModalTabbed'

create a new ng-Template with the provided code above named 'smse-tabbed-sp-model-xml'

 

At this point I just need additional clarification:

Once that's done, you have to tie it all together by pasting this on top of your HTML, where the id is the name you provided in your templateURL in your angular provider and the ng-include name is the name you gave your ng-template:This would go in my widget-form html correct? If not, where?

<script>
	<div ng-include="'smse-tabbed-sp-model-xml'"></div>
</script>

 

Last step is to change your directive name in the HTML from sp-model to whatever you named your directive using camel case.  Do a ctrl-F for <!-- form --> and make sure the directive name matches what you named your new directive.  I'm not sure where this is.

Thanks again for your help!

yes your cloned widget-form html:

<script type="text/ng-template" id="tabbed_custom_template.xml">
	<div ng-include="'custom-template-tabbed-form-scoped.xml'"></div>
</script>

your id for the script should match your templateURL in your angular provider.  

do a ctrl-f for "<!-- form -->" and you'll see <sp-model form_model="data.f" mandatory="mandatory"></sp-model>.  You need to replace sp-model with whatever you named your directive, in your case, it should be <sp-model-tabbed>

robhaas
Tera Contributor

Ok.. I overlooked the <!-- form --> section. I think I have it working now. WIll let you know if not. Greatly appreciate the help!