Skip navigation
All Places > Alfresco Content Services (ECM) > Blog > Authors rfernandes

Alfresco Summit 2014 is next door! 



summit The first day of the conference (San Francisco September 23 and London October 7) is dedicated to new and updated Alfresco training courses.  I am excited to announce that I will be the trainer for Developing Alfresco Web Scripts Using Java, both in San Francisco and London. Definitely looking forward meeting you in the class. For the training and also the break out sessions on days after. The Summit is the best opportunity to meet at the same place and time, all the most active and knowledgeable experts in the Alfresco Community. You can’t miss it, really!



Web Scripts What?



Alfresco Web Scripts is the framework for building custom REST API in the Alfresco Platform. Knowledge about Alfresco Web Scripts is critical whenever you need to integrate your solution with the Alfresco ECM repository.



With Alfresco Web Scripts you can:



  • Build API to integrate Alfresco with other systems inside your company


  • Customize Alfresco Share UI


  • Or even build your own application UI on top of Alfresco.


webscripts



We Scripts framework is lightweight and allows for fast development based on server side JavaScript.



For an introduction to the framework and fast developer enablement to build Alfresco custom REST APIs, as per best practices, the Developing Alfresco Web Scripts Using JavaScript course (offered in San Francisco  and London) is the best option. It updates and summarizes the regular content of the official 2 days training course into a single day course, including Maven Alfresco SDK 2.0 that allows for hot reloading and really fast development iteration cycles of your Web Scripts.



The course I am most excited about is the one I will be teaching. the Developing Alfresco Web Scripts Using Java (London link here).



Developing with Java in Alfresco Web Scripts is necessary:



  • Whenever what you want to do is not available on the out of the box JavaScript API


  • Also for performance optimization reasons


  • Or if you just feel more confortable building your custom REST API in Alfresco using the core Alfresco Foundation Java API in place of the higher level server side JavaScript.


This course also summarizes and updates the content of the corresponding official 2 day training course into a concentrated single day that includes the brand new Maven Alfresco SDK 2.0 (at this very moment still only available as a snapshot version) allowing for hot reloading of your Java classes and the same fast development iteration cycle (no repository restarts!).

Beyond Web Scripts



The knowledge you gain by learning Alfresco Web Scripts goes beyond just the framework and building custom REST APIs. For example the same Alfresco JavaScript API you use when developing Alfresco Web Scripts using JavaScript is leveraged throughout the platform:



  • Share UI


  • Workflows


  • Automation Rules


  • Actions, etc.


At the same time the Alfresco Java Foundation API you leverage when developing Alfresco Web Scripts using Java is also used on all other different customisations you may need to implement in the repository:



  • Workflows and Actions again


  • Automated Behaviours


  • Scheduled Processes


  • Transformations, and much more


In summary, learning Alfresco Web Scripts with JavaScript and Java ends up being important for any Alfresco developer when facing an Alfresco implementation project.

Let’s Meet



Come to Alfresco Summit and let’s connect, share best practices and learn together! You will find me at both events in San Francisco and London and I would love to hear about your challenges, and help you figure out the best way to solve them with Alfresco and introduce you to the awesome content offered in our Alfresco University Learning Pathways to set you on the path to success.



See you in San Francisco or London!
Sometimes you may need to have considerably large and complex forms that may not show best using the Alfresco out of the box form templates. In this post I present a generic solution template and the instructions on how to use it.



The code for the tabbed form template can be found at:



http://code.google.com/p/tabbed-form/



 



It’s composed of:



  • src/main/resources/alfresco/web-extension/site-webscripts/org/alfresco/components/form/tabbed.ftl The freemarker form template itself. This file contains all the logic for the structure of the form discussed in this document.


  • src/main/resources/META-INF/css/tabbed.css The CSS stylesheet for the elements used by the form template.


  • src/main/resources/META-INF/js/tabbed.js The client side javascript with the functions used by the form template mostly for the tabbed structuring of fields.


 



How to install it



