Skip to content
A simple UI for editing key-value pairs
Branch: master
Clone or download
Pull request Compare This branch is 9 commits behind openshift:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
dist
docs
src
test
.gitignore
.jshintrc
.travis.yml
LICENSE
README.md
bower.json
gulpfile.js
index.html
package.json
validate.sh

README.md

angular-key-value-editor

A simple UI for editing key-value pairs

key-value-editor screenshot

Dependencies

This key-value-editor is based on the bootstrap based framework Patternfly. Patternfly or a similar boostrap based framework should be present for proper layout rendering. Icons are from font awesome. Alternative layouts with a different framework could be achieved by replacing the key-value-editor.html template which is pre-compiled into compiled-templates.js for convenience.

Tests

See the Test Readme.md file for details about running tests.

Basic usage:

Add the key-value-editor in html and provide it some data via the entries attribute:

<!-- hard coded -->
<key-value-editor entries="[{key: 'foo', value: 'bar'}]"></key-value-editor>
<!-- via scope -->
<key-value-editor entries="entries"></key-value-editor>

Note that entries is required or <key-value-editor> will log an error!

Attributes

For configuring the directive as a whole, use the following attributes.

Automatic vs manual rows:

key-value-editor screenshot

Automatic row creation is the default, however this may not be the most accessible solution depending on the placement of your other form inputs and buttons. For this reason, the attribute add-row-link is provided. If present, a link will appear that allows the user to manually create new pairs. The link text is set by passing a value to the attribute.

<key-value-editor
  entries="entries"
  add-row-link="Add another key,value pair"></key-value-editor>

If the automatic row creation feature is used, a user cannot tab past the last input in the <key-value-editor>. If a mouse or track pad is unavailable, this is not ideal as inputs after the <key-value-editor> will be unreachable, perhaps including the form submit itself.

Readonly:

<key-value-editor
  entries="entries"
  is-readonly></key-value-editor>

(is-readonly can also be an array of string names is-readonly="['foo']" for selectively making individual entries readonly. In addition, each entry.isReadonly can be set to true||false.)

Readonly keys:

<key-value-editor
  entries="entries"
  is-readonly-keys></key-value-editor>

Makes the keys of the inital set of entries readonly. Does not affect added entries. (In implementation, this just sets isReadonlyKey: true on each of the entries in the initial set of entries for you. isReadonlyKey can be directly controlled if preferred)

Disable adding new entries:

<key-value-editor
  entries="entries"
  cannot-add></key-value-editor>

Disable sorting entries:

<key-value-editor
  entries="entries"
  cannot-sort></key-value-editor>

(Sort handle will only appear if there is more than one entry in the list.)

Disable deleting entries:

<key-value-editor
  entries="entries"
  cannot-delete></key-value-editor>

(cannot-delete can also be an array of string names cannot-delete="['foo']" for selectively making individual entries readonly. In addition, each entry.cannotDelete can be set to true||false.)

Use the attributes together:

<key-value-editor
  entries="entries"
  is-readonly
  cannot-add    
  cannot-sort
  cannot-delete></key-value-editor>

Some of the above attributes can also be applied to individual entries to control them uniquely within the set:

$scope.entries = [{
  key: 'foo',
  value: 'bar',
  isReadonly: true,      // key & value are readonly
  isReadonlyKey: true,   // only key (name) is readonly
  cannotDelete: true
}];

Validator attributes and error messages:

<key-value-editor
  entries="entries"
  key-validator="[a-zA-Z0-9_]*"
  key-validator-error="Invalid name"  
  value-validator="[a-zA-Z0-9_]*"
  value-validator-error="Invalid value"></key-value-editor>

To pass a regex directly (or an object with a .test() method, simulating a regex), you can do something like the following:

// controller code:
$scope.validation = {
  key: new RegExp('^[0-9]+$'), // numbers only
  val: {
    test: function(val) {
      // some complicated test w/multiple regex or other insanity
    }
  }
}
<!-- view code -->
<key-value-editor
  entries="entries"
  key-validator-regex="validation.key"
  key-validator-error="Invalid name, numbers only plz"  
  value-validator-regex="validation.val"
  value-validator-error="Invalid value, cuz *complicated* things"></key-value-editor>

All attributes for convenient reference.

