{"id":18817868,"url":"https://github.com/vitorluizc/vue-loadable","last_synced_at":"2025-07-14T15:37:08.954Z","repository":{"id":26085412,"uuid":"107300463","full_name":"VitorLuizC/vue-loadable","owner":"VitorLuizC","description":" ⏳ Improve your loading state control with pretty simple methods and helpers.","archived":false,"fork":false,"pushed_at":"2022-12-10T20:30:30.000Z","size":2854,"stargazers_count":25,"open_issues_count":21,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-11T20:47:24.257Z","etag":null,"topics":["async","asynchronous","decorator","interceptor","loadable","loading","loading-indicator","loading-state","promise","vue","vue-mixin","vue-plugin","vuex"],"latest_commit_sha":null,"homepage":"","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/VitorLuizC.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-17T17:14:46.000Z","updated_at":"2025-03-21T14:49:02.000Z","dependencies_parsed_at":"2023-01-14T04:00:20.399Z","dependency_job_id":null,"html_url":"https://github.com/VitorLuizC/vue-loadable","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/VitorLuizC/vue-loadable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VitorLuizC%2Fvue-loadable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VitorLuizC%2Fvue-loadable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VitorLuizC%2Fvue-loadable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VitorLuizC%2Fvue-loadable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VitorLuizC","download_url":"https://codeload.github.com/VitorLuizC/vue-loadable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VitorLuizC%2Fvue-loadable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265313079,"owners_count":23745185,"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":["async","asynchronous","decorator","interceptor","loadable","loading","loading-indicator","loading-state","promise","vue","vue-mixin","vue-plugin","vuex"],"created_at":"2024-11-08T00:13:45.823Z","updated_at":"2025-07-14T15:37:08.924Z","avatar_url":"https://github.com/VitorLuizC.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `vue-loadable`\n\n[![Build Status](https://travis-ci.org/VitorLuizC/vue-loadable.svg?branch=master)](https://travis-ci.org/VitorLuizC/vue-loadable)\n[![License](https://badgen.net/github/license/VitorLuizC/vue-loadable)](./LICENSE)\n[![Library minified size](https://badgen.net/bundlephobia/min/vue-loadable)](https://bundlephobia.com/result?p=vue-loadable)\n[![Library minified + gzipped size](https://badgen.net/bundlephobia/minzip/vue-loadable)](https://bundlephobia.com/result?p=vue-loadable)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FVitorLuizC%2Fvue-loadable.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FVitorLuizC%2Fvue-loadable?ref=badge_shield)\n\n`vue-loadable` improves your loading state flow by providing methods and helpers to manage it.\n\n```html\n\u003ctemplate\u003e\n  \u003cp v-if=\"$isLoading('initialize')\"\u003eInitializing...\u003c/p\u003e\n  \u003cdiv v-else\u003e\n    \u003c!-- Loaded content... --\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport { mapActions } from 'vuex';\nimport { loadable, mapLoadableMethods } from 'vue-loadable';\n\nexport default {\n  ...,\n\n  methods: {\n    async initialize () {\n      // Set initialize state as loading on async function start.\n      this.$setLoading('initialize');\n\n      try {\n        await this.$store.dispatch('users/fetchUsers');\n      } catch (_) {}\n\n      // Unset initialize state as loading on async function end.\n      this.$unsetLoading('initialize');\n    },\n\n    // `loadable` decorator can automate this process.\n    initialize: loadable(async function () {\n      await this.$store.dispatch('users/fetchUsers');\n    }, 'initialize'),\n\n    // An there's `mapLoadableMethods` to map methods into loadable methods (works with Vuex too).\n    ...mapLoadableMethods(\n      mapActions('users', {\n        initialize: 'fetchUsers'\n      })\n    )\n  },\n  mounted () {\n    this.initialize();\n  }\n};\n```\n\n## Installation\n\nThis library is published in the NPM registry and can be installed using any compatible package manager.\n\n```sh\nnpm install --save vue-loadable\n\n# Use the command below if you're using Yarn.\nyarn add vue-loadable\n```\n\n### Installation from CDN\n\nThis module has an UMD bundle available through JSDelivr and Unpkg CDNs.\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/vue\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/vue-loadable\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  // module will be available through `VueLoadable` object.\n  console.log(VueLoadable);\n\n  Vue.use(VueLoadable);\n\u003c/script\u003e\n```\n\n## Installation on Vue\n\n`vue-loadable` need to be installed to enable loadable methods, `loadable` decorator and `mapLoadableMethods` helper.\n\nTo install globally, just pass default exported object as argment to `Vue.use`.\n\n```js\nimport Vue from 'vue';\nimport Loadable from 'vue-loadable';\n\nVue.use(Loadable);\n```\n\nYou can install it locally instead with `LoadableMixin` mixin.\n\n```vue\n\u003cscript\u003e\nimport { LoadableMixin } from 'vue-loadable';\n\nexport default {\n  mixins: [LoadableMixin],\n};\n\u003c/script\u003e\n```\n\n## API\n\n- **`loadable`** decorates a function to change loading state during its execution. It sets the state as loading when function inits and unsets when it throws an error, when it resolves or when it returns a value.\n\n  \u003e Second argument is the loading state name, is `\"unknown\"` when it's not defined.\n\n  ```js\n  Vue.component('SignInForm', {\n    methods: {\n      signIn: loadable(async function(name) {\n        // ...\n      }, 'signIn'),\n    },\n\n    async mounted() {\n      this.$isLoading('signIn');\n      //=\u003e false\n\n      const promise = this.signIn('Vitor');\n\n      this.$isLoading('signIn');\n      //=\u003e true\n\n      await promise;\n\n      this.$isLoading('signIn');\n      //=\u003e false\n    },\n  });\n  ```\n\n  \u003e It passes down the function arguments, rejects the errors and resolves the returned value.\n  \u003e\n  \u003e ```ts\n  \u003e async function confirmUsername(username: string): Promise\u003cboolean\u003e {\n  \u003e   // ...\n  \u003e }\n  \u003e\n  \u003e export default {\n  \u003e   methods: {\n  \u003e     // Returns a function with same signature, but handling loading states.\n  \u003e     confirm: loadable(confirmUsername, 'confirmation'),\n  \u003e   },\n  \u003e   async mounted(): Promise\u003cvoid\u003e {\n  \u003e     try {\n  \u003e       const isConfirmed = await this.confirm('VitorLuizC');\n  \u003e       this.$router.push(isConfirmed ? '/checkout' : '/confirmation');\n  \u003e     } catch (error) {\n  \u003e       new Rollbar.Error(error).send();\n  \u003e     }\n  \u003e   },\n  \u003e };\n  \u003e ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  type Method =\n    | ((...args: any[]) =\u003e any)\n    | ((this: Vue, ...args: any[]) =\u003e any);\n\n  type LoadableMethod\u003cT extends Method\u003e = (\n    this: Vue,\n    ...args: Parameters\u003cT\u003e\n  ) =\u003e ReturnType\u003cT\u003e extends Promise\u003cany\u003e\n    ? ReturnType\u003cT\u003e\n    : Promise\u003cReturnType\u003cT\u003e\u003e;\n\n  const loadable: \u003cT extends Method\u003e(\n    method: T,\n    state?: string,\n  ) =\u003e LoadableMethod\u003cT\u003e;\n  ```\n\n  \u003c/details\u003e\n\n- **`mapLoadableMethods`** maps methods into loadable ones that triggers loading states, it works pretty well with Vuex.\n\n  \u003e It uses method's names as loading state name.\n\n  ```vue\n  \u003ctemplate\u003e\n    \u003cdiv v-if=\"$isLoading('signInUser')\"\u003e\n      Carregando...\n    \u003c/div\u003e\n    \u003cdiv v-else\u003e\n      \u003cSignedUserArea /\u003e\n    \u003c/div\u003e\n  \u003c/template\u003e\n\n  \u003cscript\u003e\n  import { mapActions } from 'vuex';\n  import { mapLoadableMethods } from 'vue-loadable';\n\n  export default {\n    methods: mapLoadableMethods(\n      mapActions([\n        'signInUser',\n        'signUpUser'\n      ])\n    )\n  };\n  ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  // `Method` and `LoadableMethod` are defined at `loadable` type definitions.\n\n  type Methods = Record\u003cstring, Method\u003e;\n\n  type LoadableMethods\u003cT extends Methods\u003e = {\n    [K in keyof T]: LoadableMethod\u003cT[K]\u003e;\n  };\n\n  const mapLoadableMethods: \u003cT extends Methods\u003e\u003e(\n    methods: T,\n  ) =\u003e LoadableMethods\u003cT\u003e;\n  ```\n\n  \u003c/details\u003e\n\n- **`$isLoading`** is a method to check if a state is loading.\n\n  \u003e Argument is the loading state name, is `\"unknown\"` when it's not defined.\n\n  ```vue\n  \u003ctemplate\u003e\n    \u003cv-spinner v-if=\"$isLoading('initialize')\" /\u003e\n    \u003csign-in-form v-else @click=\"onClickSignIn\" ... /\u003e\n  \u003c/template\u003e\n\n  \u003cscript\u003e\n  // ...\n\n  export default {\n    methods: {\n      ...,\n      onClickSignIn () {\n        if (!this.$isLoading('signIn')) // Call `signIn` only if its not loading.\n          return;\n\n        this.signIn();\n      }\n    }\n  };\n  ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  interface Vue {\n    $isLoading(state?: string): boolean;\n  }\n  ```\n\n  \u003c/details\u003e\n\n- **`$isLoadingAny`** is a method to check if any state is loading.\n\n  ```vue\n  \u003ctemplate\u003e\n    \u003cv-spinner v-if=\"$isLoadingAny()\" /\u003e\n    \u003cdiv\u003e\n      \u003csign-in-or-sign-up-form @signIn=\"onSignIn\" @signUp=\"onSignUp\" /\u003e\n    \u003c/div\u003e\n  \u003c/template\u003e\n\n  \u003cscript\u003e\n  // ...\n\n  export default {\n    methods: {\n      ...,\n      onSignUp () {\n        if (!this.$isLoadingAny())\n          return;\n\n        this.signUp();\n      },\n      onSignIn () {\n        if (!this.$isLoadingAny())\n          return;\n\n        this.signIn();\n      }\n    }\n  };\n  ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  interface Vue {\n    $isLoadingAny(): boolean;\n  }\n  ```\n\n  \u003c/details\u003e\n\n- **`$setLoading`** is a method to set state as loading.\n\n  \u003e Argument is the loading state name, is `\"unknown\"` when it's not defined.\n\n  ```js\n  export default {\n    methods: {\n      ...,\n      async onSubmit () {\n        this.$setLoading('submission'); // set submission state as loading.\n\n        await services.submit(this.fields);\n      }\n    }\n  };\n  ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  interface Vue {\n    $setLoading(state?: string): void;\n  }\n  ```\n\n  \u003c/details\u003e\n\n- **`$unsetLoading`** is a method to unset state as loading.\n\n  \u003e Argument is the loading state name, is `\"unknown\"` when it's not defined.\n\n  ```js\n  export default {\n    methods: {\n      ...,\n      async onSubmit () {\n        try {\n          await services.submit(this.fields);\n        } catch {}\n\n        this.$unsetLoading('submission'); // unset submission state as loading.\n      }\n    }\n  };\n  ```\n\n  \u003cdetails\u003e\n    \u003csummary\u003eTypeScript type definitions.\u003c/summary\u003e\n\n  \u003cbr /\u003e\n\n  ```ts\n  interface Vue {\n    $unsetLoading(state?: string): void;\n  }\n  ```\n\n  \u003c/details\u003e\n\n## License\n\nReleased under [MIT License](./LICENSE).\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FVitorLuizC%2Fvue-loadable.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FVitorLuizC%2Fvue-loadable?ref=badge_large)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvitorluizc%2Fvue-loadable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvitorluizc%2Fvue-loadable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvitorluizc%2Fvue-loadable/lists"}