Skip to content

Custom views

Record views

EspoCRM framework provides flexible abilities to define custom views for certain entity types. They must be defined in clientDefs category of metadata.

custom/Espo/Custom/Resources/metadata/clientDefs/YourEntityType.json

{
    "views": {
        "list": "custom:views/your-entity-type/list",
        "detail": "custom:views/your-entity-type/detail",
        "edit": "custom:views/your-entity-type/edit"
    },
    "recordViews": {
        "list": "custom:views/your-entity-type/record/list",
        "detail": "custom:views/your-entity-type/record/detail",
        "edit": "custom:views/your-entity-type/record/edit"
    }
}

Detail view

client/custom/src/views/your-entity-type/record/detail.js

The view 'views/record/detail' contains all panels with fields, relations and other data you can see on detail view. It doesn't contain header and buttons in the top-right corner.

define('custom:views/your-entity-type/record/detail', ['views/record/detail'], function (Dep) {

    return Dep.extend({

        // custom template, omit if you don't need it
        template: 'custom:your-entity-type/record/detail', 

        // custom central view, omit if you don't need it
        middleView: 'custom:views/your-entity-type/record/detail-middle', 

        // custom side column view, omit if you don't need it
        sideView: 'custom:views/your-entity-type/record/detail-side', 

        // custom bottom view, omit if you don't need it
        bottomView: 'custom:views/your-entity-type/record/detail-bottom', 

        setup: function() {
            Dep.prototype.setup.call(this);

            this.hideField('someField');
            this.showField('someField');

            // custom initialization logic, like binding listening to model changes
            this.listenTo(this.model, 'change:myField', () => {
                this.model.set('anotherField', this.model.get('myField') + ' Hello');

                this.hideField('someField');
                this.showField('someField');
                this.setFieldRequired('someField');
                this.setFieldNotRequired('someField');

                this.setFieldReadOnly('someField');
                this.setFieldNotReadOnly('someField');

                this.hidePanel('activities');
                this.showPanel('history');
            });
        },

        afterRender: function() {
            Dep.prototype.afterRender.call(this);

            // Custom code to be invoked right after rendering, when DOM is available.
            this.$el.find('label[data-name="myField"]').addClass('hidden');
        },
    });
});

You are able to create a custom template with the following path: client/custom/res/templates/your-entity-type/record/detail.tpl

client/custom/src/views/your-entity-type/detail.js

Detail view contains a record view and header view.

Edit view

client/custom/src/views/your-entity-type/edit.js client/custom/src/views/your-entity-type/record/edit.js

The same as detail but it is used when record is being created or edited not in inline-edit mode.

List view

client/custom/src/views/your-entity-type/list.js

List view contains Record/List view, Header and Search Form View.

client/custom/src/views/your-entity-type/record/list.js

The views 'views/list/record' contains rows of records.

Extending from specific view

It's worth to mention that you need to inherit your view class from specific class for your entity if one already exists.

define('custom:views/email/record/detail', ['views/email/record/detail'], function (Dep) {

});

Field views

Custom views for specific fields should be specified in entityDefs section of metadata.

Example for Address field of Account entity type.

custom/Espo/Custom/Resources/metadata/entityDefs/Account.json

{
    "fields": {
        "address": {
            "view": "custom:views/account/fields/address"
        }  
    }
}

client/custom/src/views/account/fields/address.js

define('custom:views/fields/address', ['views/fields/address'], function (Dep) {

   return Dep.extend({

        setup: function () {
            Dep.prototype.setup.call(this);
            // some initialization
        },

        afterRender: function () {
            Dep.prototype.afterRender.call(this);
            // your customizations executed after the field is rendered
        },
    });
});

See also