Skip to content

Latest commit

 

History

History

lab12

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Lab 12 - Filters and mixins

  1. Run yarn && yarn serve inside this folder.

  2. In your IDE, open the src folder and explore the code.

  3. Have you noticed how sometimes the total price in the shopping cart looks like CHF 115.05000000000001?

    In javascript all numbers are stored as floating point numbers and the arithmetic is known to not always be accurate.

    It would be great if we could instruct Vue.js to treat some numbers as currencies, round and format them correspondingly.

    The actual formatting is easily done with the Internationalization API:

    new Intl.NumberFormat('en-us', { style: 'currency', currency: 'CHF' }).format(123.456789); // will result in CHF 123.45
  4. Let's create a global price filter, that does exactly that and use it every component, that displays prices.

    Hint

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    Vue.config.productionTip = false
    
    Vue.filter('price', (value) => {
      return new Intl.NumberFormat('en-us', { style: 'currency', currency: 'CHF' }).format(value);
    })
    
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')

    Cocktail.vue

    <template>
      ....
      <button
        v-if="ingredient.price"
        @click="orderIngredient(ingredient)"
        :class="$style.button">
        Buy for {{ ingredient.price | price }}
      </button>
     ....
    </template>

    ShoppingCart.vue

    <template>
        ....
        <p>
          Subtotal: CHF {{ subtotal | price }}<br />
          Delivery fee: CHF {{ deliveryFee | price }}<br />
          Total: CHF {{ total | price }}
        </p>
        ....
    </template>

    ShoppingCartItem.vue

    <template>
      ....
      <div>
        <strong>{{ title }}</strong> <br />
        {{ price | price }} <br />
        Qty: {{ quantity }}
      </div>
      ....
    </template>
  5. Now let's imagine our shop becomes available in different countries and has to display prices in different currencies. We will not be able to hardcode CHF or the en-us locale in the filter anymore. We can store the currency value in the Vuex store and pass it to the filter as a parameter. Let's adjust just the Cocktail component so far.

    Hint

    store.js

    ....
    export default new Vuex.Store({
      state: {
        error: undefined,
        allRecipes: [],
        shoppingCartItems: {},
        favoriteCocktails: [],
        currency: 'CHF',
        locale: 'en-us'
      },
      ....
    })

    main.js

    ....
    Vue.filter('price', (value, locale, currency) => {
      return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value);
    })
    ....

    Cocktail.vue

    <template>
      ....
      <button
        v-if="ingredient.price"
        @click="orderIngredient(ingredient)"
        :class="$style.button">
        Buy for {{ ingredient.price | price(locale, currency) }}
      </button>
      ....
    </template>
    
    <script>
      ....
      export default {
        ....
        computed: {
          currency() {
            return this.$store.state.currency;
          },
          locale() {
            return this.$store.state.locale;
          }
        },
        ....
      };
    </script>
  6. An error happens now when we open Shopping Cart - we are not passing locale and currency parameters to our price filter there. In order not to re-create computed properties in every component we need, let's:

    • declare a localizationMixin mixin in a separate file
    • import it into those components, that use price filter
    • make sure we pass locale and currency parameters everywhere we use price filter
    Hint

    localizationMixin.js

    export default {
      computed: {
        currency() {
          return this.$store.state.currency;
        },
        locale() {
          return this.$store.state.locale;
        }
      }
    }

    Cocktail.vue (and other components using price filter)

    <script>
      ....
      import localizationMixin from '@/localizationMixin';
    
      export default {
        mixins: [localizationMixin],
        ....
      };
    </script>
  7. Now let's go to the store.js and switch locale to 'de-DE' and currency to 'EUR' to verify that our logic works. The price formatting should change from CHF 38.35 to 38,35 €.