in Share

Form Control Dependency Custom object-finder.js Share

Introduction

We wrote on how to create custom object-finder that gives you ability to search through repository for your custom types or folders. This feature was reserved only for authorities but as we have shown it is possible for folders too. You can read more on this here.

Recently we wrote about form control dependency and ability to make two or more controls dependent and we created a nice tutorial on this topic here.

What when we have a type with two associations? Example would be to have invoice type with association buyer and assistant. Each assistant has his buyers that are assigned to him and should not be allowed to select anyone elses. So question is how to disallow user to select only his buyers from his buyer list…

Solution Explanation

In order for us to achieve this task we must send assistent nodeRef to the servers webscript when searching for buyers. And add relevant code that will filter through buyers in such environment.

First we must create custom ObjectFinder  this is explained in previous post on this subject here.

Then we must override two methods :

  • _inAuthorityMode
  • onAddButtonClick

_inAuthorityMode is method that decides if dialog will allow user to search through results.

OnAddButtonClick is method that is called when dialog is being opened, and this is the important moment when we scan for data that will be sent to the server. In this case selected assistant.

We did not cover how to create your own script that will use assistant nodeRef, if you have any trouble send a email.

Solution

Model is kept simple and it is listed below

 

<aspect name="ab:invoice">
 <title>Invoice</title>
 <properties>
  <property name="ab:invDate">
   <type>d:datetime</type>
  </property>
  <property name="ab:invNumber">
   <type>d:int</type>
  </property>
  <property name="ab:value">
   <type>d:double</type>
  </property>
 </properties>
 <associations>
  <association name="ab:buyerassoc">
   <title>Buyer Association</title>
   <source>
    <mandatory>false</mandatory>
    <many>true</many>
  </source>
  <target>
   <class>ab:buyer</class>
   <mandatory>false</mandatory>
   <many>true</many>
  </target>
 </association>
 
  <association name="ab:assistant">
   <title>Assistant Association</title>
   <source>
    <mandatory>false</mandatory>
    <many>true</many>
   </source>
   <target>
    <class>cm:person</class>
    <mandatory>false</mandatory>
    <many>true</many>
   </target>
  </association>
 </associations>
</aspect>

As we can see we have assistent assoc and buyer assoc defined among with other properties of this invoice aspect.

Lets jump on share form config

<config evaluator="aspect" condition="ab:invoice">
 <forms>
  <form>
   <field-visibility>
    <show id="ab:invDate" />
    <show id="ab:invNumber" />
 
    <show id="ab:value" />
    <show id="ab:assistant" />
    <show id="ab:buyerassoc" />
   </field-visibility>
   <appearance>
    <field id="ab:invDate" label-id="prop.ab_invDate" />
    <field id="ab:invNumber" label-id="prop.ab_invNumber" />
    <field id="ab:value" label-id="prop.ab_value" />
    <field id="ab:assistant" label-id="prop.ab_assistant"/>

   <field id="ab:buyerassoc">
     <control
      template="/org/alfrescoblog/components/form/controls/association.ftl">
      <control-param name="showTargetLink">true</control-param>
      <control-param name="rootNode">/app:company_home/cm:Buyers/.
      </control-param>
      <control-param name="itemType">ab:buyer</control-param>
      <control-param name="searchMode">true</control-param>
      <control-param name="itemFamily">node</control-param>
      <control-param name="allowNavigationToContentChildren">false</control-param>
      <control-param name="dependantOf">ab_assistant</control-param>
      <control-param name="dependantOfType">assoc</control-param>
    </control>
   </field>
 </appearance>
 </form>
 </forms>
 </config>


<!-- This is telling share to load this javascript file.-->
<config>
 <forms>
 <dependencies>
  <js
    src="/components/com/alfrescoblog/ab-object-finder/ab-object-finder.js" />
  </dependencies>
 </forms>
 </config>

