{"id":13591406,"url":"https://github.com/posva/vue-local-scope","last_synced_at":"2025-04-09T18:17:23.433Z","repository":{"id":49985115,"uuid":"161032932","full_name":"posva/vue-local-scope","owner":"posva","description":"🖇 Generate local scopes in templates to compute data from other scoped slots or simply to have variables in templates","archived":false,"fork":false,"pushed_at":"2021-06-07T07:07:55.000Z","size":29,"stargazers_count":172,"open_issues_count":3,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-09T18:17:18.158Z","etag":null,"topics":["props","scoped-slots","vue"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/posva.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/funding.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"posva","custom":"https://www.paypal.me/posva"}},"created_at":"2018-12-09T11:38:46.000Z","updated_at":"2025-02-28T03:02:41.000Z","dependencies_parsed_at":"2022-08-03T15:45:13.799Z","dependency_job_id":null,"html_url":"https://github.com/posva/vue-local-scope","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posva%2Fvue-local-scope","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posva%2Fvue-local-scope/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posva%2Fvue-local-scope/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posva%2Fvue-local-scope/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/posva","download_url":"https://codeload.github.com/posva/vue-local-scope/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248085321,"owners_count":21045139,"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":["props","scoped-slots","vue"],"created_at":"2024-08-01T16:00:57.126Z","updated_at":"2025-04-09T18:17:23.407Z","avatar_url":"https://github.com/posva.png","language":"JavaScript","funding_links":["https://github.com/sponsors/posva","https://www.paypal.me/posva"],"categories":["JavaScript"],"sub_categories":[],"readme":"# vue-local-scope [![Build Status](https://badgen.net/circleci/github/posva/vue-local-scope)](https://circleci.com/gh/posva/vue-local-scope) [![npm package](https://badgen.net/npm/v/vue-local-scope)](https://www.npmjs.com/package/vue-local-scope) [![coverage](https://badgen.net/codecov/c/github/posva/vue-local-scope)](https://codecov.io/github/posva/vue-local-scope) [![thanks](https://badgen.net/badge/thanks/♥/pink)](https://github.com/posva/thanks)\n\n\u003e 🖇 Generate local scopes in templates to compute data from other scoped slots\n\n## Installation\n\n```sh\nnpm install vue-local-scope\n```\n\n## Why?\n\nWhen using [scoped slots](https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots) you often get access to data only in the template. But sometimes, you still need to apply transformation to that data, like calling a `map` on an array or a `filter`. Here is an example using [Vue Promised](https://github.com/posva/vue-promised) to fetch information from an API endpoint:\n\n```vue\n\u003ctemplate\u003e\n  \u003cPromised :promise=\"usersPromise\" v-slot=\"users\"\u003e\n    \u003cdiv\u003e\n      \u003cAutocomplete v-model=\"selectedUsers\" :items=\"users.map(user =\u003e ({ value: user.id, label: user.name })) /\"\u003e\n      \u003cSelectedUsers :users=\"selectedUsers.map(user =\u003e users.find(u =\u003e u.id === user.value))\" /\u003e\n    \u003c/div\u003e\n  \u003c/Promised\u003e\n\u003c/template\u003e\n```\n\nThis approach has multiple issues:\n\n- The `map` functions are called everytime the component renders even if the array `users` didn't change\n- If you need the mapped version of `users` in multiple places you will duplicate the code and calls of `map`\n- There is too much code written in the template, it should definitely go in the `script` section\n\nVue Local Scope solve these problems with components and scoped slots.\n\n## Usage\n\nVue Local Scope exports two things:\n\n- **LocalScope**: a functional component that pass down any prop into a scoped slot\n- **createLocalScope** a function that returns a regular components with computed properties provided as a scoped slot\n\n### LocalScope\n\nLocalScope doesn't generate any DOM node by itself, it renders whatever is passed as a scoped slot. It allows you to not duplicate your code but still present the first and third problem discussed in the [Why](#Why) section. You can pass any prop to it, usually applying some kind of transformation, like a `map` or a `reduce`, **that transformation is only applied once everytime the template renders**, and it allows you to have a **local variable** based on anything that exists in the template. This is useful for data coming from a `v-slot`:\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cDataProvider v-slot=\"items\"\u003e\n      \u003cLocalScope\n        :names=\"items.map(i =\u003e i.name)\"\n        :ids=\"items.map(i =\u003e i.id)\"\n        v-slot=\"{ names, ids }\"\n      \u003e\n        \u003c!-- we are able to use the mapped names three times but we only run map once --\u003e\n        \u003cDisplayNames :names=\"names\" @handle-change=\"updateNames(ids, names)\" /\u003e\n        \u003cp\u003e{{ names }}\u003c/p\u003e\n        \u003cp\u003e{{ ids }}\u003c/p\u003e\n      \u003c/LocalScope\u003e\n    \u003c/DataProvider\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport { LocalScope } from 'vue-local-scope'\n\nexport default {\n  // other options\n  components: { LocalScope },\n}\n\u003c/script\u003e\n```\n\nBecause `LocalScope` is a functional component, you can return any amount of elements but it will call `map` everytime something in the same template changes.\n\n### `createLocalScope`\n\n`createLocalScope` is a function that generates a component to hold computed properties and provide them in a scoped slot. It is less convenient than LocalScope but because it generates a stateful component **it benefits from caching in computed properties**. It also exposes the data through a scoped slot:\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003c!-- Here we are intentionally using the same variable name `others` to shadow the variable inside NamesAndIdsScope --\u003e\n    \u003cDataProvider v-slot=\"{ items, others }\"\u003e\n      \u003cNamesAndIdsScope :items=\"items\" :others=\"others\" v-slot=\"{ name, ids, others }\"\u003e\n        \u003cDisplayNames :names=\"names\" @handle-change=\"updateNames(ids, names)\" /\u003e\n        \u003cp\u003e{{ names }}\u003c/p\u003e\n        \u003cp\u003e{{ ids }}\u003c/p\u003e\n        \u003cp\u003e{{ others }}\u003c/p\u003e\n      \u003c/NamesAndIdsScope\u003e\n    \u003c/DataProvider\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport { createLocalScope } from 'vue-local-scope'\n\nconst NamesAndIdsScope = createLocalScope({\n  names: ({ items }) =\u003e items.map(i =\u003e i.name),\n  ids: ({ items }) =\u003e items.map(i =\u003e i.id),\n  // we don't need to transform items but we need it as a prop\n  items: false,\n  // we can also override a value directly\n  // others is a prop and will appear in the `v-slot` variable as `others`\n  others: ({ others }) =\u003e others.filter(o =\u003e !o.skip),\n})\n\nexport default {\n  // other options\n  components: { NamesAndIdsScope },\n}\n\u003c/script\u003e\n```\n\nIn this case we do get the benefit from computed properties caching but `NamesAndIdsScope` creates a root element to group the content under it.\n\n## API\n\n### `createLocalScope(computed, propsOptions?): Component`\n\n- `computed`: object of transformations applied to props\n- `propsOptions` optional object to define `propOptions` for each key in `computed`\n\n## Related\n\n- [vue-promised](https://github.com/posva/vue-promised)\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposva%2Fvue-local-scope","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fposva%2Fvue-local-scope","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposva%2Fvue-local-scope/lists"}