For installing it (after extracting it locally as per http://code.google.com/p/tabbed-form/source/checkout) just execute:



 

mvn clean install


 



This will generate a jar file in the target folder: tabbed-alfresco-form-1.0.0.jar



Copy it to the shared/lib folder of your tomcat install or inside the WEB-INF/lib folder of your share webapp (you can also make the jar part of your own extension amp). In the first case make sure your tomcat installation has been configured properly for loading shared libraries. In conf/catalina.properties you should have set for that:



 

shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar


 



Restart your server and you should be able to use the new form template.



 



How to use it



The form template can be used for any form. Depending on where you want to use it and what you exactly need some tweaking on original code might be required. Here we will present the example of using the form template for editing the properties of a content type but the instructions will be still valid for whatever other case of Share form you may use it.



On shared/classes/alfresco/web-extension/share-config-custom.xml add it to the custom configuration (don’t worry into understanding it exactly for now) the same sample configuration as contained in the second config tag of https://code.google.com/p/tabbed-form/source/browse/sample/share-config-custom.xml



After any editing of the shared/classes/alfresco/web-extension/share-config-custom.xml  you don't need to restart the server just go to http://localhost:8080/share/page/index and refresh the web scripts, the share application configuration should be refreshed.



Now just make sure to add for a certain document in any site the aspects:



  • Emailed


  • Effecitivity


  • Dublin Core


 



If you edit now the properties of the document you should see something like this:



 



Tabbed_Complex_Form_Template



 



If you click on Extra tab above:



Tabbed_Complex_Form_Template2



 



Now let’s discuss how our configuration of the form template before led us to get this.



About the field-visibility tag on the configuration there’s nothing much to say except to specify all fields you want to see on the form.



Then on edit-form tag we specify our template:



 

<edit-form template='tabbed.ftl' />


 



On the appearance tag is where all the logic of the form templates comes in action.



 



The tabs



First we specify our tabs we want our form to be structured. In our case we just have two:



 

               <set id='Zgeneric' label='Generic' />



               <set id='Zextra' label='Extra' />


 



Note that we use the id for both cases starting with a Z. This is important. And after on the label the name we want to show for each tab.



Tabbed_Complex_Form_Template3



 



The tab major layout



Afterwards we specify the major layout columns for each tab.



 

             <set id='generic1' parent='Zgeneric' label='' />



               <set id='extra1' parent='Zextra' label='' />



               <set id='extra2' parent='Zextra' label='' />


 



So we are specifying 1 single major layout column for the generic tab (look at the parent attribute for each set) and 2 major layout columns for the extra tab.



Tabbed_Complex_Form_Template4



 



Here the exact id given to each set is not important. It’s assumed that any primary child set of a a tab set (Zgeneric and Zextra) are always specifying the number of columns of the tab layout.



 



The Group Sets



After we specify the groups in which we want to gather the fields (they are surrounded with a blue line and the corresponding label group). This allows for more structuring on our forms.



 

               <!-- generic group -->



               <set id='Ggeneric' parent='generic1' label='Generic'/>



               <!-- dates group -->



               <set id='Gdates' parent='generic1' label='Control'/>



          <!-- dublin group -->



               <set id='Gdublin' parent='extra1' label='Dublin'/>



                <!-- emailed group -->



               <set id='Gemailed' parent='extra2' label='Emailed'/>



                <!-- effectivity group -->



               <set id='Geffectivity' parent='extra2' label='Effectivity'/>


 



So we can see that for the single column of the first Generic tab we have two group sets: Generic and Control. The id here is important and it should start by a G. The labels are also going to be used on the representation of the form. Note that the parent is always the column tab layout they belong to.



Tabbed_Complex_Form_Template5



 



For the 2 columns of the Extra tab layout we have 3 groups: Dublin, Emailed and Effectivity (corresponding to the aspects we have added to the document). The Dublin one we represent on the first column of the tab, while the other two in the second.



Tabbed_Complex_Form_Template6



 



The table like structure of group fields



For each group before we can specify a fairly complex table like structure for the distribution of the fields in order to get the best look and feel we want. In our example we just use this capability in full for the groups Generic and Control of the first Generic tab. But it should be enough for understanding the template logics for others usages.



So lets look first to the generic subgroup in the first tab:



Tabbed_Complex_Form_Template7



 

              <!-- name -->



               <set id='110Ggeneric-0-0' parent='Ggeneric'/>



               <!-- mimetype -->



               <set id='110Ggeneric-0-1' parent='Ggeneric'/>



                <!-- description -->



               <set id='121Ggeneric-0-2' parent='Ggeneric'/>



               <!-- title -->



               <set id='211Ggeneric-1-0' parent='Ggeneric'/>


 



Each one of these set tags is specifying the cell distribution (row and column span and break of lines) for the subgroup Ggeneric. This is done through the id first 3 numbers. The rest of the id just has to guarantee that the id is overall unique and we use a convention based on the subgroup name and the row and column within the row, but it is not interpreted by the form template.



  • The first number specifies the column span of the cell


  • The second number the row span of the cell


  • And the third number specifies if the row ends (1) or continues to the next cell/set (0).


 



So for 110Ggeneric-0-0 we are specifying the name cell has a row and column span 1 (so no span) and the line continues.



For the 110Ggeneric-0-1 of the mime type the same.



For 121Ggeneric-0-2 of the description we are specifying there’s no column span but there’s row span, so the cell spans to the row after. As you can check looking the form screenshot.



Finally for the title 211Ggeneric-1-0 we do the opposite, spanning the columns but not the row. As again is visible on the screen shot.



If we look into the next subgroup Control:



Tabbed_Complex_Form_Template8



 



The structure is much more simple and now we probably don’t need to explain the configuration:



 

               <!-- creator -->



               <set id='110Gdates-0-0' parent='Gdates'/>



                <!-- modifier -->



               <set id='111Gdates-0-1' parent='Gdates'/>



               <!-- created -->



               <set id='110Gdates-1-0' parent='Gdates'/>



               <!-- modified -->



               <set id='111Gdates-1-1' parent='Gdates'/>


 



For the Extra tab the table structure for each subgroup is the simplest possible with no row or column span and each cell occupying a full row. So all ids start by 111.



So far we just described the set tags that define the layout but haven't discussed the field tags yet. The fields tags are needed and through the set attribute it’s how we map each field with the set/cell it belongs to:



 

               <field id='cm:name' set='110Ggeneric-0-0'>



                   <control>



                       <control-param name='style'>width: 150px;</control-param>



                   </control>



               </field>



               <field id='mimetype'  set='110Ggeneric-0-1'>



                  <control template='/org/alfresco/components/form/controls/mimetype.ftl'>



                       <control-param name='style'>width: 200px;</control-param>



                  </control>



               </field>


 



But aside that there’s nothing particular about the field tag settings when using the tabbed.ftl form template.



HIH
This post won’t tell you much new if you are already experienced in Alfresco but even then you might found something curious somewhere. So be warned that the audience for this post is mostly the Alfresco newbie that just started playing with this great Open Source ECM platform.



I am often asked about things that are related in a way or another with the parent-child relationship between nodes in Alfresco (folders or documents). Not surprising this is a core concept in Alfresco. So I thought it deserved a dedicated post going through some of the nuances.



 



Javascript API Root Variables 



One of the most common places where a conversation about a node’s parents and children in Alfresco will start is the Alfresco’s server side Javascript API. If we look into it [1]:



 





































Root ObjectType in Script RuntimeDescription
documentorg.alfresco.repo.jscript.ScriptNodeThe current document ScriptNode (if any)
spaceorg.alfresco.repo.jscript.ScriptNodeThe current space ScriptNode (if any). For a script executing from a rule, the space object is the space in which the rule resides. If the rule is inherited, this may not be the expected space.


 



The newbye will naturally assume document always refers to a (content) document and space to a folder. But that’s very far from the truth (although the original root variables names themselves bear a big amount of fault for this). It is in fact better to map it conceptually as following:



 































Root ObjectDescription
documentThe current node ScriptNode.
spaceThe parent node ScriptNode of the current node.


 



If you want to see this in action just create a simple Javascript script as the following:



 

function main() {



     return 'Node: ' + document.name +'\tParent: '+space.name+ '\tDate: ' + new Date().toUTCString();



}



main();


 



Call it as myscript.js (by the way this would be a terrible name for a real production script...) and store it in the Company Home/Data Dictionary/Scripts folder in Alfresco.



This server-side script basically returns a line with the details about the node name and its parent name, besides the date of execution.



So now, if we use the Script Command Processor of Alfresco we can call the script for any node on our repository. We just need to call from our browser an URL like this [2]:



 



http://localhost:8080/alfresco/command/script/execute/workspace/SpacesStore/b9f89106-acb3-458c-9151-0318b1c613dc/workspace/SpacesStore/98ef0384-d882-4839-89d2-40026edd89f9



 



The first uuid belongs to the script’s node reference and the second to the node we want to execute the script against (so you should replace according to your installation and setup). You should get a response similar to this:



Node: test Parent: documentLibrary Date: Wed, 25 Sep 2013 10:10:05 GMT



 



document can be a Space



Just execute the script for a folder in Alfresco and you will see that document will reference the folder’s ScriptNode and less strangely space to its parent folder. This is in fact a very common case with server-side scripting in Alfresco.



 



space can be a Document



This will be most probably more unexpected to some. But if you call the script for an inner child of a document, the space variable will refer to the document and document to the inner child node. And yes, documents can have children in Alfresco and in fact they are very common.



For example when you upload a document in Alfresco Share Document Library you can see with the Node Browser [3] that these documents have children for things like thumbnail, preview and rating. You can use a node reference for one of these child nodes to run the script against and see how your document will be referenced by the space root variable in the Javascript.







The fact that these document children (doclib, webpreview, etc) are not available during normal navigation, be it through Share or file protocols like CIFS, is just because those interfaces were specifically designed (or by their own nature as in case of CIFS wouldn’t adapt to it very easily...) to ignore those objects and corresponding particular kinds of parent-child association used. They just know about the standard parent child association that associates a folder to other children folders or documents.



 



What about rules? (an experiment)



Why rules can’t be defined for documents just like they are for spaces? In fact you can, just configure Share to show the Manage Rules action in a document. If you want to try (you definitely don’t want to do that for real projects) just edit the share-documentlibrary-config.xml and add the corresponding action entry for the action group of document-details. Something like this:



 

<actionGroup id='document-details'>



<action index='100' id='document-download' />



<action index='105' id='folder-manage-rules' />



...


 



When you restart Alfresco you should be able to see now the Manage Rules action on the document details pages. You can create the rule and execute for example a variation [4] (see bellow) of the previously used for any “incoming node inside” your document.



 

var logFile = companyhome.childByNamePath(document.id+'.txt');



if (logFile == null) {



      logFile = companyhome.createFile(document.id+'.txt');



}



if (logFile != null) {



      logFile.content += 'Node: ' + document.name +'\tParent: '+space.name+ '\tDate: ' + new Date().toUTCString() + '\r\n';



}






 



If you execute the rules explicitly from the Manage Rules interface for the document you should see that the script executes as before with the Script Command Processor for each of the document children (doclib, webpreview and rating if there’s one). Except for the rules child itself (created cause of the definition of the document rule), because Alfresco ignores the rules folders as expected (imagine if a rule in a folder was sensitive to the node where it’s defined, it wouldn’t make any sense and that would be definitely unexpected to the end user that don’t see it).



But although this might be fun as an experiment it is not really useful because any rules automation won’t be triggered for non standard folder-document parent child related nodes. So for documents rules will never be triggered for its children (only explicitly as in the experiment we just did). [5]



In any case a script that references a document as space and its inner children as document can still be useful in other contexts.



 



Multiple Parents



This fact is many times ignored by new comers to Alfresco platform, but Alfresco does not limit the number of parents a node may have. Although parents of a node are not completely equivalent between themselves. There’s always one considered to be the primary parent while the others if any are considered to be the secondary parents. The difference between a primary parent and the other secondary parents, is that if a primary parent is deleted the child node is deleted with it while for secondary parents this cascading deletion does not happen.



If you want to see multiple parents in action just save the following javascript as a new script (same as before but with a different name) [6]:



 

var childNodeRef = 'workspace://SpacesStore/08bba651-81d6-4f17-bf8b-06def398b7b8';  



var childNode = search.findNode(childNodeRef); 



document.addNode(childNode); 


 



Replace on the script before the value for node reference by one of a document in your repository.



This script adds your document as a child to any folder you run the script against it, so that the folder becomes a secondary parent of your document.



Execute the script against a folder that is not the actual parent of the document from which you copied the node reference inside the script. You should then see that the same document (it could also be a folder) shows up besides in its original location also as a child of the new folder. This is not a copy but exactly the same document as you can confirm by editing it (and seeing same changes on metadata or content reflected on both places) or just by checking its node reference [7].



And from the node browser you can check that the document has in fact two parents now (one, the first one, which is the primary).







On the Alfresco Share UI you will notice on the head breadcrumb of the document’s page details that, doesn’t matter how you navigate till it (from the primary or secondary parent), the path shown is always the one from the primary parent (which not necessarily may always be ideal but it’s consistent with Share URL’s addressability).



 



An example: Link to Rule Set 



When in Share you Link to Rule Set [8] (in place of creating local rules) Alfresco is in fact leveraging multiple parents for making the ‘hidden’ rule folder of the first folder to gain a new secondary folder parent. You can confirm that again by navigating through the node browser.



 



Javascript Add Node Extension



By the way the javascript API out of the box is limited to what concerns creating parent child associations that not the standard one (as we did before in our script with the addNode method). To have that would be useful in the case we wanted to link a rule set by ourselves through some automated script for example. But Alfresco allows us to extend its Javascript server side API fairly easily with some coding. [9]



You can check this project for an example on how to extend the API for allowing that: https://code.google.com/p/rules-scriptnode-extension-demo/



This extension once applied to Alfresco allows you to use a new root variable called extScriptNode and its method linkRuleSet to do that, or if you wanted to add another specific custom parent child association of your own the method addNode of the new root variable could be leveraged. [10]



Another example: In Situ Records



With Alfresco Enterprise 4.2 and Alfresco Records Management 2.1 we offer the capability to declare in situ records. So that the records can be declared without leaving the original edition collaboration context. This is great of course and make records management so much more useful for the generic end business user. And by the way it’s in fact implemented leveraging multiple parents.



The collaboration document after declared as record gains a new parent (belonging to the RM site) which becomes in fact its primary parent, and the original parent collaboration folder his secondary parent. Also the new option available for hiding a record (available on the original collaboration context after the record declaration) what in fact does is to remove the secondary parent-child association of the record, so that the record can now only be discovered on the Records Manager site.



Back to Javascript API



Now back to our Javascript server side API of Alfresco we are in conditions to refine the initial conceptual description/mapping of those two root variables to:



 































Root ObjectDescription
documentThe current node ScriptNode.
spaceThe primary parent node ScriptNode of the current node.


 



I hope it was useful (or at least relatively fun) this ‘small’ walkthrough by some details around Alfresco’s parents and children nodes.

______________________________________

1. Source: http://docs.alfresco.com/4.1/index.jsp?topic=%2Fcom.alfresco.enterprise.doc%2Freferences%2FAPI-JS-rootscoped.html



2. In general for creating a custom REST HTTP API you should leverage the Alfresco Web Scripts framework



http://docs.alfresco.com/4.1/index.jsp?topic=%2Fcom.alfresco.enterprise.doc%2Fconcepts%2Fws-architecture.html



But for our purposes the Script Command Processor is very handy and does in fact what we want it to do: execute scripts against specific nodes.



3. http://docs.alfresco.com/4.1/index.jsp?topic=%2Fcom.alfresco.enterprise.doc%2Ftasks%2Fadminconsole-nodebrowser.html



4. The script now is writing the same line as before to a document in the repository (with name equal to id of the corresponding node). It it will create the document before writing or append it if already existing. This way we have a “registry” of the script execution.



5. For cases like this you might need to leverage the powerful policies capability of Alfresco:



http://wiki.alfresco.com/wiki/Policy_Component



6. By the way you can notice how in this sample script the variable document is actually referencing a folder.



7. A copy of a node generates another different node, that can be acted separately (for editing, deleting, etc), even if the binary content path for the copied node points to the same location (till an update in one of the nodes happens, branching the content between the nodes).



8. http://docs.alfresco.com/4.1/index.jsp?topic=%2Fcom.alfresco.enterprise.doc%2Ftasks%2Flibrary-folder-rules-manage.html



9. Check http://wiki.alfresco.com/wiki/4.0_JavaScript_API#Adding_Custom_Script_APIs



10. Check the class code for details:



https://code.google.com/p/rules-scriptnode-extension-demo/source/browse/src/main/java/demo/rf/alfresco/script/node/extension/ExtScriptNode.java .
So you need to make the options available on your Alfresco Share select form html fields depending on each other? But unfortunately your content model in Alfresco does not allow you to group constraint value options and say 'show these values for this field if user selected the value X for that other field, and change it (without reload) when he selects the value Y”… There's no way right now of configuring that through out of the box Alfresco constraints.  This post shows a simple way of achieving this in a generic way with some customization (just a pair of form controls freemarker templates) allowing for any changes on the dependency configuration for your properties to be immediately recognized by Alfresco Share.



First of all you can check the source code at the Google Code Project (the code on head has been tested for Alfresco Enterprise 4.0.0): http://code.google.com/p/share-form-control-dependency/



This customization allows you to control that only some sets of values are used for a set of dependent properties at the UI (Share) level. This won't be constrained at the repository level even if the dependency control configuration is 'specified' at the content model level (it's really based on a convention that only our Share form controls know about).



