Question

I'm contemplating creating a color picker to be called from one of my widgets. A user would click a button to bring up the color picker and click a color, it would then be returned to the calling widget.

I am thinking I need to create a deferred object that would somehow wait until the deferred resolves. I could then set that color as a variable in the calling widget. Having trouble wrapping my mind around it though.

My calling widget has a method like this:

pickColor: function (e) {
    Event.stop(e);
    var colorPicker = new ColorWidget();
    colorPicker.getColor().then(function (value) {
        console.log(value);
    });
}

My ColorWidget would be the one creating the deferred object, correct?

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    "dijit/_TemplatedMixin",
    "dojo/text!./templates/ColorWidget.html",
    "dojo/Deferred",
    "dojo/_base/Color",
    "dojo/dom-construct",
    "dojo/domReady!"],

function (declare, _WidgetBase, _TemplatedMixin, template, Deferred, Color, domConstruct) {

    return declare("ColorWidget", [_WidgetBase, _TemplatedMixin], {
        templateString: template,
        deferred: {},
        color: {},

        constructor: function () {
            this.deferred = new Deferred();
        },
        postCreate: function () {
            domConstruct.place(this.domNode, "color-picker-holder", "last");
        },
        pick: function (evt) {
            this.color = new Color(evt.srcElement.id);
            domConstruct.destroy(this.domNode);
            this.deferred.resolve(this.color);
        },
        getColor: function () {
            return this.deferred;
        }
    });
});

This is just a thought spinning in my head, but is this how it's designed to work? I'd probably use this same idea for a login dialog that would stop initializing a page until successful authentication. Is this right?

Edit: I was actually on track. This works.

Was it helpful?

Solution

Although you say you have answered your own question, I will answer with a better solution as I think other users might also attempt to use a Deferred (which wouldbe totally wrong).

What you want to do is either...

1) Create your Color picker so that it is a form element. You would just need to extend a valid dojo form element. (I choose to extend ValidationTextBox for my color picker).

2) Create a custom widget that accepts a callback function. You could just override onChange or you could have a custom _callback method. Any time the value changes (you could use the observer methods .watch()) you would call the callback.

3) You just connect normally to an onChange event.


I created a custom Dojo widget.. that looks like this:

Color Picker

enter image description here

When you click either the color picker, or the textbox gets' focus, then the DropDown opens which contains the color picker. The color picker once changed, updates the parent widget (which is the text area).

You can see the associated classes below. It's split into a few files...

ColorTextBox.js (Extends ValidationTextBox)

_ColorPickerDropDown.js (Is just a simple widget that creates a color picker)

The Code

ColorTextBox.js

define([
    "dijit/form/ValidationTextBox",
    "dojo/_base/declare",
    "dojox/widget/ColorPicker",
    "dojo/text!./ColorTextBox.html",
    "dijit/_HasDropDown",
    "my/diskit/form/_ColorPickerDropDown",
    "dojo/_base/lang",
    "dojo/dom-style"

    ], function(ValidationTextBox, declare, ColorPicker, template,
        _HasDropDown, _ColorPickerDropDown, lang, domStyle ){
    return declare([ ValidationTextBox , _HasDropDown ], {
        templateString : template,
        regExp: "(?:[0-9a-fA-F]{3}){1,2}",

        baseClass: "diskitColorTextBox",
        postCreate : function(){

            this.connect(this.focusNode, "onclick", "openDropDown");
            this.watch( "value", lang.hitch( this, function(attr, oldVal, newVal){

                if(newVal === ""){
                    domStyle.set(this._buttonNode, "background", "transparent" );
                } else {
                    domStyle.set(this._buttonNode, "background", "#" + newVal );
                }
            }) );
            this.inherited( arguments );
        },
        openDropDown: function(/*Function*/ callback){

            if( this.dropDown ){
                this.dropDown.destroyRecursive();
            }
            var _changeMethod = function(){
                var hex = this.picker.get('value');
                if (hex.substring(0, 1) === '#') {
                    hex = hex.substring(1);
                    this.parent.set('value', hex);
                }
            };

            var lastHex = this.get('value');

            this.dropDown = new _ColorPickerDropDown({
                parent : this,
                value : "#" + lastHex,
                onCancel : lang.hitch( this.dropDown, function(){
                     this.parent.set('value', lastHex );
                }),
                onChange :lang.hitch( this.dropDown, _changeMethod ),
                onExecute : lang.hitch( this.dropDown, _changeMethod )
            });

            this.inherited(arguments);
        },
        closeDropDown: function() {
            this.inherited(arguments);
            if (this.dropDown) {
                this.dropDown.destroy();
                this.dropDown = null;
            }
        }



    });

});

Template String

<div class="itemCheckWrapper colorPicker">
    <fieldset>
        <div ><label>${label}</label></div>
        <div data-dojo-attach-point="_buttonNode" class="colorPreview"></div>
        <div class="dijitTextBox small dijit dijitReset dijitInline dijitLeft" id="widget_${id}" role="presentation">
            <div class="diskitInputPrefix" data-dojo-attach-point="verifiedNumberPrefixNode" >
                    #
            </div>
            <div class='dijitReset dijitValidationContainer'>
                <input class="dijitReset dijitInputField dijitValidationIcon dijitValidationInner" value="&#935; " type="text" tabIndex="-1" readonly="readonly" role="presentation"        />
            </div>
            <div class="dijitReset dijitInputField dijitInputContainer">
                <input maxlength="6" class="dijitReset dijitInputInner" data-dojo-attach-point='_aroundNode,textbox,focusNode' autocomplete="off" ${!nameAttrSetting} type='${type}'/>
            </div>
        </div>
    </fieldset>

</div>

And then this is the ColorPicker which just extends the dojox/widget/ColorPicker...

ColorPickerDropDown.js

define([
    "dojo/_base/declare",
    "dojox/widget/ColorPicker",
    "dojo/text!./_ColorPickerDropDown.html",
    "my/diskit/_base/_DiskitMixin",
    "dojo/_base/lang"
    ], function( declare, ColorPicker, template, _DiskitMixin, lang ){
    return declare([ _DiskitMixin ], {
        templateString : template,
        baseClass: "diskitColorPickerDropDown",
        postCreate : function(){


            this.picker = new ColorPicker({
                animatePoint:false,
                showHsv: false,
                showRgb: false,
                webSafe:false,
                onChange :  lang.hitch( this, this.onChange )
            }, this._colorPickerNode);
            if(this.value.length === 7){
                this.picker.setColor( this.value.trim() );
            }
            this.inherited( arguments );
        },
        onCancel : function(){

        },
        onExecute : function(){

        }
    });

});

Template String

<div >
<div data-dojo-attach-point="_colorPickerNode"></div>
<div class='toolbar'>
    <a data-dojo-attach-event="onclick:onCancel" class='pull-right'>Cancel</a>
    <a data-dojo-attach-event="onclick:onExecute" class='btn btn-sm btn-default pull-right'>Select</a>
</div>
</div>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top