If you do not understand any of the form setting read post about it here. There are few control-params that are not in the specification, so lets explain them

  • control-template specifies custom template for association that will be shown shortly
  • root-node, specifies what is the root path that will be listed and searched
  • searchMode, specifies if search mode should be enabled or not
  • dependentOf, is important part it shows which property value will be sent to the webscript
  • dependedOfType specifies the type of property, it can be assoc, input and date. This way we allow any type of property to work!

Custom association is really simple and is used to set object-finder options, important part of the code is listed below. Full custom association.ftl can be downloaded here

 searchMode:"${field.control.params.searchMode!"false"}",
 dependantOf:"${field.control.params.dependantOf!""}",
 dependantOfType:"${field.control.params.dependantOfType!"input"}",

Custom object finder 

(function () {

 /**
 * YUI Library aliases
 */
 var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event;

 Alfresco.ABObjectFinder = function Alfresco_ABObjectFinder(htmlId, currentValueHtmlId) {
  Alfresco.ABObjectFinder.superclass.constructor.call(this, htmlId, currentValueHtmlId);

  // Re-register with our own name
  this.name = "Alfresco.ABObjectFinder";
  Alfresco.util.ComponentManager.reregister(this);

  return this;
 };

 YAHOO.extend(Alfresco.ABObjectFinder, Alfresco.ObjectFinder, {
  _inAuthorityMode: function ABObjectSearcher__inAuthorityMode() {
   if (this.options.searchMode == "true") {
    return true;
   } else {
    return false;
   }
  },
 
onAddButtonClick: function test(e, p_obj) {
 Alfresco.ABObjectFinder.superclass.onAddButtonClick.call(this, e, p_obj);

 if (this.options.dependantOfType == 'input') {
   var otherInputs = YAHOO.util.Selector.query('input[id*=' + this.options.dependantOf);
   var val = otherInputs[0].value;
   if (val != '') {
    this.options["params"] = this.options.dependantOf + "=" + val;
   }
 } else if (this.options.dependantOfType == 'date') {
  var otherInputs = YAHOO.util.Selector.query('input[id*=' + this.options.dependantOf + '][typ    e=hidden]');
  var paramsTemp = "";
  for (var i = 0; i < otherInputs.length; i++) {
   var val = otherInputs[i].value;
   paramsTemp += this.options.dependantOf + "=" + val;
  }

  if (val != '') {
   this.options["params"] = paramsTemp;
  }

 } else if (this.options.dependantOfType == 'assoc') {
   var otherInputs = YAHOO.util.Selector.query('input[id*='
       + this.options.dependantOf + '][type=hidden]');

   for(var i=0;i<otherInputs.length;i++){
    var val = otherInputs[i].value;
    if(val!=null){
     break;
    }
   }
   if (val != '') {
    this.options["params"] = this.options.dependantOf + "=" + val;
   }
  }
 }});
})();

Custom picker.inc is needed to make this all work, this inc script creates instance of our object finder. Since object finder is called ABObjectFinder than this must be created like so. Here is the download link picker.inc.ftl.

 var ${picker} = new Alfresco.ABObjectFinder("${controlId}", "${fieldHtmlId}").setOptions(
...

Final result

As final result in HTTP request to the webscript will be like this

share/proxy/alfresco/api/forms/picker/node/children?selectableType=ab:buyer&searchTerm=Buyer1&size=1000&xpath=%2Fapp%3Acompany_home%2Fcm%3ABuyers%2F.&rootNode=%2Fapp%3Acompany_home%2Fcm%3ABuyers%2F.&ab_assistant=workspace://SpacesStore/8b910a7f-c7a3-458a-bae9-e934e502ea7f

More on how to override /form/picker webscript read here.

Summary

We have seen how to create custom object-finder component and allow searching. This was not enough and we wanted to make this searching depend of other properties in the form.

We hope that this was helpful to you.

 

Don't be shellfish...Tweet about this on TwitterShare on LinkedInShare on Google+Share on RedditShare on Facebook

Was this helpful ?