AEM 61 - Touch UI Default Image (Placeholder) in Granite File Upload Widget


Add default (placeholder) image capability to components with Granite File Upload widgets granite/ui/components/foundation/form/fileupload in cq:dialog. In the demo, a custom component /apps/touchui-fileupload-default-image/sample-image-component with two file upload widgets in cq:dialog are configured with placeholder attribute value /content/dam/Paintings/Placeholder.png. When a new component editable is created using drag/drop on page, the file upload widget fileReferenceParameter value is automatically filled with the placeholder file path. When a new component is added, user will always see placeholder image first, before any image can be dropped or uploaded in widget. The placeholder image may provide some instructions on what type of images can be used for the widget (eg. the placeholder may say upload PNGs only)

Demo | Package Install

Placeholder Image added on Component Drop

Placeholder configuration in cq:dialog

Placeholder path in CRX, added on Component Drop


1) Login to CRXDE Lite, create folder (nt:folder) /apps/touchui-fileupload-default-image

2) Create clientlib (type cq:ClientLibraryFolder/apps/touchui-fileupload-default-image/clientlib and set a property categories of String type to cq.authoring.dialogdependencies of type String[] with value underscore

3) Create file ( type nt:file ) /apps/touchui-fileupload-default-image/clientlib/js.txt, add the following


4) Create file ( type nt:file ) /apps/touchui-fileupload-default-image/clientlib/default-image.js, add the following code

(function ($document, gAuthor) {
    var COMPONENT = "touchui-fileupload-default-image/sample-image-component",
        FILE_UPLOAD_WIDGET = "granite/ui/components/foundation/form/fileupload",
        DROP_TARGET_ENABLED_CLASS = "js-cq-droptarget--enabled",
        FILE_REF_PARAM = "fileReferenceParameter",
        PLACEHOLDER_PARAM = "placeholder";

    $document.on('cq-inspectable-added', addPlaceholder);

    $document.on('mouseup', setNewDropFlag);

    var newComponentDrop = false;

    function setNewDropFlag(event){
        var LM = gAuthor.layerManager;

        if (LM.getCurrentLayer() != "Edit") {

        var DC = gAuthor.ui.dropController,
            generalIH = DC._interactionHandler.general;

        if (!generalIH._hasStarted || !$( {

        newComponentDrop = true;

    function addPlaceholder(event){
        var LM = gAuthor.layerManager;

        if ( (LM.getCurrentLayer() != "Edit") || !newComponentDrop) {

        newComponentDrop = false;

        var editable = event.inspectable;

        if(editable.type !== COMPONENT){

        $.ajax(editable.config.dialog + ".infinity.json").done(postPlaceholder);

        function postPlaceholder(data){
            var fileRefs = addFileRefs(data, {});


                type : 'POST',
                url : editable.path,
                data  : fileRefs

        function addFileRefs(data, fileRefs){
                return fileRefs;

            _.each(data, function(value, key){
                    addFileRefs(value, fileRefs);

                if( (key != "sling:resourceType") || (value != FILE_UPLOAD_WIDGET)){

                if(!data[FILE_REF_PARAM] || !data[PLACEHOLDER_PARAM]){

                fileRefs[data[FILE_REF_PARAM]] = data[PLACEHOLDER_PARAM];
            }, this);

            return fileRefs;

1 comment:

  1. Hello Sreekanth, This works perfectly. However, if the author clears image in the dialog and reloads it. We see a broken image. I had seen the same issue with Default Text&Image component. Wondering if you any other workaround for that.