Aikau Mini Examples – Wrapping a JQuery Widget

cancel
Showing results for 
Search instead for 
Did you mean: 

Aikau Mini Examples – Wrapping a JQuery Widget

ddraper
Intermediate II
0 16 10.1K

Introduction



This is one post in a series of short examples of things that can be done using the Aikau framework. The series is not intended to provide complete documentation but simply to show how to solve frequently encountered problems, implement repeating UI patterns, show case how to use existing widgets or how to create new ones.



PLEASE NOTE: This requires at least Alfresco 5.0.b Community (or Alfresco 5.0 Enterprise when it is released).

Real World Use Case



Aikau heavy use of Dojo for its AMD module loading and many of the Aikau widgets use the Dojo widget templating and utility functions. That doesn’t mean that you have to use Dojo for your own widgets if you’d prefer to use other JavaScript libraries.

Simple Example



In this example we’re going to define an extension module that includes some JQuery libraries and then create a new Aikau widget that wraps an existing JQuery widget.

Build an Extension



First we need to download the JQuery and JQueryUI resources we want to make use of. In this example I have downloaded JQuery 1.11.1 and JQuery UI 1.11.1 and will wrap the Accordion widget. We’re going to need to define 3 new AMD packages for:



  • JQuery


  • JQuery UI


  • Our blog widgets


The extension looks like this and is included in the downloadable example JAR:

<extension>

  <modules>

    <module>

      <id>Add JQuery</id>

      <auto-deploy>true</auto-deploy>

      <evaluator type='default.extensibility.evaluator'/>

      <configurations>

        <config evaluator='string-compare' condition='WebFramework' replace='false'>

          <web-framework>

            <dojo-pages>

              <packages>

                <package name='blog' location='js/lib/blog'/>

                <package name='jquery' location='js/lib/jquery-1.11.1' main='jquery-1.11.1.min'/>

                <package name='jqueryui' location='js/lib/jquery-ui-1.11.1' main='jquery-ui'/>

              </packages>

            </dojo-pages>

          </web-framework>

        </config>

      </configurations>

    </module>

  </modules>

</extension>


I won’t go into any depth on what this configuration does as it has been discussed in this previous blog post.

Create Our Custom Widget



The JQuery UI website provides excellent examples of how to use the Accordion widget, but to make this a more realistic example we want to be able to include other Aikau widgets in each Accordion section.



Our widget comprises a JavaScript file and an HTML template file (although we could also include CSS and i18n files as well - see this previous post for details). The HTML template is just about as simple as possible containing nothing more than a single DIV element with a class that we could anchor specific selectors to.



The JavaScript file first declares our dependencies:

