cancel
Showing results for 
Search instead for 
Did you mean: 

Cannot add my custom Aikau widget in the Share search page

mlagneaux
Champ on-the-rise
Champ on-the-rise
Hi,

I want to add an "Export" button in the Share search form. I understand that I have to replace the "FCTSRCH_SEARCH_FORM" Aikau widget in the faceted-search.get.js by my custom widget (which we can name, for example "FCTSRCH_EXPORTABLE_SEARCH_FORM).

First question : how to replace an Aikau widget in a page ? I know how to add a new widget (push a new widget in the "widgets" object) but how to replace an existing one by my custom one ?

When I add my custom widget somewhere in the page, it doesn't show up :



var exportableSearchForm = {
   id: "FCTSRCH_EXPORTABLE_SEARCH_FORM",
   name: "js/dcnsgroup/ExportableSearchForm/ExportableSearchForm",
   config: {
      useHash: true,
      okButtonLabel: msg.get("faceted-search.search-form.ok-button-label"),
      okButtonPublishTopic : "ALF_SET_SEARCH_TERM",
      okButtonPublishGlobal: true,
      okButtonIconClass: "alf-white-search-icon",
      okButtonClass: "call-to-action",
      textFieldName: "searchTerm",
      textBoxIconClass: "alf-search-icon",
      textBoxCssClasses: "long hiddenlabel",
      textBoxLabel: msg.get("faceted-search.search-form.search-field-label"),
      queryAttribute: "term",
      optionsPublishTopic: "ALF_AUTO_SUGGEST_SEARCH",
      optionsPublishPayload: {
         resultsProperty: "response.suggestions"
      },
      /* new form features */
      exportButtonLabel: msg.get("export-button-label"),
      exportButtonPublishTopic : "ALF_SET_EXPORT_TERM",
      exportButtonPublishGlobal: true,
      exportButtonIconClass: "alf-white-search-icon",
      exportButtonClass: "call-to-action"
   }
};

var verticalLayout = widgetUtils.findObject(model.jsonModel, "id", "FCTSRCH_MAIN_VERTICAL_STACK");
verticalLayout.config.widgets.push(exportableSearchForm);



My Aikau widget JS file IS CORRECTLY LOADED in the browser :



define(
      [ "dojo/_base/declare", "alfresco/forms/SingleComboBoxForm",
            "dojo/text!./ExportableSearchForm.html", ],
      function(declare, SingleComboBoxForm, template) {
         return declare(
               [ SingleComboBoxForm, template],
               {
                  cssRequirements : [ {
                     cssFile : "./ExportableSearchForm.css",
                     mediaType : "screen"
                  } ],
                  i18nRequirements : [ {
                     i18nFile : "./ExportableSearchForm.properties"
                  } ],

                  /**
                   * The HTML template to use for the widget.
                   *
                   * @instance
                   * @type {String}
                   */
                  templateString : template,

                  /**
                   * Adds the export button to the form.
                   *
                   * @instance
                   */
                  createButtons : function alfresco_forms_ExportableSearchForm__createButtons() {
                     this.inherited(arguments);
                     if (this.showExportButton === true) {
                        var onButtonClass = this.exportButtonClass ? this.exportButtonClass
                              : "";
                        this.exportButton = new AlfButton(
                              {
                                 pubSubScope : this.pubSubScope,
                                 label : this
                                       .message(this.exportButtonLabel),
                                 additionalCssClasses : "confirmationButton "
                                       + onButtonClass,
                                 publishTopic : this.exportButtonPublishTopic,
                                 publishPayload : this.exportButtonPublishPayload,
                                 publishGlobal : this.exportButtonPublishGlobal,
                                 iconClass : this.exportButtonIconClass
                              }, this.exportButtonNode);
                     }
                  },
               });
      });


My custom widgets is not rendered but there is no error, neither in the browser logs or in alfresco.log or share.log !
The declare() function in my custom widget JS is called but my createButtons() function is not.

<b>Other question</b> : how Alfresco/Aikau does the mapping between the widget name defined in my faceted-search.get.js and the widget JS file to load ? At first I set the name "dcnsgroup/ExportableSearchForm/ExportableSearchForm" but with that name, the "/res/dcnsgroup/ExportableSearchForm/ExportableSearchForm.js" was loaded instead of the correct path "/res/<b>js</b>/dcnsgroup/ExportableSearchForm/ExportableSearchForm.js". So I added "/js" in the name to make it work.


Thanks you in advance for your answers,

Mickaël
12 REPLIES 12

stuartonmaui
Champ in-the-making
Champ in-the-making
I put my widget in a new project generated by the SDK, in the same folder as the furnished example with "TemplateWidget" and added it to the "simple-page." The widget uses the arguments

function(declare, _Widget, Core, _Templated, template)

Again, my widget does not show up while its companion in the same folder works as it should.
Something is wrong with the widget. I recoded it to separate it from the alfresco/html/Label that it contains.
<blockcode>
define(["dojo/_base/declare",
        "dijit/_WidgetBase",
        "alfresco/core/Core",
        "dijit/_TemplatedMixin",
        "alfresco/html/Label",
        "dojo/text!./templates/DateBarDate.html"
    ],
    function(declare, _Widget, Core, _Templated, template) {
               
   return declare([_Widget, Core, _Templated], {
             id: "MY_ELUSIVE_LABEL_WIDGET",
        templateString: template,
             cssRequirements: [{cssFile:"./css/DateBarDate.css",mediaType:"screen"}],
             config: {
                 widgets: [{
                     name: "alfresco/html/Label",
                     id: "MY_ELUSIVE_LABEL",
                     config: {
                         label: "the MISSING LABEL"
                     }
                  }]
              }
   })
});
</blockcode>
Which unfortunately still doesn't work.

stuartonmaui
Champ in-the-making
Champ in-the-making
I removed the widget and placed text directly in the .html file. The text appeared as it should. Something with the above use of alfresco/html/Label as a widget it wrong.

steven_okennedy
Star Contributor
Star Contributor
At least some of your problem here is related to the ordering of your parameters.  From the above you had:


define(["dojo/_base/declare",
        "dijit/_WidgetBase",
        "alfresco/core/Core",
        "dijit/_TemplatedMixin",
        "alfresco/html/Label",
        "dojo/text!./templates/DateBarDate.html"
    ],

    function(declare, _Widget, Core, _Templated, template){



The way that the AMD/dojo stuff works is that it resolves the strings you provide as arguments to define into the right objects/functions and passes them as parameters to the function you provide.  This allows you to reference these resolved ("loaded") objects using the names of your parameters.  It maps them in the order you provide.  So from the above:

"dojo/_base/declare" -> declare
"dijit/_WidgetBase" -> _widget
"alfresco/core/Core" -> Core
"dijit/_TemplatedMixin" -> _Templated
"alfresco/html/Label" -> <em>template</em>
"dojo/text!./templates/DateBarDate.html" -> <em>Nothing!</em>

So you are acutally mapping the Label widget to the parameter template and attempting to use that as the templateString.  You need to add another parameter, e.g. Label, in between _Templated and template in order for your parameters to be representing what you think they are.

The main issue however, is that you're not constructing your widget in a way that it is going to do anything.  Your widget is "extending" _Widget, Core and _Templated via the mixins you've specified, but there's nothing within those mixins that will process most of the properties you're specifying.  E.g. templateString: template will work because the _Templated mixin has logic that's being run to take the string from your template and turn it into the relevant Dom objects. Similarly, Core handles your cssRequirements and includes the right stylesheet.

However, there's nothing in _Widget, Core or _Templated that will do anything with your config element automatically.  What you'll need to do is put some logic in your widget to process any subwidgets it might contain.  There's an out of the box mixin called ProcessWidgets that you can use as the base parent for your widget (it already includes Core, _WidgetBase and _TemplatedMixin for you so it simplifies things a bit further


define(["dojo/_base/declare",
        "alfresco/core/ProcessWidgets",
        "alfresco/html/Label",
        "dojo/text!./templates/DateBarDate.html"
    ],

    function(declare, ProcessWidgets, Label, template) {

   return declare([ProcessWidgets],
        {
            id: "MY_ELUSIVE_LABEL_WIDGET",
       templateString: template,
            cssRequirements: [{cssFile:"./css/DateBarDate.css",mediaType:"screen"}],
            widgets:
            [
                {
                    name: "alfresco/html/Label",
                    id: "MY_ELUSIVE_LABEL",
                    config:
                    {
                        label: "the MISSING LABEL"
                    }
                }
            ]
   })
});


You can see I've fixed the parameters above and I've also removed the "config" element as a porperty - config gets mapped by default to the top level properties of the widget, so this.widgets is what's needed rather than this.config.widgets.  Using ProcessWidgets mixes in a function called postCreate which is part of the Dojo/Dijit widget lifecycle and will be called once the template processing and rendering has been completed.  For your info (the more you can see, the less magic things get), the function that's being inherited looks like this (you don't to put this code in yourself as its coming from ProcessWidgets:


   postCreate: function alfresco_core_ProcessWidgets__postCreate() {
      domClass.add(this.domNode, this.additionalCssClasses || "");
      if (this.widgets)
      {
         this.processWidgets(this.widgets, this.containerNode);
      }
   }


So you can see that it's going to take any widget object literals that exist in this.widgets and it's going to process them, creating widget objects from them out of widget definitions, and the best thing is, this mechanism will work if create your child widgets literally in the widget definition like we have above, or if you pass in the widgets you want when you call your custom widget in the json model from your webscript.  Have a look at how some of the out of the box widgets like HorizontalWidgets etc are put together if you want to see more.

Lastly, to make sure your widget knows where to put your child widgets, it's easiest to include some specific parameters in the html file:

<div class="d-bar-date" data-dojo-attach-point="containerNode">
</div>


This additional attach-point parameter gives your widget a property called this.containerNode to use as the place to add child nodes under - you can see it's used by ProcessWidgets in the postCreate function above.  This is a quick shrtcut to you have to go and do a Dom search to find the right parent to add the new children under.

On your frustrations, I fully understand, having picked up and dropped attempts at "doing" Aikau stuff a couple of times before.  However, its like pretty much any modern web framework these days you need to know a certain amount about the technologies backing it before it can be useful, e.g. in the same way you can't effectively do NodeJs without understanding npm, webpack etc etc. at least at a basic level, similarly you won't get far in creating custom Aikau widgets without understanding basic Dojo/Dijit widget lifecycle and Surf extensions.  Once you do though, you can do quite a lot quite quickly with a relatively small amount of code.  The documentation is growing and improving (as are the number of prebuilt widgets available) but it does require the time to go through the main tutorial from start to finish more or less before you'll get the hang of it

Regards

Steven