<key-value-editor
  entries="[
    {name: 'foo', value: 'stuff'},
    {name: 'bar', value: 'things'},
    {
      name: 'baz',
      value: '3',
      isReadonly: true,
      cannotDelete: true,
      isReadonlyKey: true
    }
  ]"
  key-placeholder="name"
  key-min-length="3"
  key-max-length="25"
  key-validator="[a-zA-Z0-9_]*"
  key-validator-error="Invalid name"
  key-validator-error-tooltip="Name must be alphanumeric including - and _"
  key-validator-error-tooltip-icon="fa fa-exclamation-circle"
  value-placeholder="value"
  value-min-length="3"
  value-max-length="25"
  value-validator="[a-zA-Z0-9_]*"
  value-validator-error="Invalid value"
  secret-value-tooltip="This is a hidden value"
  secret-value-icon="fa fa-external-link-square"
  is-readonly="['can','be','a','list']"
  is-readonly-keys
  cannot-delete="['can','be','a','list']"
  cannot-add    
  cannot-sort
  grab-focus></key-value-editor>

Non-standard Values

key-value-editor screenshot

Some entry lists may include non-standard key-value pairs. If the value is not a string, or is a different object entirely, such as this:

$scope.entries = [{
                    name: 'entry_value',
                    value: 'value'
                  },{
                    name: 'valueFrom-valueAlt',
                    isReadonly: true,
                    // non-standard
                    valueFrom: {
                      "configMapKeyRef": {
                        "name": "test-configmap",
                        "key": "data-1"
                      }
                    },
                    // valueAlt to the rescue!
                    valueAlt: 'valueFrom is a non-standard value',
                  }];

The valueAlt attribute can provide the user with some alt text for understanding that this key-value pair will not display properly. It is not necessary to set isReadonly:true as an input receiving valueAlt will auto to readonly. The valueValidator property, minLength and maxLength properties are all ignored as valueAlt is help text and it is assumed that it will break typical validation rules for the rest of the values.

Tooltip

NOTE: the default template provided with <key-value-editor> uses bootstrap tooltips via Patternfly/Bootstrap. Be sure to initialize the tooltips somewhere with code such as:

// opt in to the bootstrap tooltips
$('[data-toggle="tooltip"]').tooltip();

Validation

General validation rules can be put on the directive as attributes and will run against each of the entries:

<key-value-editor
  key-validator="{{regex}}"
  value-validator="{{regex2}}"
  key-validator-error="The error message if you break it"
  value-validator-error="The other error message if you break it"></key-value-editor>

For a more granular approach, each entry provided can have its own custom validation rules that will override the generic set on the directive:

return [{
  key: 'foo',
  value: 'bar',
  keyValidator: '[a-zA-Z0-9]+' // alphanumeric
  keyValidatorError: 'Thats not alphanumeric!!',
  valueValidator: '[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}', // email address
  valueValidatorError: 'Hey, this has to be an email.'
}]

For convenience, here are a few useful regex. Note that the <key-value-editor> internally uses ng-pattern which expects string regex that angular will internally new RegExp('^' + regex + '$');. Therefore be sure to leave off the leading /^ and trailing $/ or your regex will not work.

// <key-value-editor key-validator="regex.digitsOnly"></key-value-editor>
$scope.regex = {
  noWhiteSpace: '\S*',
  digitsOnly: '[0-9]+',
  alphaOnly: '[a-zA-Z]+',
  alphaNumeric: '[a-zA-Z0-9]+',
  alphaNumericUnderscore: '[a-zA-Z0-9_]*',
  alphaNumericDashes: '[a-zA-Z0-9-_]+',
  email: '[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}',
}

Setting global validation via the provider

Global defaults can be set via the provider:

angular
  .module('demo')
  .config([
    'keyValueEditorConfigProvider',
    function(keyValueEditorConfigProvider) {
      // set a global value here:
      keyValueEditorConfigProvider.set('keyValidator', '[0-9]+');
      // or, pass an object to set multiple values at once:
      keyValueEditorConfigProvider.set({
        keyValidator: '[0-9]+',
        keyValidatorError: 'This is an invalid key'
      });
    }
  ]);

Globals are still overridden via attributes on the <key-value-editor> directive, or via the entries="entries" data objects passed to the directive.

Other utils

There are two useful utility functions provided to help process the entries. The first will eliminate entries missing the name or value, the second will convert the list of entries to a map (object) of name-values (duplicate keys override values).

angular
  .module('app')
  .controller([
    'keyValueEditorUtils'
    function(kveUtils) {
      angular.extend($scope, {
        entries: [{name: 'foo', value: 'bar'}],
        // a 'save'function
        onSubmit: function() {
          // eliminates entries missing a key or val.
          console.log('compact', kveUtils.compactEntries($scope.entries));
          // transforms the array into an object.
          console.log('map', kveUtils.mapEntries($scope.entries));
        }
      })
    }
  ]);

If other filtering/mapping abilities are needed user will have to write own utils or use a lib such as lodash.

You can’t perform that action at this time.