In pictures, if you select value A for the main property the conditioned property One should automatically just present the corresponding allowed values. The same for any other conditioned property Two.







The basic idea is to have specific form controls for Alfresco Share aware of the convention used to configure in our content model those dependencies and also have those generic form controls empowered (through client javascript) to update the corresponding form controls according to the updates made by the user on the other associated properties.



So if we define our constraints like (check sample model on our google code project):

<constraints> 


<constraint name='sample:parentConstraint' type='LIST'> 


<parameter name='allowedValues'> 


<list> 


<value></value> <value>1 - VALUE A</value> 


<value>2 - VALUE B</value> 


<value>3 - VALUE C</value>


 </list> 


</parameter> 


</constraint> 


<constraint name='sample:constraintOne' type='LIST'> 


<parameter name='allowedValues'> 


<list> 


<value></value> 


<value>1 - SUBVALUE ONE AX</value> 


<value>1 - SUBVALUE ONE AY</value> 


<value>1 - SUBVALUE ONE AZ</value> 


<value>2 - SUBVALUE ONE BX</value> 


<value>2 - SUBVALUE ONE BY</value> 


<value>3 - SUBVALUE ONE CY</value> 


<value>3 - SUBVALUE ONE CZ</value> 


</list> 


</parameter> 


</constraint> 


