Creating a new percentage Field?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Marcel
    Junior Member
    • Jul 2025
    • 13

    #1

    Creating a new percentage Field?

    Hi all,

    is there a way to create a new percentage Field based on the float field? Just want to see the value like 5,45 % instead of 5,45 in the layout.

    Thanks!
  • item
    Active Community Member
    • Mar 2017
    • 1539

    #2
    Hi,

    i am not specialist of front-end but you can begin with this working code (espoCrm v9.1.8)
    it's a little different because he color if value is < 0 or = 0 or > 0. but you have the direction of how to do.

    create a file : client/custom/src/views/fields/pourcent-float.js

    PHP Code:

    define
    (['views/fields/float'], (FloatFieldView) => {

       return class extends 
    FloatFieldView {

            
    setup () {
                
    super.setup();
            }

            
    afterRender () {
                
    super.afterRender();
                if (
    this.mode == 'search') return;
                
    let value parseFloat(this.model.get(this.name));

                if (
    this.mode =='list'){
                    
    this.$el.text('');
                    
    this.$el
                        
    .addClass(this.getListClass(value))
                        .
    append($('<span>').text(value.toFixed(2) + '%'));
                }else{
                    
    this.$el.text('');
                    
    this.$el.append(this.getSpanTag(value) );
                }

                
    this.$el.on('change', (e) => {
                    
    let value parseFloat(this.model.get(this.name));
                    if (
    this.mode =='list'){
                        
    this.$el.text('');
                        
    this.$el
                            
    .addClass(this.getListClass(value))
                            .
    append($('<span>').text(value.toFixed(2) + '%'));
                    }else{
                        
    this.$el.text('');
                        
    this.$el.append(this.getSpanTag(value) );
                    }
                });
            }

            
    getListClassvalue ){
                if ( 
    value 0) {
                    return 
    'text-primary';
                }

                if (
    value 0.001 && value > -0.001 ) {
                    return 
    'text-success';
                }

                if (
    value 0){
                    return 
    'text-danger'
                
    }

            }

            
    getSpanTag value ){
                if ( 
    value 0) {
                    return $(
    '<span>')
                                .
    addClass('label label-md label-primary')
                                .
    text(value.toFixed(2) + '%');
                }

                if (
    value 0.001 && value > -0.001 ) {
                    return $(
    '<span>')
                                .
    addClass('label label-md label-success')
                                .
    text(value.toFixed(2) + '%');
                }

                if (
    value 0){
                    return $(
    '<span>')
                                .
    addClass('label label-md label-danger')
                                .
    text(value.toFixed(2) + '%');
                }
            }
        }
    }); 
    And in your entityDefs (where the field must be append with %) here a sample field "balance" :

    path : custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json. // for sample in Contact.json

    PHP Code:

            
    "balance": {
                
    "notNull"false,
                
    "type""float",
                
    "default"0,
                
    "readOnly"true,
                
    "isCustom"true,
                
    "duplicateIgnore"true,
                
    "decimalPlaces"2,
                
    "view""custom:views/fields/pourcent-float",   // only add this line
                
    "audited"true
            
    }, 
    clearCache, rebuid... clear browser (maybe) .. and you will see result
    Last edited by item; 07-25-2025, 07:27 PM.
    If you could give the project a star on GitHub. EspoCrm believe our work truly deserves more recognition. Thanks.​

    Comment

    • Marcel
      Junior Member
      • Jul 2025
      • 13

      #3
      Originally posted by item
      Hi,

      i am not specialist of front-end but you can begin with this working code (espoCrm v9.1.8)
      it's a little different because he color if value is < 0 or = 0 or > 0. but you have the direction of how to do.

      create a file : client/custom/src/views/fields/pourcent-float.js

      PHP Code:

      define
      (['views/fields/float'], (FloatFieldView) => {

      return class extends 
      FloatFieldView {

      setup () {
      super.setup();
      }

      afterRender () {
      super.afterRender();
      if (
      this.mode == 'search') return;
      let value parseFloat(this.model.get(this.name));

      if (
      this.mode =='list'){
      this.$el.text('');
      this.$el
      .addClass(this.getListClass(value))
      .
      append($('').text(value.toFixed(2) + '%'));
      }else{
      this.$el.text('');
      this.$el.append(this.getSpanTag(value) );
      }

      this.$el.on('change', (e) => {
      let value parseFloat(this.model.get(this.name));
      if (
      this.mode =='list'){
      this.$el.text('');
      this.$el
      .addClass(this.getListClass(value))
      .
      append($('').text(value.toFixed(2) + '%'));
      }else{
      this.$el.text('');
      this.$el.append(this.getSpanTag(value) );
      }
      });
      }

      getListClassvalue ){
      if ( 
      value 0) {
      return 
      'text-primary';
      }

      if (
      value 0.001 && value > -0.001 ) {
      return 
      'text-success';
      }

      if (
      value 0){
      return 
      'text-danger'
      }

      }

      getSpanTag value ){
      if ( 
      value 0) {
      return $(
      '')
      .
      addClass('label label-md label-primary')
      .
      text(value.toFixed(2) + '%');
      }

      if (
      value 0.001 && value > -0.001 ) {
      return $(
      '')
      .
      addClass('label label-md label-success')
      .
      text(value.toFixed(2) + '%');
      }

      if (
      value 0){
      return $(
      '')
      .
      addClass('label label-md label-danger')
      .
      text(value.toFixed(2) + '%');
      }
      }
      }
      }); 
      And in your entityDefs (where the field must be append with %) here a sample field "balance" :

      path : custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json. // for sample in Contact.json

      PHP Code:

      "balance": {
      "notNull"false,
      "type""float",
      "default"0,
      "readOnly"true,
      "isCustom"true,
      "duplicateIgnore"true,
      "decimalPlaces"2,
      "view""custom:views/fields/pourcent-float"// only add this line
      "audited"true
      }, 
      clearCache, rebuid... clear browser (maybe) .. and you will see result
      Hi item

      Thanks a lot! That helped!

      I created this script out of it and I am currently trying to create that a bit more modular. I want to set parameters per field in the entityDefs file like

      PHP Code:

        
      "interestRate": {  "notNull"false,  "type""float",  "required"false,  "audited"true,  "max"100,  "decimalPlaces"2,  "isCustom"true,  "tooltip"true,  "view""custom:views/fields/percent-float",  "useColorLabel"true,  "useColorText"true,  "useRenderOn": ["list""detail"]  } 

      is that somehow possible?

      I tried a bit arround. See my comments in the Code

      PHP Code:

        
      /**   * Extend the default FloatFieldView to render percentage values with optional color styling  *   * Example "../metadata/entityDefs/[ENTITYNAME].json" field  * "interestRate": {  * "type": "float",  * "decimalPlaces": 2,  * "max": 100,  * "isCustom": true,  * "view": "custom:views/fields/percent-float", // This needs to be added  * "useColorLabel": true, // This can be added if you want to use label colors. If you don´t set it, it will be false  * "useColorText": true, // This can be added if you want to use text colors. If you don´t set it, it will be false  * "useRenderOn": ["list", "detail"] // This can be used to define where the formatted render should be used. If missing or empty, nothing will be rendered.  * }  */    define(['views/fields/float'], (FloatFieldView) => {  return class extends FloatFieldView {    setup () {  super.setup();  }    afterRender () {  super.afterRender();    // Safety check for unexpected call contexts  if (!this.model || !this.name || typeof this.model.get !== 'function') return;    const value = parseFloat(this.model.get(this.name));  if (isNaN(value)) return;    /**   * Read target render modes from metadata.  *   * Supported render modes in EspoCRM for field views:  *   * | Mode | Meaning / Usage Context |  * | ------------ | ----------------------------------------------------------- |  * | `list` | Entity list view (grid/table showing multiple records) |  * | `detail` | Detail view of a single record (read-only display) |  * | `edit` | Edit mode (form for editing a record) |  * | `search` | Search/filter form mode (filter fields in list search) |  * | `massUpdate` | Mass update mode (bulk editing dialog for multiple records) |  * | `kanban` | Kanban board view mode (card style layout for records) |  * | `preview` | Preview mode (e.g. quick view panels or preview popups) |  */    // Get field metadata from entityDefs via Metadata API  //const entityDefs = this.model.getMetadata().get('entityDefs')[this.model.name] || {};  //const fieldDefs = (entityDefs.fields && entityDefs.fields[this.name]) ? entityDefs.fields[this.name] : {};    // Try different places to get field definitions  //const fieldDefs = this.def || this.fieldDefs || {};    const renderModes = Array.isArray(this.params.useRenderOn) ? this.params.useRenderOn : ['list', 'detail'];  //const renderModes = Array.isArray(this.params.useRenderOn) ? this.params.useRenderOn : [];  //const renderModes = Array.isArray(fieldDefs.useRenderOn) ? fieldDefs.useRenderOn : [];    // Only render if useRenderOn is set and includes current mode  if (renderModes.length === 0 || !renderModes.includes(this.mode)) {  return; // Do not render formatted percentage  }    const $span = $('<span>').text(value.toFixed(2) + '%');    // Read field parameters from metadata  const useLabel = this.params.useColorLabel === true;  const useText = this.params.useColorText === true;  //const useLabel = fieldDefs.useColorLabel === true;  //const useText = fieldDefs.useColorText === true;    if (useLabel) {  $span.addClass(this.getLabelClass(value));  }    if (useText) {  $span.addClass(this.getTextClass(value));  }    this.$el.empty().append($span);  }    /**  * Bootstrap label classes for badge-style color background.  *   * | Class Name | Description |  * | --------------- | ------------------------------------- |  * | label-default | Gray (neutral) |  * | label-primary | Dark blue (informational or negative)|  * | label-success | Green (positive/success) |  * | label-warning | Orange (caution) |  * | label-danger | Red (critical/negative) |  * | label-info | Light blue (general info) |  *   * Conditions can be adjusted in getLabelClass().  */  getLabelClass(value) {  if (value < 0) return 'label label-md label-primary';  if (value > 0) return 'label label-md label-danger';  return 'label label-md label-success';  }    /**  * Bootstrap text color classes (affects text color only).  *   * | Class Name | Description |  * | -------------- | ---------------------------------- |  * | text-muted | Light gray (subtle/disabled) |  * | text-primary | Dark blue (informational or negative) |  * | text-success | Green (positive/success) |  * | text-info | Light blue (neutral info) |  * | text-warning | Orange (warning) |  * | text-danger | Red (critical/negative) |  *   * Conditions can be adjusted in getTextClass().  */  getTextClass(value) {  if (value < 0) return 'text-primary';  if (value > 0) return 'text-danger';  return 'text-success';  }  }  });
      ​ 

      Comment

      • Marcel
        Junior Member
        • Jul 2025
        • 13

        #4
        Hi item

        Thanks a lot! That helped!

        I created this script out of it and I am currently trying to create that a bit more modular. I want to set parameters per field in the entityDefs file like

        PHP Code:

                
        "interestRate": {
                    
        "notNull"false,
                    
        "type""float",
                    
        "required"false,
                    
        "audited"true,
                    
        "max"100,
                    
        "decimalPlaces"2,
                    
        "isCustom"true,
                    
        "tooltip"true,
                    
        "view""custom:views/fields/percent-float",
                    
        "useColorLabel"true,
                    
        "useColorText"true,
                    
        "useRenderOn": ["list""detail"]
                } 
        is that somehow possible?

        I tried a bit arround. See my comments in the Code

        PHP Code:

        /**
         * Extend the default FloatFieldView to render percentage values with optional color styling
         *
         * Example "../metadata/entityDefs/[ENTITYNAME].json" field
         * "interestRate": {
         *     "type": "float",
         *     "decimalPlaces": 2,
         *     "max": 100,
         *     "isCustom": true,
         *     "view": "custom:views/fields/percent-float",     // This needs to be added
         *     "useColorLabel": true,                           // This can be added if you want to use label colors. If you don´t set it, it will be false
         *     "useColorText": true,                            // This can be added if you want to use text colors. If you don´t set it, it will be false
         *     "useRenderOn": ["list", "detail"]                // This can be used to define where the formatted render should be used. If missing or empty, nothing will be rendered.
         * }
         */

        define(['views/fields/float'], (FloatFieldView) => {
            return class extends 
        FloatFieldView {

                
        setup () {
                    
        super.setup();
                }

                
        afterRender () {
                    
        super.afterRender();

                    
        // Safety check for unexpected call contexts
                    
        if (!this.model || !this.name || typeof this.model.get !== 'function') return;

                    const 
        value parseFloat(this.model.get(this.name));
                    if (
        isNaN(value)) return;

                    
        /**
                     * Read target render modes from metadata.
                     *
                     * Supported render modes in EspoCRM for field views:
                     *
                     * | Mode         | Meaning / Usage Context                                     |
                     * | ------------ | ----------------------------------------------------------- |
                     * | `list`       | Entity list view (grid/table showing multiple records)      |
                     * | `detail`     | Detail view of a single record (read-only display)          |
                     * | `edit`       | Edit mode (form for editing a record)                       |
                     * | `search`     | Search/filter form mode (filter fields in list search)      |
                     * | `massUpdate` | Mass update mode (bulk editing dialog for multiple records) |
                     * | `kanban`     | Kanban board view mode (card style layout for records)      |
                     * | `preview`    | Preview mode (e.g. quick view panels or preview popups)     |
                     */

                    // Get field metadata from entityDefs via Metadata API
                    //const entityDefs = this.model.getMetadata().get('entityDefs')[this.model.name] || {};
                    //const fieldDefs = (entityDefs.fields && entityDefs.fields[this.name]) ? entityDefs.fields[this.name] : {};

                    // Try different places to get field definitions
                    //const fieldDefs = this.def || this.fieldDefs || {};

                    
        const renderModes = Array.isArray(this.params.useRenderOn) ? this.params.useRenderOn : ['list''detail'];
                    
        //const renderModes = Array.isArray(this.params.useRenderOn) ? this.params.useRenderOn : [];
                    //const renderModes = Array.isArray(fieldDefs.useRenderOn) ? fieldDefs.useRenderOn : [];

                    // Only render if useRenderOn is set and includes current mode
                    
        if (renderModes.length === || !renderModes.includes(this.mode)) {
                        return; 
        // Do not render formatted percentage
                    
        }

                    const 
        $span = $('<span>').text(value.toFixed(2) + '%');

                    
        // Read field parameters from metadata
                    
        const useLabel this.params.useColorLabel === true;
                    const 
        useText this.params.useColorText === true;
                    
        //const useLabel = fieldDefs.useColorLabel === true;
                    //const useText = fieldDefs.useColorText === true;

                    
        if (useLabel) {
                        
        $span.addClass(this.getLabelClass(value));
                    }

                    if (
        useText) {
                        
        $span.addClass(this.getTextClass(value));
                    }

                    
        this.$el.empty().append($span);
                }

                
        /**
                 * Bootstrap label classes for badge-style color background.
                 *
                 * | Class Name      | Description                             |
                 * | --------------- | ------------------------------------- |
                 * | label-default   | Gray (neutral)                        |
                 * | label-primary   | Dark blue (informational or negative)|
                 * | label-success   | Green (positive/success)              |
                 * | label-warning   | Orange (caution)                      |
                 * | label-danger    | Red (critical/negative)               |
                 * | label-info      | Light blue (general info)             |
                 *
                 * Conditions can be adjusted in getLabelClass().
                 */
                
        getLabelClass(value) {
                    if (
        value 0) return 'label label-md label-primary';
                    if (
        value 0) return 'label label-md label-danger';
                    return 
        'label label-md label-success';
                }

                
        /**
                 * Bootstrap text color classes (affects text color only).
                 *
                 * | Class Name     | Description                          |
                 * | -------------- | ---------------------------------- |
                 * | text-muted     | Light gray (subtle/disabled)       |
                 * | text-primary   | Dark blue (informational or negative) |
                 * | text-success   | Green (positive/success)            |
                 * | text-info      | Light blue (neutral info)           |
                 * | text-warning   | Orange (warning)                    |
                 * | text-danger    | Red (critical/negative)             |
                 *
                 * Conditions can be adjusted in getTextClass().
                 */
                
        getTextClass(value) {
                    if (
        value 0) return 'text-primary';
                    if (
        value 0) return 'text-danger';
                    return 
        'text-success';
                }
            }
        }); 

        Comment

        • item
          Active Community Member
          • Mar 2017
          • 1539

          #5
          Hi,
          if i understand :

          create custom/Espo/Custom/Resources/metadata/fields/pourcent-float.json

          see out-of-box float field

          PHP Code:

          {  
              
          "params": [  
                  {  
                      
          "name""required",  
                      
          "type""bool",  
                      
          "default"false  
                  
          },  
                  {  
                      
          "name""default",  
                      
          "type""float"  
                  
          },  
                  {  
                      
          "name""min",  
                      
          "type""float"  
                  
          },  
                  {  
                      
          "name""max",  
                      
          "type""float"  
                  
          },  
                  {  
                      
          "name""decimalPlaces",  
                      
          "type""int"  
                  
          },  
                  {  
                      
          "name""useColorLabel",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""useColorText",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""useRenderOn",  
                      
          "type""multiEnum",  
                      
          "options": ["list""detail"]  
                  },  
                  {  
                      
          "name""audited",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""readOnly",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""readOnlyAfterCreate",  
                      
          "type""bool"  
                  
          }  
              ],  
              
          "validationList": [  
                  
          "required",  
                  
          "min",  
                  
          "max"  
              
          ],  
              
          "mandatoryValidationList": [  
                  
          "valid"  
              
          ],  
              
          "filter"true,  
              
          "view""views/fields/pourcent-float",  
              
          "fieldDefs": {  
                  
          "notNull"false  
              
          }  

          or something so :

          path : custom/Espo/Custom/Resources/metadata/fields/float.json

          PHP Code:
          {  
              
          "params": [
                  
          "__APPEND__",  
                  {  
                      
          "name""useColorLabel",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""useColorText",  
                      
          "type""bool"  
                  
          },  
                  {  
                      
          "name""useRenderOn",  
                      
          "type""multiEnum",  
                      
          "options": ["list""detail"]  
                  }
              ]  

          language file in custom dir : i18n/en_US/Admin.json and 18n/en_US/FieldManager.json
          this need to be brainstorm i think... why pourcent... maybe appendChar so you can append % ou another char (km, m, *, #) or prepend.
          if i am wrong, please anybody can correct.
          Last edited by item; 07-28-2025, 07:03 AM.
          If you could give the project a star on GitHub. EspoCrm believe our work truly deserves more recognition. Thanks.​

          Comment

          • Marcel
            Junior Member
            • Jul 2025
            • 13

            #6
            Originally posted by item
            Hi,
            if i understand :

            create custom/Espo/Custom/Resources/metadata/fields/pourcent-float.json

            see out-of-box float field

            PHP Code:

            {
            "params": [
            {
            "name""required",
            "type""bool",
            "default"false
            },
            {
            "name""default",
            "type""float"
            },
            {
            "name""min",
            "type""float"
            },
            {
            "name""max",
            "type""float"
            },
            {
            "name""decimalPlaces",
            "type""int"
            },
            {
            "name""useColorLabel",
            "type""bool"
            },
            {
            "name""useColorText",
            "type""bool"
            },
            {
            "name""useRenderOn",
            "type""multiEnum",
            "options": ["list""detail"]
            },
            {
            "name""audited",
            "type""bool"
            },
            {
            "name""readOnly",
            "type""bool"
            },
            {
            "name""readOnlyAfterCreate",
            "type""bool"
            }
            ],
            "validationList": [
            "required",
            "min",
            "max"
            ],
            "mandatoryValidationList": [
            "valid"
            ],
            "filter"true,
            "view""views/fields/pourcent-float",
            "fieldDefs": {
            "notNull"false
            }

            or something so :

            path : custom/Espo/Custom/Resources/metadata/fields/float.json

            PHP Code:
            {
            "params": [
            "__APPEND__",
            {
            "name""useColorLabel",
            "type""bool"
            },
            {
            "name""useColorText",
            "type""bool"
            },
            {
            "name""useRenderOn",
            "type""multiEnum",
            "options": ["list""detail"]
            }
            ]

            language file in custom dir : i18n/en_US/Admin.json and 18n/en_US/FieldManager.json
            this need to be brainstorm i think... why pourcent... maybe appendChar so you can append % ou another char (km, m, *, #) or prepend.
            if i am wrong, please anybody can correct.
            Thank you, that is helping a lot!

            After I created the file custom/Espo/Custom/Resources/metadata/fields/percent-float.json -> I was able to create a new field with the additional parameters. But even when I set those parameters I don´t get the value into the code with this.params.useRenderOn for example. Is there another way to get the value ?

            Thanks!

            Comment

            • Marcel
              Junior Member
              • Jul 2025
              • 13

              #7
              I think I got it. I will post it tomorrow.

              Comment

              • shalmaxb
                Senior Member
                • Mar 2015
                • 1710

                #8
                You could achieve this also all without coding.
                1. You have your float field
                2. introduce an enum field, name it "unit" and fill it with the unit options you want to provide.
                3. create a field "output" or whatever name
                4. create a formula, that concatenates the float and unit values and writes it to the output.

                The formula can be formatted to include ifThen rules etc. and und circumstances only the concatenated field will be displayed. That depends, how you achieve the value of the float field.

                Comment

                Working...