# Link Creation and Editing (JavaScript Scheduler) | DayPilot Pro for JavaScript Demo

> [Create links](https://doc.daypilot.org/scheduler/link-creation-drag-and-drop/) by dragging between event handles. Click a link to [edit its color and text](https://doc.daypilot.org/scheduler/links-api/), or right-click for Edit and Delete.

## Links

- Canonical HTML: /demo/scheduler/eventlinksediting.html
- Source HTML folder: /demo/scheduler/
- Catalog root: /demo/
- Catalog: /demo/llms.txt

## Source

### Inline demo script 1

```javascript
/* global DayPilot */
        /* eslint-disable no-use-before-define -- Callbacks run after app initialization. */
        const dp = new DayPilot.Scheduler("dp", {
            startDate: "2027-04-01",
            days: 18,
            scale: "Day",
            timeHeaders: [
                {groupBy: "Month", format: "MMMM yyyy"},
                {groupBy: "Day", format: "d"}
            ],
            cellWidthSpec: "Auto",
            cellWidthMin: 45,
            rowHeaderWidth: 150,
            eventHeight: 40,
            heightSpec: "Max",
            height: 400,
            resources: [
                {id: "design", name: "Design"},
                {id: "build", name: "Development"},
                {id: "test", name: "Quality assurance"},
                {id: "ops", name: "Operations"},
                {id: "release", name: "Release"}
            ],
            timeRangeSelectedHandling: "Disabled",
            linkCreateHandling: "Update",
            linkBubble: new DayPilot.Bubble({
                onLoad: args => {
                    const data = args.source.data;
                    args.html = app.escapeHtml(app.linkTitle(data));
                    if (data.text) {
                        args.html += "<br>" + app.escapeHtml(data.text);
                    }
                }
            }),
            contextMenuLink: new DayPilot.Menu({
                items: [
                    {text: "Edit…", onClick: args => app.editLink(args.source.data)},
                    {text: "Delete", onClick: args => app.deleteLink(args.source)}
                ]
            }),
            onLinkClick: args => app.editLink(args.link.data),
            onLinkCreate: async args => {
                args.preventDefault();
                const duplicate = dp.links.list.some(link => link.from === args.from && link.to === args.to && link.type === args.type);
                if (args.from === args.to || duplicate) {
                    dp.message("This dependency already exists. Choose another connection.");
                    return;
                }
                await app.editLink({
                    id: DayPilot.guid(),
                    from: args.from,
                    to: args.to,
                    type: args.type,
                    color: "#3c78d8",
                    text: ""
                }, true);
            }
        });
        /* eslint-enable no-use-before-define */
        dp.init();

        const app = {
            init() {
                this.loadData();
                this.addEventHandlers();
            },
            addEventHandlers() {
                document.querySelector("#reset").addEventListener("click", () => this.loadData());
            },
            linkTitle(link) {
                return dp.events.find(link.from).text() + " → " + dp.events.find(link.to).text();
            },
            escapeHtml(value) {
                const element = document.createElement("div");
                element.textContent = value;
                return element.innerHTML;
            },
            deleteLink(link) {
                dp.links.remove(link);
                dp.message("Link deleted");
            },
            async editLink(data, create = false) {
                const form = [
                    {name: this.linkTitle(data), type: "title"},
                    {name: "Color", id: "color", type: "select", options: [
                        {id: "#3c78d8", name: "Blue"},
                        {id: "#6aa84f", name: "Green"},
                        {id: "#c98512", name: "Orange"},
                        {id: "#8e63b5", name: "Purple"},
                        {id: "#606060", name: "Gray"}
                    ]},
                    {name: "Text", id: "text"}
                ];
                if (data.type !== "FinishToStart") {
                    form.push({type: "html", html: "Text appears in the hover bubble. On-path labels are available for finish-to-start links."});
                }
                const modal = await DayPilot.Modal.form(form, {
                    color: data.color || "#3c78d8",
                    text: data.text || ""
                }, {
                    width: 480,
                    okText: create ? "Create link" : "Save"
                });
                if (modal.canceled) {
                    return;
                }
                const updated = {...data, color: modal.result.color, text: modal.result.text.trim()};
                if (create) {
                    dp.links.add(updated);
                } else if (dp.links.find(data.id)) {
                    dp.links.update(updated);
                }
            },
            loadData() {
                const events = [
                    {id: "design", resource: "design", text: "Design", start: "2027-04-02", end: "2027-04-05"},
                    {id: "docs", resource: "design", text: "Documentation", start: "2027-04-12", end: "2027-04-16"},
                    {id: "build", resource: "build", text: "Build", start: "2027-04-06", end: "2027-04-10"},
                    {id: "integration", resource: "build", text: "Integration", start: "2027-04-11", end: "2027-04-14"},
                    {id: "test", resource: "test", text: "Test", start: "2027-04-11", end: "2027-04-15"},
                    {id: "prepare", resource: "ops", text: "Prepare release", start: "2027-04-09", end: "2027-04-12"},
                    {id: "deploy", resource: "release", text: "Deploy", start: "2027-04-16", end: "2027-04-18"}
                ];
                const links = [
                    {id: "design-build", from: "design", to: "build", type: "FinishToStart", color: "#3c78d8", text: "Ready"},
                    {id: "build-test", from: "build", to: "test", type: "FinishToStart", color: "#6aa84f"},
                    {id: "build-integration", from: "build", to: "integration", type: "FinishToStart", color: "#606060"},
                    {id: "docs-deploy", from: "docs", to: "deploy", type: "FinishToStart", color: "#c98512"},
                    {id: "test-deploy", from: "test", to: "deploy", type: "FinishToStart", color: "#3c78d8"},
                    {id: "prepare-deploy", from: "prepare", to: "deploy", type: "FinishToStart", color: "#8e63b5"}
                ];
                dp.update({events, links});
            }
        };
        app.init();
```