<constraint name='sample:constraintTwo' type='LIST'> 


<parameter name='allowedValues'> 


<list> 


<value></value> 


<value>1.2.3 - SUBVALUE TWO ABCX</value> 


<value>2.3 - SUBVALUE TWO BCX</value> 


<value>2.3 - SUBVALUE TWO BCY</value> 


<value>2.3 - SUBVALUE TWO BCZ</value> 


<value>3 - SUBVALUE TWO CX</value> 


<value>3 - SUBVALUE TWO CY</value> 


<value>3 - SUBVALUE TWO CZ</value> 


</list> 


</parameter> 


</constraint> 


</constraints>


What we are trying to say (through convention: our repository really doesn't know about this...) is that some possible values for properties one and two (to which will apply the constraintOne and constraintTwo) just should show if the corresponding group value (the number which starts the value) was selected for the main property. If the value selected for the main property changes we will also want to change the shown values for the other properties one and two.



For cases  like 1.2.3 - SUBVALUE TWO ABCX in the constraintTwo, we will want the value to be available for property two for whatever value (1, 2 or 3) is selected  for the main property. We also don't want the values to be presented with the preceding main property association 1 -, 2 -, etc. And finally we want all updates to happen dynamically as user fulfills the form.



Well that's exactly what our custom form control components do. They are generic and can be used for any equivalent case. Just build the jar, incorporate in your project and finally configure your form for Alfresco Share:

<form> 


<field-visibility> 


<show id='sample:mainProperty' /> 


<show id='sample:propertyOne' /> 


<show id='sample:propertyTwo' /> 


<show id='sample:propertyThree' /> 


</field-visibility> 


<appearance> 


<set id='sample-2col' template='/org/alfresco/components/form/2-column-set.ftl'/> 


<field id='sample:mainProperty' set='sample-2col'> 


<control template='/org/alfresco/components/form/controls/parent-filter-selectone.ftl'> 


<control-param name='filteredProperty'>sample_propertyOne,sample_propertyTwo</control-param> 


</control> 


</field> 


<field id='sample:propertyOne' set='sample-2col'> 


<control template='/org/alfresco/components/form/controls/filtered-selectone.ftl'/> 


</field> 


<field id='sample:propertyTwo' set='sample-2col'> 


<control template='/org/alfresco/components/form/controls/filtered-selectone.ftl'/> 


</field> 


</appearance> 


</form>


As you see we are using the same custom form control filtered-selectone.ftl for both conditioned properties, and another parent-filter-selectone.ftl for the main one (if you import this into your project these two freemarker files are the only ones you should care about, everything else on the google project is for the sake of demonstration). This last one must also receive the list of conditioned properties (separated by comma) as a control-param. As the dependency is defined this way at the form control configuration level this allows for us to have many separated groups of associated properties in the same form.



And with that in place the magic will happen.







Pay attention as besides the dynamic filtering of values we also have the initial numbers who define our dependency convention ripped from the values shown in the form.



The good stuff is that this is fully generic and can be used for any form, type or aspect, including search forms, data-lists types, and so on.



Finally the last advantage is that it allows you to manage the associated dynamic behavior of your properties just by configuring your content model constraints, that can be located in a dynamic model for example and so allow for hot update without server restart.

Filter Blog

By date: By tag: