Navigation

    Quasar Framework

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    1. Home
    2. benoitranque
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    benoitranque

    @benoitranque

    94
    Reputation
    351
    Posts
    1641
    Profile views
    5
    Followers
    0
    Following
    Joined Last Online
    Location Santa Cruz, Bolivia Age 25

    benoitranque Follow

    Best posts made by benoitranque

    • [How to] load external dependencies (CDN) ASYNC

      The Problem

      So recently I came upon a problem: I needed to use Google Map API

      The Google Maps API cannot be simply included as a NPM dependency, and you need a key to use it

      Of course I could request it in src/index.html like so

      
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <meta name="format-detection" content="telephone=no">
          <meta name="msapplication-tap-highlight" content="no">
          <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
      
          <title>My awesome page</title>
          <link rel="icon" href="statics/img/favicon.ico" type="image/x-icon">
        </head>
        <body>
          <div id="q-app"></div>
          <!-- built files will be auto injected -->
      
          <script src="https://maps.googleapis.com/maps/api/js?key=xxxxxxx">
      
        </body>
      </html>
      
      

      This is not ideal

      Say you have a large web app. You will load the google maps api on first load. Even if you only use it in one page of your SPA. This means clients download a library they may not need at a moment they definitely dont need it.

      So add the deffer atribute

      
         <script deffer src="https://maps.googleapis.com/maps/api/js?key=xxxxxxx">
      
      

      This is better

      This means the loading of this library is done last. However clients still download it whether they need it or not.

      Still not ideal

      Ideally we want the api to load when needed, if it is not in memory yet. How do we do this? Using this script:

      // src/externalApi.js
      
      let api = {}
      export default {
        config: function configApi (id, url) {
          if (!api[id]) {
            api[id] = {
              config: {
                id,
                url
              }
            }
          }
          else {
            // atempted creating same api multiple times
            // error code goes here
            console.error(`Atempted to create API ${id} multiple times`)
          }
        },
        load: function loadApi (id) {
          if (api[id]) {
            if (!api[id].promise {
              if (!document.getElementById(api[id].config.id)) {
                api[id].promise = new Promise((resolve, reject) => {
                  let script = document.createElement('script')
                  script.src = api[id].config.url
                  script.async = true
                  script.id = api[id].config.id
                  script.onload = () => {
                    resolve()
                  }
                  script.onerror = (err) => {
                    reject(err)
                    // not sure about this part. ESLint wants error to be passed, not sure if doing it properly
                  }
                  document.body.appendChild(script)
                })
              }
              else {
                // atempted to create api but id already exists
                // error code
               console.error(`Make sure the id ${id} is unique and is not used anywhere else in your app.`)
              }
            })
            return api[id].promise
          }
          else {
            // api has not been configured
            // error
            console.error(`API ${id} does not exist. Have you configured it in main.js?`)
          }
        }
      }
      
      

      What this does

      This allows us to configure our api in main.js, but load it only once requested. If the api has already been loaded, it will not be loaded again.

      Usage:

      
      // main.js
      import externalApi from '~src/externalApi'
      
      externalApi.config('google-api', 'https://maps.googleapis.com/maps/api/js?key=xxxxxxxxxxxxxxxxxxx')
      
      // some component or view
      import { externalApi } from 'quasar'
      
      ...
      externalApi.load('google-api')
      .then(() => {
        console.log('google api is loaded')
      })
      ...
      // allternative
      
      mounted: async function () {
        await externalApi.load()
        console.log('api now loaded')
      }
      
      

      Hope this helps!

      posted in Show & Tell
      benoitranque
      benoitranque
    • RE: Questions about layout

      regarding the view code:

      // split your screen in 9 pieces
      
      X   X   X
      X   X   X
      X   X   X
      
      // the center is the page content
      
      
      X   X   X
      X   p   X
      X   X   X
      
      // top is header, bottom is footer
      
      
      X   h   X
      X   p   X
      X   f   X
      
      // left and right drawers
      
      
      X   h   X
      l   p   r
      X   f   X
      
      // who gets the corners?
      // in this case both top corners go to header, bottom corners to respective drawer
      
      h    h   h
      l    p   r
      l    f   r
      
      // finally scrolling. using an upper case letter will
      // for header/footer make them non scrolling. They will be fixed while page content scrolls
      // drawers: they get their own scroll, not shared with page scroll
      
      // I want my header fixed to the top, and both drawers to have their own scroll. 
      // My footer should stay at the bottom, and only appear once the whole page has been scrolled down
      
      // result
      
      H  H  H
      L  p  R
      L  f  R
      
      // finally place those in one line, slicing the block horizontally:
      
      view="HHH LpR LfR"
      
      // I hope this helps
      
      ```
      posted in Help
      benoitranque
      benoitranque
    • [How to] load all files in a directory as views

      Hello

      This script will allow you to load all files in a directory as views. This allows you to avoid registering all views manually, rather you configure once then simply start adding pages!

      // router.js
      
      // returns all vue files in directory 'page'
      const pages = require.context('./components/page', true, /^\.\/.*\.vue$/)
        .keys()
        .filter(page => page.split('/').length >= 2)
        .map(page => page.slice(2).slice(0, -4))
      
      // Standard quasar load function. Only load view once needed
      function load (component) {
        // '@' is aliased to src/components
        return () => System.import(`@/${component}.vue`)
      }
      
      // page loading function 
      function loadPage (page) {
        return {
          path: `/${page}`,
          component: load(`page/${page}`)
        }
      }
      
      // Add first route with layout
      let routes = [
        {
          path: '/',
          component: load('Layout'),
          children: []
        }
      ]
      
      // Add all other pages
      pages.forEach(page => {
        routes[0].children.push(loadPage(page))
      })
      
      // Standard quasar default will redirect to '/404' route
      // Always leave this last one
      routes.push({ path: '*', redirect: '/404' }) // Not found
      
      

      You are all set! With this any .vue file you add in src/components/page/ will be added as a view.

      Of course this has limitations. Your files names must not have spaces. If anyone is interested I could show you how to extract a title for your page from the filename.

      Have a nice day!

      posted in Show & Tell
      benoitranque
      benoitranque
    • RE: Use Plugin inside Vuex module action

      You could also use this._vm.$axios …

      posted in Help
      benoitranque
      benoitranque
    • RE: Environment detection in v0.15

      fairly sure it’s

      if (process.env.DEV) {}
      
      posted in Framework
      benoitranque
      benoitranque
    • RE: Pass data to touch hold handler

      bit late but here you go

      https://codepen.io/anon/pen/ZVgZNz

      posted in Help
      benoitranque
      benoitranque
    • RE: v0.15 news

      End of month is still the schedule… (fingers crossed)

      posted in Announcements
      benoitranque
      benoitranque
    • [how to] Implement i18next in quasar

      Hello all

      I recently implemented i18next in my Quasar project.
      Here I will try to show you all how it was done.

      My use case

      The project is a multi language static site.
      I have a simple button with a popover to select languages.
      My language files go in ‘/src/statics/i18n/’ folder.
      I am using these packages: i18next, vue-i18next, i18next-xhr-backend

      Getting started

      Install basic packages
        $  npm install --save i18next  @panter/vue-i18next
      

      This will install the core i18next library, as well as the vue-i18next plugin.

      Boot up i18next

      
      // src/main.js
      
      // import libraries
      import i18next from 'i18next'
      import VueI18Next from '@panter/vue-i18next'
      
      ....
      
      // init i18next
      i18next
        .init({
          debug: false, // set this to true for now. Will give som interesting output in console
          lng: 'en', // default language
          resources: {  // fixed resources for now. may be useful to keep critical messages here. 
            en: { // language
              translations: { // Namespace. Default namespace is 'translations'
                key: 'value'  // your translations go here.
              }
            }
          }
        }, (err, t) => {
          if (DEV && err) {
            // if there is an error on init, log it
            console.log(err)
          }
        })
      
      // plug Vuei18Next into Vue,
      Vue.use(VueI18Next)
      // use your instace of i18next with vue
      const i18n = new VueI18Next(i18next)
      
      // init quasar 
      Quasar.start(() => {
        /* eslint-disable no-new */
        new Vue({
          el: '#q-app',
          i18n, // pass i18n: i18n
          .....
          // other arguments here as usual
        })
      })
      

      With this, you should be set up. try the following in any .vue component

      {{$t('key')}}
      

      If everything is working, this should render as ‘value’. Try adding a few more.

      Changing language

      First update your main.js i18next resources to look like so to look like so

      
          resources: {
            en: {
              translations: {
                hello: 'Hello World!' 
              }
            },
            es: {
              translations: {
                hello: 'Hola Mundo!' 
              }
            },
            fr: {
              translations: {
                hello: 'Bonjour Monde!' 
              }
            }
          }
      
      

      Now add {{$t('hello)}} in a .vue component.

      You should be able to change language with the following:

      
      changeLanguage (lng) {
        // where lng is one of 'es', 'fr', 'en'
        this.$i18n.i18next.changeLanguage(lng)
      }
      
      

      Accessing the current language

      This can be useful for choosing an icon representing the current language.

      
        this.$i18n.i18next.language 
      
      

      Using a xHR backend

      Having all your language data in main.js only works for the smallest of apps.
      Here is a way to pull language data from static .json files

      Add the following files

      /src/statics/i18n/en/translations.json

      {
        "hello": "Hello from backend"
      }
      

      /src/statics/i18n/es/translations.json

      {
        "hello": "Hola desde statics"
      }
      
      Install the XHR backend
        $  npm install --save i18next-xhr-backend
      

      src/main.js

      
      import i18next from 'i18next'
      import VueI18Next from '@panter/vue-i18next'
      import XHR from 'i18next-xhr-backend' // import xhr backend
      
      ....
      
      i18next
        .use(XHR) // Add  xhr backend to i18next 
        .init({
          debug: true,
          lng: 'en',
          ns: 'translations',
          backend: { // backend config
            loadPath: '/statics/i18n/{{lng}}/{{ns}}.json', // load path based on language and namespaces
            parse: data => JSON.parse(data) // parse data
          }
        }, (err, t) => {
          if (DEV && err) {
            console.log(err)
          }
        })
      
      

      This should set up the backend.

      Additional configuration options

      
      import i18next from 'i18next'
      import VueI18Next from '@panter/vue-i18next'
      import XHR from 'i18next-xhr-backend' // import xhr backend
      
      ....
      
      i18next
        .use(XHR)
        .init({
          debug: true,
          returnObjects: true, // this is very useful if you want translations to return an array on which you can use v-for
          lng: 'en',
          fallbackLng: 'en', // language to fallback to if current language is unavailable 
          ns: 'translations',
          defaultNS: 'translations',
          fallbackNS: 'translations' //  namespace to fallback to if current namespace is unavailable 
          backend: { // add backend
            loadPath: '/statics/i18n/{{lng}}/{{ns}}.json', // load path based on namespaces and language
            parse: data => JSON.parse(data) // parse data
          }
        }, (err, t) => {
          if (DEV && err) {
            console.log(err)
          }
        })
      
      

      And now in any .vue file, configure local namespaces for said file

      export default {
        .....
        i18nOptions: {
          namespaces: 'translations' // either string or array of strings. The corresponding files will be loaded
        }
        .....
      }
      
      Hope this helped

      I’m tired now. Will edit later. Please post if you spot any mistakes. Thanks you

      posted in Show & Tell
      benoitranque
      benoitranque
    • RE: v0.14 beta - route tabs - default

      Check out the bottom of this page in the vue-router docs
      basically set a default path using

      {path: '', redirect: '/path/to/default' }
      

      note the use of redirect to avoid duplicating component load

      posted in Help
      benoitranque
      benoitranque
    • RE: Q select (dynamic values for option)

      To expand on what @Max said:

      <template>
        <div>
          <q-select v-model="value" :options="options"></q-select>
        </div>
      </template>
      
      <script>
        import { QSelect } from 'quasar'
        export default {
          components: {
            QSelect
          },
          data() {
            return {
              options: [],
              value: ''
            }
          },
          mounted () {
            this.$http.get('/Route')
              .then(response => {
                this.options = response.data
              })
          }
        }
      </script>
      
      posted in Framework
      benoitranque
      benoitranque

    Latest posts made by benoitranque

    • RE: Pass data to touch hold handler

      bit late but here you go

      https://codepen.io/anon/pen/ZVgZNz

      posted in Help
      benoitranque
      benoitranque
    • RE: How can I put the "Drawer" between the header and the footer (toolbars), opening and closing between them?

      Sure. Take a look at the view prop of q-layout

      You would set view="HHH LpR fff" for example. Also take a look at the overlay prop of q-layout-drawer

      posted in Help
      benoitranque
      benoitranque
    • RE: Async code in App Plugins

      @zmilan just make sure you read the corresponding docs. The boot plugin is special

      posted in Help
      benoitranque
      benoitranque
    • RE: Adding a button to a cell within a datatable

      if you are not using the body slot, you can target a specific cell using slot="body-cell-{column-name}" where column-name is the the name of one of the columns in your column definition.

      posted in Framework
      benoitranque
      benoitranque
    • RE: Printing in an electron dev
      const { remote } = require('electron')
      
      remote.getCurrentWebContents().print()
      
      posted in Help
      benoitranque
      benoitranque
    • RE: [0.14] print css

      I’m sure you’ve seen this

      posted in Framework
      benoitranque
      benoitranque
    • RE: Upgrade Old Project

      You can migrate your old project: create a new project and move things carefully, one by one to the new project.
      To run the last compatible quasar-cli on older project see the docs

      posted in Help
      benoitranque
      benoitranque
    • RE: <q-input /> with float-label has no margin or padding top

      Working as intended. If you want padding add it yourself

      posted in Framework
      benoitranque
      benoitranque
    • RE: Dependency was not found using a npm package

      you should be using ES6 import instead of require

      posted in Help
      benoitranque
      benoitranque
    • RE: Using plugin quasar/vue in Vuex

      No I do not. Try this here, dispatch that action from a vue component

      posted in Help
      benoitranque
      benoitranque