[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: murraco # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\nlfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Mauricio Urraco\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Vue Cheatsheet\n\nThis is a simplified cheatsheet along with some tips for people who often works with Vue.js.\n\n## Table of Contents\n\n* [Expressions](#expressions)\n* [Directives](#directives)\n* [List Rendering](#list-rendering)\n* [Binding](#binding)\n* [Actions / Events](#actionsevents)\n* [Component Anatomy](#component-anatomy)\n* [Custom Events](#custom-events)\n* [Life Cycle Hooks](#life-cycle-hooks)\n* [Using a Single Slot](#using-a-single-slot)\n* [Multiple slots](#multiple-slots)\n* [Libraries You Should Know](#libraries-you-should-know)\n* [Tips](#tips)\n  * [Nested objects are NOT reactive (by default)](#1-nested-objects-are-not-reactive-by-default)\n  * [Learn and use Vuex from the start](#2-learn-and-use-vuex-from-the-start)\n  * [When in doubt, re-render](#3-when-in-doubt-re-render)\n  * [Learn the difference between props and data](#4-learn-the-difference-between-props-and-data)\n  * [Have a plan for loading elements](#5-have-a-plan-for-loading-elements)\n  * [Make common filters global](#6-make-common-filters-global)\n* [Contribution](#contribution)\n* [Donate](#donate)\n\n## Expressions\n\n```vue\n<div id=\"app\">\n  <p>I have a {{ product }}</p>\n  <p>{{ product + 's' }}</p>\n  <p>{{ isWorking ? 'YES' : 'NO' }}</p>\n  <p>{{ product.getExpiryDate() }}</p>\n</div>\n```\n\n## Directives\n\nElement inserted/removed based on truthiness:\n\n```html\n<p v-if=\"inStock\">{{ product }}</p>\n<p v-else-if=\"onSale\">...</p>\n<p v-else>...</p>\n```\n\nToggles the display: none CSS property:\n\n```html\n<p v-show=\"showProductDetails\">\n  ...\n</p>\n```\n\nTwo-way data binding:\n\n```html\n<input v-model=\"firstName\">\nv.model.lazy=\"...\" // Syncs input after change event\nv.model.number=\"...\" // Always returns a number\nv.model.trim=\"...\" // Strips whitespace\n```\n\n## List Rendering\n\n```html\n<li v-for=\"item in items\" :key=\"item.id\">\n  {{ item }}\n</li>\n```\n\nTo access the position in the array:\n\n```html\n<li v-for=\"(item, index) in items\">...</li>\n```\n\nTo iterate through objects:\n\n```html\n<li v-for=\"value in object\">...</li>\n<li v-for=\"(value, index) in object\">...</li>\n<li v-for=\"(value, name, index) in object\">...</li>\n```\n\nUsing v-for with a component:\n\n```html\n<cart-product v-for=\"item in products\" :product=\"item\" :key=\"item.id\">\n```\n\n## Binding\n\n```html\n<a v-bind:href=\"url\">...</a>\n<a :href=\"url\">...</a> // Shorthand\n```\n\nTrue or false will add or remove attribute:\n\n```html\n<button :disabled=\"isButtonDisabled\">...</button>\n```\n\nIf isActive is truthy, the class 'active' will appear:\n\n```html\n<div :class=\"{ active: isActive }\">...</div>\n```\n\nStyle color set to value of activeColor:\n\n```html\n<div :style=\"{ color: activeColor }\">...</div>\n```\n\nPassing arguments to a computed binding:\n\n```vue\n<template>\n  <ProductComponent :cost=\"product_type('product_2')\"></ProductComponent>\n</template>\n\n<script>\n  import ProductComponent from @/components/ProductComponent\n  \n  export default {\n    components: { ProductComponent },\n    data() {\n      return {\n        products: {\n          product_1: '100',\n          product_2: '200',\n          product_3: '300'\n        }\n      }\n    },\n    computed: {\n      product_type() {\n        // Argument passed to arrow function, NOT computed function declaration.\n        return (product_id) => { // Arrow function to allow 'this' instance to be accessible.\n          return this.products[product_id]  // Square bracket notation for 'any' type variable\n        }\n      }\n    }\n  }\n</script>\n```\n\n## Actions/Events\n\nCalls addToCart method on component:\n\n```html\n<button v-on:click=\"addToCart\">...</button>\n<button @click=\"addToCart\">...</button> // Shorthand\n```\n\nArguments can be passed:\n\n```html\n<button @click=\"addToCart(product)\">...</button>\n```\n\nTo prevent default behaviour (e.g. page reload):\n\n```html\n<form @submit.prevent=\"addProduct\">...</form>\n```\n\nOnly trigger once:\n\n```html\n<img @mouseover.once=\"showImage\">\n.stop // Stop all event propagation\n.self // Only trigger if event.target is element itself\n```\n\nKeyboard entry example:\n\n```html\n<input @keyup.enter=\"submit\">\n```\n\nCall onCopy when control-c is pressed:\n\n```html\n<input @keyup.ctrl.c=\"onCopy\">\n```\n\nKey modifiers:\n\n```markdown\n.tab\n.delete\n.esc\n.space\n.up\n.down\n.left\n.right\n.ctrl\n.alt\n.shift\n.meta\n```\n\nMouse modifiers:\n\n```markdown\n.left\n.right\n.middle\n```\n\n## Component Anatomy\n\n```vue\n<template>\n  <span>{{ message }}</span>\n</template>\n\n<script>\n  import ProductComponent from '@/components/ProductComponent'\n  import ReviewComponent from '@/components/ReviewComponent'\n  \n  export default {\n    components: { // Components that can be used in the template\n      ProductComponent,\n      ReviewComponent\n    },\n    props: { // The parameters the component accepts\n      message: String,\n      product: Object,\n      email: {\n        type: String,\n        required: true,\n        default: 'none',\n        validator: function (value) {\n          // Should return true if value is valid\n        }\n      }\n    },\n    data: function () { // Must be a function\n      return {\n        firstName: 'Vue',\n        lastName: 'Mastery'\n      }\n    },\n    computed: { // Return cached values until dependencies change\n      fullName: function () {\n        return `${this.firstName} ${this.lastName}`\n      }\n    },\n    watch: { // Called when firstName changes value\n      firstName: function (value, oldValue) { /* ... */ }\n    },\n    methods: { /* ... */ }\n  }\n</script>\n```\n\n## Custom Events\n\nUse props (above) to pass data into child components, custom events to pass data to parent elements.\n\nSet listener on component, within its parent:\n\n```html\n<button-counter v-on:incrementBy=\"incWithVal\">...</button-counter>\n```\n\nInside parent component:\n\n```js\nmethods: {\n  incWithVal: function (toAdd) { ... }\n}\n```\n\nInside button-counter template:\n\n```js\nthis.$emit('incrementyBy', 5)\n```\n\n## Life Cycle Hooks\n\n```\nbeforeCreate\ncreated\nbeforeMount\nmounted\nbeforeUpdate\nupdated\nbeforeDestroy\ndestroyed\n```\n\n## Using a single slot\n\nComponent template `MyComponent`:\n\n```html\n<div>\n  <h2>I'm a title</h2>\n  <slot>\n    Only displayed if no slot content\n  </slot>\n</div>\n```\n\nUse of `MyComponent` with custom data for the slot:\n\n```html\n<my-component>\n  <p>This will go in the slot</p>\n</my-component>\n```\n\n## Multiple slots\n\nComponent `AppLayout` template:\n\n```html\n<div class=\"container\">\n  <header>\n    <slot name=\"header\"></slot>\n  </header>\n  <main>\n    <slot>Default content</slot>\n  </main>\n  <footer>\n    <slot name=\"footer\"></slot>\n  </footer>\n</div>\n```\n\nUse of `AppLayout` with custom data for the slots:\n\n```html\n<app-layout>\n  <h1 slot=\"header\">Page title</h1>\n  <p>The main content</p>\n  <p slot=\"footer\">Contact info</p>\n</app-layout>\n```\n\n## Libraries you should know\n\n**[Vue CLI](https://router.vuejs.org)**\n\nCommand line interface for rapid Vue development.\n\n**[Vue Router](https://router.vuejs.org)**\n\nNavigation for a Single-Page Application.\n\n**[Vue DevTools](https://github.com/vuejs/vue-devtools)**\n\nBrowser extension for debugging Vue applications.\n\n**[Nuxt.js](https://nuxtjs.org)**\n\nLibrary for server side rendering, code-splitting, hot-reloading, static generation and more.\n\n# Tips\n\n### 1. Nested objects are NOT reactive (by default)\n\n```vue\n<script>\n  export default {\n    data () {\n      return {\n        someVar: ''\n      }\n    },\n    mounted () {\n      this.someVar: {\n        level1: {\n          level2: {\n            level3: 'something old'\n          }\n        }\n      }\n    },\n    methods : {\n      changeSomeVar () {\n        this.someVar.level1.level2.level3 = 'something new'\n      }\n    }\n  }\n</script>\n```\n\nThat method looks like it should work, say you have an input that matches `someVar.level1.level2.level3`, if you ran this method it would not update the model. Instead you need to use `Vue.set` or in a SPC (Single Page Component) you'd just use `this.$set`:\n\n```vue\n<script>\n  export default {\n    // ...\n    methods : {\n      changeSomeVar () {\n        this.$set(this.someVar.level1.level2, 'level3', 'new value here')\n      }\n    }\n  }\n</script>\n```\n\n### 2. Learn and use Vuex from the start\n\nThis could start a flame war, some Vue fan will tell you to start with an event bus and work your way up, but Vuex is modular enough that you can use it on small and large apps alike. If you're building a SPA there's no chance you'll have fun without Vuex, you're going to implement a lot of the same functionality in your event bus, and making any other developer who works on the project's life a living hell.\n\nA good primer on vuex can be found here: [WTF is Vuex? A Beginner’s Guide To Vue’s Application Data Store](https://vuejsdevelopers.com/2017/05/15/vue-js-what-is-vuex/)\n\n### 3. When in doubt, re-render\n\nHere's a simple use case, say you have an order form that pops up. If for some reason the user closes the order form and reopens it you might find some of the fields won't allow edits, or they have stale data, or if you're triggering the popup via a select box it might not work right. Honestly it's a major headache.\n\nOne trick is to re-render your components. The easiest method I've found to do that is whenever a modal or some other component is registered on the DOM pass it a key, or on mount make it generate a random one. A good key could just be to use `Date.now()` or `moment.js` to generate a UTC timestamps and use that.\n\nThe key tells Vue that this is a NEW instance, forget about the old one, and let's start over.\n\n### 4. Learn the difference between props and data\n\nEssentially a prop is data that you pass INTO the component from a parent component or on initializing the root component for the first time.\n\nData is the reactive properties defined on the instance. I find it to be a good practice if you ever think you'll need to update the value or use it re-actively to create a new value on mount that is a duplicate of the prop. So say you have a prop called `colorProp`, you might have a value in data called just `color`, then in your `mounted()` method have `this.color` set to `colorProp`.\n\n### 5. Have a plan for loading elements\n\nYou may start out just letting users wait without knowing what's going on but this is going to get dirty fast. Especially when you bring Vuex and multiple data points into the mix. It's best to have a single global **loader** setup that triggers whenever the global **loading** property from Vuex is updated. This way you can always toggle it properly and make sure to un-toggle it.\n\nOne caveat is though - be sure you catch all errors - especially when using axios and promises and be sure to end the loading message on errors so users can go back, fix things and resubmit the form.\n\n### 6. Make common filters global\n\nThe example below is a bad example on how you should be using filters:\n\n```vue\n<template>\n  <div>\n    <!-- Bad idea -->\n    <input type=\"text\" ..> ${{ moneyVar | money }}\n  </div>\n</template>\n\n<script>\n  export default {\n    data() { \n      moneyVar: 3.50\n    },\n    filters: {\n      money: function (value) {\n        if (!value) {\n          return '0.00'\n        }\n        return '$' + parseFloat(value).toFixed(2)\n      }\n    }\n  }\n</script>\n```\n\nWe should make it a global filter:\n\n```vue\n<script>\n  Vue.filter('money', function (value) {\n    if (!value) {\n      return '0.00'\n    }\n    return '$' + parseFloat(value).toFixed(2)\n  })\n</script>\n```\n\n# Contribution\n\n- Report issues\n- Open pull request with improvements\n- Spread the word\n- Reach out to me directly at <mauriurraco@gmail.com>\n\n# Buy me a coffee to show your support!\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/murraco)\n"
  }
]