{"id":13808378,"url":"https://github.com/ngneat/edit-in-place","last_synced_at":"2025-05-07T18:15:32.332Z","repository":{"id":37953923,"uuid":"278583623","full_name":"ngneat/edit-in-place","owner":"ngneat","description":"A flexible and unopinionated edit in place library for Angular applications","archived":false,"fork":false,"pushed_at":"2024-05-20T19:40:54.000Z","size":3366,"stargazers_count":269,"open_issues_count":19,"forks_count":20,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-07T18:15:28.499Z","etag":null,"topics":["angular","form"],"latest_commit_sha":null,"homepage":"https://ngneat.github.io/edit-in-place","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngneat.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ngneat"}},"created_at":"2020-07-10T08:42:13.000Z","updated_at":"2025-04-30T08:44:41.000Z","dependencies_parsed_at":"2024-05-03T03:43:09.671Z","dependency_job_id":"6a6439cb-5790-4bc2-a027-a2572b0a6c8b","html_url":"https://github.com/ngneat/edit-in-place","commit_stats":{"total_commits":96,"total_committers":7,"mean_commits":"13.714285714285714","dds":"0.36458333333333337","last_synced_commit":"85644478dfc60e104fea6bf3aba563fc477a6ca2"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fedit-in-place","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fedit-in-place/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fedit-in-place/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fedit-in-place/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngneat","download_url":"https://codeload.github.com/ngneat/edit-in-place/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252931506,"owners_count":21827112,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","form"],"created_at":"2024-08-04T01:01:41.366Z","updated_at":"2025-05-07T18:15:32.307Z","avatar_url":"https://github.com/ngneat.png","language":"TypeScript","funding_links":["https://github.com/sponsors/ngneat"],"categories":["Table of contents"],"sub_categories":["Third Party Components"],"readme":"\u003cp align=\"center\"\u003e\n \u003cimg width=\"20%\" height=\"20%\" src=\"./logo.svg\" alt=\"project logo\"\u003e\n\u003c/p\u003e\n\n\u003cbr /\u003e\n\n[![MIT](https://img.shields.io/packagist/l/doctrine/orm.svg?style=flat-square)]()\n[![commitizen](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)]()\n[![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)]()\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-2)\n[![ngneat](https://img.shields.io/badge/@-ngneat-383636?style=flat-square\u0026labelColor=8f68d4)](https://github.com/ngneat/)\n[![spectator](https://img.shields.io/badge/tested%20with-spectator-2196F3.svg?style=flat-square)]()\n\n\u003e A flexible and unopinionated edit in place library for Angular applications\n\nEdit in place is a complete solution for switching modes between static content and an editable control that allows editing it.\n\nFollowing open/closed principle, the library focuses on the switch mechanism, giving you full control of the data you want to update and the content you want to display and how to edit it.\n\n![alt-text](./demo.gif)\n\n[Demo](https://ngneat.github.io/edit-in-place)\n\n## Features\n\n- ✅ Fully customizable\n- ✅ Manual trigger support \n- ✅ Reactive Forms support\n- ✅ Multiple Forms support\n\n## Installation\n\n`npm install @ngneat/edit-in-place`\n\n## Usage\n\n### version 1.9 and above\n\n\u003e The project is now using the Angular Standalone API and support SSR.\n\u003e It requires Angular 16+\n\nImports the **EditableComponent**, **EditModeDirective** and **ViewModeDirective** in the ìmports array of your **NgModule** or your standalone**Component**:\n\n```typescript\nimport { EditableComponent, EditModeDirective, ViewModeDirective } from '@ngneat/edit-in-place';\n\n@NgModule({\n  ...\n  standalone: true,\n  imports: [EditableComponent, EditModeDirective, ViewModeDirective],\n})\nexport class AppComponent {}\n```\n\n### version 1.6 and below\n\nAdd the `EditableModule` to your `AppModule`.\n\n```typescript\nimport { EditableModule } from '@ngneat/edit-in-place';\n\n@NgModule({\n  declarations: [AppComponent],\n  imports: [EditableModule],\n  bootstrap: [AppComponent]\n})\nexport class AppModule {}\n```\n\nNow you can use the `\u003ceditable\u003e` component:\n\n```ts\n@Component({\n  template: `\n    \u003ceditable (save)=\"update()\" (cancel)=\"cancel()\"\u003e\n      \u003cng-template viewMode\u003e{{ value }}\u003c/ng-template\u003e\n\n      \u003cng-template editMode\u003e\n        \u003cinput editableOnEnter editableOnEscape [formControl]=\"control\" /\u003e\n      \u003c/ng-template\u003e\n    \u003c/editable\u003e\n  `\n})\nclass MyComponent {\n  value = 'foo';\n  control = new FormControl(this.value);\n\n  update() {\n    this.value = this.control.value;\n  }\n\n  cancel() {\n    this.control.setValue(this.value);\n  }\n}\n```\n\nFor more complex examples, check out the [playground](https://github.com/ngneat/edit-in-place/blob/master/src/app/app.component.html).\n\n### Changing the Active Mode\n\nClick on the `viewMode` template to switch it to `editMode` or click outside the editable component to switch back to `viewMode`.\n\nYou can customize the switch trigger which set to `click` by default by providing a `MouseEvent` type:\n\n```html\n\u003ceditable openBindingEvent=\"dblclick\"\n          closeBindingEvent=\"dblclick\"\u003e\n    ...\n\u003c/editable\u003e\n```\n\nYou can also set this value globally by providing it in the `EDITABLE_CONFIG` provider:\n\n```typescript\n@NgModule({\n  ...\n  providers: [\n    {\n      provide: EDITABLE_CONFIG, \n      useValue: {\n        openBindingEvent: 'dblclick',\n        closeBindingEvent: 'dblclick',\n      } as EditableConfig\n    }\n  ]\n})\nexport class AppModule {}\n```\n\n\n## Handle Events Manually\n\nYou can use the `editableOnUpdate` and `editableOnCancel` directives to trigger the update or the reset of the value on chosen elements.\n\n```html\n\u003ceditable (save)=\"updateField()\" (cancel)=\"resetField()\"\u003e\n  \u003cng-template viewMode\u003e...\u003c/ng-template\u003e\n\n  \u003cng-template editMode\u003e\n    \u003cinput formControlName=\"name\"\u003e\n    \u003cbutton editableOnSave\u003eSave\u003c/button\u003e\n    \u003cbutton editableOnCancel\u003eCancel\u003c/button\u003e    \n  \u003c/ng-template\u003e\n\u003c/editable\u003e\n```\n\n## Track event changes\n\nYou can use the `modeChange` event to know what is the state of a given `EditableComponent`.\n\n```html\n\u003ceditable (modeChange)=\"doWhatever()\"\u003e\n  \u003cng-template viewMode\u003e...\u003c/ng-template\u003e\n\n  \u003cng-template editMode\u003e\n    \u003cinput formControlName=\"name\"\u003e\n    \u003cbutton editableOnSave\u003eSave\u003c/button\u003e\n    \u003cbutton editableOnCancel\u003eCancel\u003c/button\u003e    \n  \u003c/ng-template\u003e\n\u003c/editable\u003e\n```\n\n## Handle Focus\n\nAs a focusable form tag might be nested or custom, it isn't focused by default when the `editMode` is displayed.\n\nTo make it focusable, you can add the `editableFocus` directive on the input:\n\n```html\n\u003ceditable\u003e\n\n  \u003cng-template viewMode\u003e\n    ... \n  \u003c/ng-template\u003e\n\n  \u003cng-template editMode\u003e\n    \u003cinput editableFocusable formControlName=\"name\"\u003e   \n  \u003c/ng-template\u003e\n\u003c/editable\u003e\n```\n\n## Events\n\nAdd the `(save)` event binding to handle the update of the content. \n\n```html\n\u003ceditable (save)=\"updateField()\"\u003e\n   ...\n\u003c/editable\u003e\n```\n\nThe following actions will trigger this event:\n\n- `editableOnEnter` directive\n- `editableOnSave` directive\n- `closeBindingEvent` @Input() MouseEvent\n\n\nOptionally you can add the `(cancel)` event binding to handle the reset of the value of a formControl:\n\n```html\n\u003ceditable (cancel)=\"resetField()\"\u003e\n  ...\n\u003c/editable\u003e\n```\n\nThe following actions will trigger this event:\n\n- `editableCancel` directive\n- `editableOnEscape` directive\n\n## Inputs\n\n| @Input                 | Type                      | Description                                                  | Default                                                                |\n| ---------------------- | ------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- |\n| openBindingEvent       | `string`                  | The MouseEvent type to display the editMode                  | `click`                                                              |\n| closeBindingEvent      | `string`                  | The MouseEvent type to display the viewMode                  | `click`                                                                 |\n| enabled                | `boolean`                 | Allows or forbids edit mode (doesn't switch to it)           | `true`                                                                 |\n\n## Outputs\n\n| @Output                | Type                      | Description                                                                                                               |\n| ---------------------- | ------------------------- | ------------------------------------------------------------\n| save                   | `void`                    | triggered by the editableOnSave and editableOnEnter directives and the MouseEvent on closeBindingEvent @Input                                                                               |\n| cancel                 | `void`                    | triggered by the editableCancel and editableOnEscape directives                                                                                 |\n| modeChange             | `edit` or `view`          | triggered when the mode changes                                                                               |\n\n\n## Directives\n\n#### editableFocusable\n\n\u003e import { EditableFocusableDirective } from '@ngneat/edit-in-place';\n\nFocus the host element when switching to `editMode` (for nested inputs).\n\n#### editableOnEnter\n\n\u003e import { EditableOnEnterDirective } from '@ngneat/edit-in-place';\n\nListen to keyup `enter` to switch to `viewMode` and update the value of the `viewMode` host element.\n\n#### editableOnEscape\n\n\u003e import { EditableOnEscapeDirective } from '@ngneat/edit-in-place';\n\nListen to keyup `escape` to switch to `viewMode` without updating the value of the `viewMode` host element.\n\n#### editableOnSave\n\n\u003e import { EditableOnSaveDirective } from '@ngneat/edit-in-place';\n\nListen to a `MouseEvent` on ths host element in order to switch to `viewMode` and udpate the value of the content of the `viewMode`*host element.\n\n| @Input                 | Type                      | Description                                                  | Default                                                                |\n| ---------------------- | ------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- |\n| saveEvent              | `string`                  | The MouseEvent type used to trigger the @Output() save       | `click`                                                              |\n\n\n#### editableOnCancel\n\nListen to a `MouseEvent` on ths host element in order to trigger to switch to `viewMode` without updating the value of the `viewMode` host element.\n\n\n| @Input                 | Type                      | Description                                                  | Default                                                                |\n| ---------------------- | ------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------- |\n| cancelEvent            | `string`                  | The MouseEvent type used to trigger the @Output() cancel     | `click`                                                              |\n\n\n## Multiple Forms Usage\n\nedit-in-place also supports switching between modes for multiple components at once.\n\nAdd the `editableGroup` directive on a parent html tag of your `editable` components:\n\n```html\n\u003csection editableGroup\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n\u003c/section\u003e\n```\n\n### Changing the Active Mode\n\n\u003e Unlike using a single `editable` component, an `editableGroup` doesn't support `MouseEvent` events on the component to switch modes.\n\nYou can switch modes by using dedicated directives on html button tag to switch mode for the whole group:\n\n- `editableGroupEdit` to switch to `editMode`\n- `editableGroupSave` to save the value of each form tag and switch to `viewMode`\n- `editableGroupCancel` to switch to `viewMode` without saving the value of each form tag\n\n```html\n\u003csection editableGroup\u003e\n  \u003cbutton editableGroupEdit\u003eEdit\u003c/button\u003e\n  \u003cbutton editableGroupSave\u003eSave\u003c/button\u003e\n  \u003cbutton editableGroupCancel\u003eCancel\u003c/button\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n\u003c/section\u003e\n```\n\nAdd the `(editableModeChange)` event binding to keep track of the active mode.   \n\nIt's triggered by the `editableGroupEdit`, `editableGroupSave` and `editableGroupCancel` directives.\n\n```html\n\u003csection (editableModeChange)=\"handleModeChange($event)\"\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n\u003c/section\u003e\n```\n\nAdd the `(save)` event binding to handle the update of the group.   \nIt's triggered by the `editableGroupSave` directive:\n\n```html\n\u003csection (save)=\"updateGroup()\"\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n\u003c/section\u003e\n```\n\nOptionally you can add the `(cancel)` event binding to handle the reset of the value of the group.\n\nIt's triggered by the `editableGroupCancel`:\n\n```html\n\u003csection (cancel)=\"cancelUpdate()\"\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n  \u003ceditable\u003e\u003c/editable\u003e\n\u003c/section\u003e\n```\n\n## Directives\n\n#### editableGroup\n\n\u003e import { EditableGroupDirective } from '@ngneat/edit-in-place';\n\nOvercharges the behavior of children editable Components to work as one entity.\n\n| @Output                | Type                      | Description                                                                                                               |\n| ---------------------- | ------------------------- | ------------------------------------------------------------\n| save                   | `void`                    | triggered by the editableGroupSave directive                                                                           |\n| cancel                 | `void`                    | triggered by the editableGroupCancel directive                                                                               |\n| editableModeChange     | `'view'` or `'edit'`      | triggered by the editableGroupEdit, editableGroupSave and editableGroupCancel directives when switching modes                                                                              |\n\n\n#### editableGroupEdit\n\n\u003e import { EditableGroupEditDirective } from '@ngneat/edit-in-place';\n\nListen to a click `MouseEvent` to switch to *editMode*.\n\n\n#### editableGroupSave\n\n\u003e import { EditableGroupSaveDirective } from '@ngneat/edit-in-place';\n\nListen to a click `MouseEvent` to switch to *viewMode* and update the value of the group.\n\n\n#### editableGroupCancel\n\n\u003e import { EditableGroupCancelDirective } from '@ngneat/edit-in-place';\n\nListen to a click `MouseEvent` to switch to *viewMode* without updating the value of the group.\n\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://gerome-dev.netlify.com/\"\u003e\u003cimg src=\"https://avatars0.githubusercontent.com/u/32737308?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGérôme Grignon\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=geromegrignon\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=geromegrignon\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#ideas-geromegrignon\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://www.netbasal.com/\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/6745730?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNetanel Basal\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#blog-NetanelBasal\" title=\"Blogposts\"\u003e📝\u003c/a\u003e \u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=NetanelBasal\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#ideas-NetanelBasal\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/itayod\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/6719615?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eItay Oded\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=itayod\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://medium.com/@overthesanity\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7337691?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eArtur Androsovych\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=arturovt\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/baxyz\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/7852177?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBérenger\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/@ngneat/edit-in-place/commits?author=baxyz\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\nLogo made by \u003ca href=\"https://www.flaticon.com/authors/freepik\" title=\"Freepik\"\u003eFreepik\u003c/a\u003e from \u003ca href=\"https://www.flaticon.com/\" title=\"Flaticon\"\u003e www.flaticon.com\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngneat%2Fedit-in-place","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngneat%2Fedit-in-place","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngneat%2Fedit-in-place/lists"}