Question

I'm trying to get a custom extjs component to render either a green-check or red-x image, based on a true/false value being bound to it.

There's a couple of other controls that previous developers have written for rendering custom labels/custom buttons that I'm trying to base my control off but I'm not having much luck.

I'd like to be able to use it in a view as follows where "recordIsValid" is the name of the property in my model. (If I remove the xtype: it just renders as true/false)

{
    "xtype": "booldisplayfield",
    "name": "recordIsValid"
}

Here's what I have so far, but ExtJS is pretty foreign to me.

Ext.define('MyApp.view.ux.form.BoolDisplayField', {
    extend: 'Ext.Component',
    alias : 'widget.booldisplayfield',
    renderTpl : '<img src="{value}" />',
    autoEl: 'img',
    config: {
        value: ''
    },
    initComponent: function () {
        var me = this;
        me.callParent(arguments);

        this.renderData = {
            value: this.getValue()
        };
    },
    getValue: function () {
        return this.value;
    },
    setValue: function (v) {

        if(v){
            this.value = "/Images/booltrue.png";
        }else{
            this.value = "/Images/boolfalse.png";
        }
        return this;
    }
});

I'd taken most of the above from a previous custom linkbutton implementation. I was assuming that setValue would be called when the model-value for recordIsValid is bound to the control. Then based on whether that was true or false, it would override setting the value property of the control with the correct image.

And then in the initComponent, it would set the renderData value by calling getValue and that this would be injected into the renderTpl string.

Any help would be greatly appreciated.

Was it helpful?

Solution

You should use the tpl option instead of the renderTpl one. The later is intended for rendering the component structure, rather that its content. This way, you'll be able to use the update method to update the component.

You also need to call initConfig in your component's constructor for the initial state to be applied.

Finally, I advice to use applyValue instead of setValue for semantical reasons, and to keep the boolean value for getValue/setValue.

Ext.define('MyApp.view.ux.form.BoolDisplayField', {
    extend: 'Ext.Component',
    alias : 'widget.booldisplayfield',

    tpl: '<img src="{src}" />',

    config: {
        // I think you should keep the true value in there
        // (in order for setValue/getValue to yield the expected
        // result)
        value: false
    },

    constructor: function(config) {
        // will trigger applyValue
        this.initConfig(config);

        this.callParent(arguments);
    },

    // You can do this in setValue, but since you're using
    // a config option (for value), it is semantically more
    // appropriate to use applyValue. setValue & getValue
    // will be generated anyway.
    applyValue: function(v) {

        if (v) {
            this.update({
                src: "/Images/booltrue.png"
            });
        }else{
            this.update({
                src: "/Images/boolfalse.png"
            });
        }

        return v;
    }
});

With that, you can set your value either at creation time, or later, using setValue.

// Initial value
var c = Ext.create('MyApp.view.ux.form.BoolDisplayField', {
    renderTo: Ext.getBody()
    ,value: false
});

// ... that you can change later
c.setValue(true);

However, you won't be able to drop this component as it is in an Ext form and have it acting as a full fledged field. That is, its value won't be set, retrieved, etc. For that, you'll have to use the Ext.form.field.Field mixin. See this other question for an extended discussion on the subject.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top