Skip to main content

Add a property editor

To create a property editor, we use the Inspector plugin of JointJS+. The plugin populates an ordinary <div> HTML element with an interactive form that allows the user to view and modify specific properties of Elements and Links.

In our example, we define <div id="inspector"> to be the host HTML element for our Inspector. As with the Stencil and Toolbar, we have to make sure that the Inspector is visible, and we do that via absolute positioning in our CSS.

Unlike the Stencil and PaperScroller components, we only open the Inspector when we need it, and close it when we no longer do. We define two helper functions for this - openInspector() and closeInspector(). Inside the openInspector() function, the cell refers to the Element or Link whose properties we will be editing, and the inputs specify the Inspector content:

function openInspector(cell) {
closeInspector(); // close inspector if currently open

ui.Inspector.create('#inspector', {
cell: cell,
inputs: getInspectorConfig(cell)
});
}

function closeInspector() {
ui.Inspector.close();
}

What is the content of our Inspector? Each definition inside the Inspector's inputs object specifies one property which will be editable by the user on the provided cell, and provides information to the Inspector about what kind of an HTML input field it should present for that.

Different Inspector content should be defined for different types of Cells, because different types of Cells have different properties. Our getInspectorConfig() function distinguishes between Elements and Links:

function getInspectorConfig(cell) {
if (cell.isElement()) {
return {
attrs: {
label: {
text: {
type: 'content-editable',
label: 'Label'
}
}
}
};

} else { // cell.isLink()
return {
labels: {
type: 'list',
label: 'Labels',
item: {
type: 'object',
properties: {
attrs: {
text: {
text: {
type: 'content-editable',
label: 'Text',
defaultValue: 'label'
}
}
},
position: {
type: 'select-box',
options: [
{ value: 30, content: 'Source' },
{ value: 0.5, content: 'Middle' },
{ value: -30, content: 'Target' }
],
defaultValue: 0.5,
label: 'Position'
}
}
}
}
};
}
}
What do we define in our Inspector's inputs?

If the user interacts with an Element:

  • The Element's label text can be changed.

If the user interacts with a Link:

  • The Link's list of labels can be modified - new labels can be created, existing labels can be removed.
  • An existing Link label's text can be changed.
  • An existing Link label's position can be changed to one of a list of options - close to Link source, in the middle, close to Link target.

We need to call the openInspector() and closeInspector() functions in response to user interaction. In our example, we react to three different events:

paper.on('cell:pointerdown', function (cellView) {
openInspector(cellView.model);
});

stencil.on('element:drop', function (elementView) {
openInspector(elementView.model);
});

paper.on('blank:pointerdown', function () {
closeInspector(); // close inspector if currently open
});
What do our Inspector events do?
  • Open the Inspector if the user initiates a click on a Cell (Element or Link).
  • Open the Inspector if the user drops an Element into the diagram from the Stencil.
  • Close the Inspector if the user initiates a click on an empty area of our Paper.

Finally, we tell our program to open the Inspector when the user first opens the application:

openInspector(rect1);

See it in action

You can test these new interactions in our example:

💡 Would you prefer to learn more about Property editor & viewer? We have many demos illustrating it on our Demos & examples page.