define(['dojo/_base/declare',

        'dijit/_WidgetBase',

        'dijit/_TemplatedMixin',

        'dojo/text!./templates/JQueryAccordion.html',

        'alfresco/core/Core',

        'alfresco/core/CoreWidgetProcessing',

        'jquery',

        'jqueryui'],

       function(declare, _WidgetBase, _TemplatedMixin, template, AlfCore, CoreWidgetProcessing, $) {


We’re going to construct the widget using the base Dojo templating capabilities provided by “dijit/_WidgetBase” and “dijit/_TemplatedMixin” and will then mixin in the Aikau modules “alfresco/core/Core” (which provides i18n handling, pub/sub, logging and data binding capabilites) and “alfresco/core/CoreWidgetProcessing” which provides capabilities for processing child widgets. Lastly we declare our JQuery dependencies, mapping the return value of the jquery module to $.

Dojo Widget Lifecycle



We then need to override two Dojo widget lifecycle attributes/functions.

templateString: template,



postCreate: function blog_JQueryAccordion__postCreate() {

  this.processWidgets(this.widgets, this.domNode);

  $(this.domNode).accordion();

},


“templateString” is set to be the template mapped from our HTML file (see the Dojo documentation for more information on this, but its essentially boilerplate code).



“postCreate” is the main function we need to override to actually do some work. This function is called once the widget DOM is available. We first call the “processWidgets” function (inherited from “alfresco/core/CoreWidgetProcessing”) to process any child widgets in the JSON model and then we use JQuery to create the Accordion against the root widget DOM node.

Aikau Override



In between those two lines executing the “createWidgetDomNode” function from “alfresco/core/CoreWidgetProcessing” will be called for each widget being processed. All Aikau widget functions are designed to be overridden for simple customizations and in this case we need to change the DOM that is constructed for each child widget to match the expectations of the JQuery widget. This is achieved by overriding the inherited function:

createWidgetDomNode: function(widget, rootNode, rootClassName) {

  $(rootNode).append($('<h3>' + widget.title + '</h3>'));

  return $('<div>').appendTo($('<div>').appendTo(rootNode))[0];

}


The normal behaviour of the function would just be to create a single DIV element, but our overridden function creates an H3 and and a DIV within a DIV. This last DIV element is returned to the next stage of wiget processing and will be the element that the child widget is added to.

WebScript Time



Now we just need to define an Aikau page that includes our new widget:

model.jsonModel = {

  widgets: [

    {

      name: 'blog/JQueryAccordion',

      config: {

        widgets: [

          {

            name: 'alfresco/logo/Logo',

            title: 'Alfresco Logo',

            config: {

              logoClasses: 'alfresco-logo-large'

            }

          },

          {

            name: 'alfresco/logo/Logo',

            title: 'Surf Logo',

            config: {

              logoClasses: 'surf-logo-large'

            }

          }

        ]

      }

    }

  ]

};


In this page adding two “alfresco/logo/Logo” widgets as children of an instance of our new “blog/JQueryAccordion” widget.

Example In Action



This is defined in a JavaScript controller for a WebScript mapped to the /jqueryWidget URL. When deployed to a Share (or any Surf based Aikau application) this can be accessed by the URL: http://localhost:8081/share/page/dp/ws/jqueryWidget



Here is a screenshot of the resulting page:



AikauEx3_JQuery



Download the entire example here.



Download a PDF version of this blog here.
16 Comments
blog_commenter
Active Member
Hi,  I am trying to implement this tutorial, but it just loads a blank page and when I open javascript console I can see errors:

Failed to load resource: the server responded with a status of 404 (Not Found)



this happens for the following resources:

http://localhost:8080/share/res/js/alfresco/core/CoreWidgetProcessing.js

http://localhost:8080/share/res/js/lib/jquery-1.11.1/main.js

http://localhost:8080/share/res/js/lib/jquery-ui-1.11.2/main.js



I even tried to just copy your provided JAR file and putting it in my tomcat directory, same result.



Is there something I am missing?
ddraper
Intermediate II
@Massimo - what version of Alfresco are you using?
blog_commenter
Active Member
Thanks for the answer Dave.



I am using 4.2.3 Enterprise. For the record, I am putting the 'lib' folder in share/src/main/amp/web/js/.

I am saying this because it seems like the only possible flaw in my implementation, the most likely explanation for failure, as the rest seems pretty trivial.
ddraper
Intermediate II
@Massimo - you need to be on a 5.0.b Community or greater (or 5.0 Enterprise when it is released).



Apologies - I should have made this clear in the post - I'll update it.
blog_commenter
Active Member
Thank you! Looking forward to use it when 5.0 Enterprise then.



I'll try not to go off topic with this one, but I was trying to use JQuery as I am having a bit of a hard time understanding how to capture interaction on widgets.

I have read example with onClick on an AlfButton, and I kind of got the basics about Pubblish/Subscription for ...

ddraper
Intermediate II
@Massimo - The point about using the pub/sub approach is that it doesn't require one widget to explicitly listen on the DOM element of another to capture events which makes it possible to swap widgets in and out (or even remove them entirely or add additional widgets that subscribe or publish on the same topic).



The use case of the change in value of one select (in a  form control) setting the values in another is something we haven't implemented yet but is something we're likely to need in the future. There are workarounds currently (depending upon your data) such as only revealing one select menu (out of a collection) as the value of another select menu changes - but that isn't an ideal solution.



In your scenario I'd either expect the value of the select menu to contain the options for the select menu to update, or for it to trigger a refresh of values via XHR request where the selected value (in the first select menu) will alter the returned values (for the second select menu).
blog_commenter
Active Member
@Dave - Thank you very much again for your response. The final scenario you described is very much like what I am trying to implement.

I have a webscript that accepts a NodeRef as argument and returns a json with its children. The NodeRef is selected with the first DojoSelect and the result of the webscript will be processed and finally populate the second DojoSelect.

What I still miss is: how can I 'trigger a refresh of values via XHR request where the selected value (in the first select menu) will alter the returned values (for the second select menu)'? I mean, I haven't figured out how to 'listen for onChange' events on the DojoSelect widget.

I am sorry if this is a trivial question, but I tried going through your blog posts and didn't find an example of a similar case.

Thank you very much again
ddraper
Intermediate II
@Massimo - that's the point really...  we haven't implemented such a widget in Aikau yet. The closest we have is the 'alfresco/renderers/PublishingDropDownMenu', but that's not for use in forms. It's something we'll be looking at during development for the next release (after 5.0) .
blog_commenter
Active Member
@Dave - OK, since I am quite new to Alfresco and definitely not a master of JavaScript I was blaming the fact that I could not do it to myself.

From what I am reading in your blog and on ohej's GitHub tutorial, I am liking Aikau and I am very excited about it, so I wanted to implement something with it, instead of sticking with 'the old way'. I guess I just have to wait.

Thank you very much again for you blog posts and for the help!
blog_commenter
Active Member
Hi Dave, it's me again! Smiley Very Happy



I finally updated to Alfresco 5.0.0.3, and I came back to this to try and get it to work.



I was really disappointed at first, because it seemed like something was in the page, but it didn't look quite right. After messing with Chrome inspector and clicking here and there, I realized that I was able to collapse the Alfresco logo and show the Surf logo, so the accordion was there, it just looked so terribly plain I wasn't able to see it at first.



The issue was that in your jar package in js/lib/jquery-ui-1.11.1 there's a bunch of css files, that didn't get loaded in the page, that's why the widget was plain. I worked around it by moving them in a 'css' folder where the widget definition is and put this line in jQueryAccordion.js is:



cssRequirements: [ {cssFile:'./css/jquery-ui.css'}, {cssFile:'./css/jquery-ui.structure.css'}, {cssFile:'./css/jquery-ui.theme.css'} ],



This way, the widget finally looks like a widget, but images are still not loaded. So I'm asking: why is this happening? I am using your jquery-widget-extension.xml, which states:



is this the correct way to do it? Am I missing something?



Thank you again, hoping to finally make heavy usage of Aikau!



Massimo
blog_commenter
Active Member
the jquery-widget-extension.xml says this:



blog_commenter
Active Member
package name='jqueryui' location='js/lib/jquery-ui-1.11.1' main='jquery-ui'
ddraper
Intermediate II
@Massimo - it looks like I forgot to include the CSS import in the JQueryAccordion widget. It should have this line included:



cssRequirements: [{cssFile:'/js/lib/jquery-ui-1.11.1/jquery-ui.css'}],



Apologies for having missed that. Give that a try and let me know if it works.  I'd recommend as well that if you're able to upgrade t. 5.0.1 then you'll be able to start using the latest weekly releases of Aikau from the GitHub project.
blog_commenter
Active Member
Thanks a lot David for the quick reply, on a relatively old post!



I understand now the absolute path definition in the cssRequirements, and the way images are referenced in CSS style sheets.



Just to let you know, I am working on wrapping an Autocomplete widget, which now it seems a relatively straightforward task, thanks to you.



Me and the team will think about upgrading Alfresco soon, thanks for the heads-up on that.



Thank you again
blog_commenter
Active Member
I'm trying to build a custom widget that needs client side javascript. I tried adding a script tag to my template (e.g. your JQueryAccordion.html) but it doesn't render anything if my template file includes a script tag. What else can I do to inject client side javascript block or reference a js file? Thx!
ddraper
Intermediate II
@Erkan You almost certainly don't want to be adding script tags into the WebScript template... if you want to pull in additional JS dependencies then you can use the standard require/define approach in your widget source (or for non-AMD supported libraries you can use 'nonAmdDependencies' - look for examples in the Aikau source).



Also, it's worth noting that we now pull in JQuery and JQueryUI by default so there is no longer a need to add those as separate AMD packages into your config.



It would be helpful if there was some context to this question... what is it you're trying to do? Maybe sharing the code over pastebin or similar?