Handle to Duplicate component

Hi,

I have a scenario where I should be able to Duplicate a component on my diagram. I achieved it by using the command handler’s copySelection and pasteSelection as shown below:

duplicateComponent(compInstance, pt, e) {
    let refDiagram = this.diagram;
    refDiagram.startTransaction('duplicate');
    refDiagram.commandHandler.copySelection();
    const point = new go.Point(e['Ir']['offsetX'] + 20, e['Ir']['offsetY'] + 20);
    refDiagram.commandHandler.pasteSelection(point);
    refDiagram.commitTransaction('duplicate');
}

In this case, If i have a node called ‘ExampleNode1’ my duplicate node is also called ‘ExampleNode1’.
But, I want the Duplicate node to have the name ‘ExampleNode1-Copy1’.

How can i achieve this?

When and how are you calling this function? What is the value of e? You should not be depending on minified property names such as “Ir”.

Which node data property does that TextBlock’s string come from?

I suggest that just before you commit your transaction you modify the data of the selected nodes, which are the newly inserted copies, so that they have the strings that you want them to have.

I have a click event on the component template. Please find it below:

click: (e, cmbutton, pt) => {
                                            const node = cmbutton.part.adornedPart;
                                            e.diagram.select(node);
                                            this.duplicateComponent(cmbutton, pt, e) 
                                        }

Im using the following binding, in the original component to display the name:

new go.Binding('text', '', (data) => {
                            let sameObjArray = [];
                            this.diagram.model.nodeDataArray.forEach(element => {
                                if (element['text'] == data.text && data.text == data.componentName) {
                                    sameObjArray.push(element);
                                }
                            });
                            let count = sameObjArray.length;
                            if (count == 0) {
                                return data.componentName;
                            } else {
                                return data.componentName + Math.abs(count);
                            }
                        }).makeTwoWay(),

Im using the counter to append a count to the component name - to keep it unique - if the same type of component is dragged and dropped onto the diagram canvas multiple times.

Also, How can i fetch the newly inserted copy to modify the data before committing the transaction?

The click event handler only takes two arguments, so pt will be undefined: https://gojs.net/latest/api/symbols/GraphObject.html#click

You probably want to use the InputEvent.documentPoint, https://gojs.net/latest/api/symbols/InputEvent.html#documentPoint

You really should not be iterating over all of the nodes in the model whenever any Bindings are evaluated. It would be better to have data.componentName always be the whole string that is shown, or else have the string be composed of the componentName as the type of node and another read-only property as the unique instance number. As it is, if a node is deleted, the numbers will change dynamically, causing confusion in users regarding the identity of the nodes.

After the call to https://gojs.net/latest/api/symbols/CommandHandler.html#pasteSelection, all of the newly inserted Parts will be selected. https://gojs.net/latest/intro/collections.html#MoreIterationExamples

Thank you. I changed my implementation to documentPoint, and also handled the click event.

I am currently modifying the text string of the Duplicated component before committing the transaction as seen below:

duplicateComponent(e) {
    let refDiagram = this.diagram;
    refDiagram.startTransaction('duplicate');
    refDiagram.commandHandler.copySelection();
    const point = new go.Point(e.documentPoint.x + 20, e.documentPoint.y + 20);
    refDiagram.commandHandler.pasteSelection(point);
    refDiagram.selection.each((part) => {
        part.data['componentName'] = this.validateComponentName(part.data['componentName']);
    })
    this.propertiesFlagEvent.emit('');
    refDiagram.commitTransaction('duplicate');
}

Where the function validateComponentName gives me the unique string for the newly inserted component.

The problem i am facing here is that the component is pasted with the original name itself. Since the name modification is done after it is pasted, the new unique string is only reflected after I move the new component, or when i click on it again.

How can this be resolved?

Got it working!
Changed
part.data['componentName'] = this.validateComponentName(part.data['componentName']);
To
this.diagram.model.setDataProperty(part.data, 'componentName', this.validateComponentName(part.data['componentName']));