├── .babelrc ├── .gitignore ├── .npmignore ├── test ├── helpers │ ├── webpack.config.test.js │ ├── setup.js │ └── google_stub.js └── index.test.js ├── example └── src │ ├── app.js │ └── index.html ├── LICENSE.md ├── package.json ├── webpack.mix.js ├── .all-contributorsrc ├── webpack.config.js ├── src └── VueGoogleAutocomplete.vue └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | mix-manifest.json 4 | example/dist -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | webpack.config.js 3 | webpack.mix.js 4 | /test 5 | /.github -------------------------------------------------------------------------------- /test/helpers/webpack.config.test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | module: { 3 | rules: [{ 4 | use: 'vue-loader', 5 | }], 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /test/helpers/setup.js: -------------------------------------------------------------------------------- 1 | const browserEnv = require('browser-env'); 2 | const { join } = require('path'); 3 | const hook = require('vue-node'); 4 | 5 | browserEnv(); 6 | hook(join(__dirname, 'webpack.config.test.js')); 7 | -------------------------------------------------------------------------------- /test/helpers/google_stub.js: -------------------------------------------------------------------------------- 1 | export default function googleStub() { 2 | const google = { 3 | maps: { 4 | places: { 5 | Autocomplete: function () { 6 | return { 7 | addListener: function () { } 8 | } 9 | }, 10 | Geocoder: function () { 11 | return { 12 | geocode: function () { } 13 | } 14 | } 15 | }, 16 | } 17 | }; 18 | 19 | return google; 20 | } 21 | -------------------------------------------------------------------------------- /example/src/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueGoogleAutocomplete from './../../src/VueGoogleAutocomplete.vue'; 3 | 4 | const app = new Vue({ 5 | el: '#app', 6 | 7 | components: { VueGoogleAutocomplete }, 8 | 9 | data: { 10 | address: '' 11 | }, 12 | 13 | methods: { 14 | /** 15 | * When the location found 16 | * @param {Object} addressData Data of the found location 17 | * @param {Object} placeResultData PlaceResult object 18 | * @param {String} id Input container ID 19 | */ 20 | getAddressData(addressData, placeResultData, id) { 21 | this.address = addressData; 22 | }, 23 | 24 | handleError(error) { 25 | alert(error) 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Dmitriy Olefyrenko 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import test from 'ava'; 3 | import googleStub from './helpers/google_stub'; 4 | import VueGoogleAutocomplete from '../src/VueGoogleAutocomplete.vue'; 5 | 6 | window.google = global.google = googleStub(); 7 | 8 | test('that it has a mounted hook', t => { 9 | t.is(typeof VueGoogleAutocomplete.mounted, 'function'); 10 | }); 11 | 12 | test('that it renders input', t => { 13 | let Constructor = Vue.extend(VueGoogleAutocomplete); 14 | 15 | let vm = new Constructor({ propsData: { 16 | 'id': 'map' 17 | }}).$mount(); 18 | 19 | t.is(vm.$el.nodeName, 'INPUT'); 20 | t.is(vm.$el.type, 'text'); 21 | }); 22 | 23 | test('that it renders proper props', t => { 24 | let Constructor = Vue.extend(VueGoogleAutocomplete); 25 | 26 | let vm = new Constructor({ propsData: { 27 | 'id': 'map', 28 | 'classname': 'form-control', 29 | 'placeholder': "Start typing" 30 | }}).$mount(); 31 | 32 | t.is(vm.$el.placeholder, "Start typing"); 33 | t.is(vm.$el.className, 'form-control'); 34 | t.is(vm.$el.id, 'map'); 35 | t.is(vm.$el.disabled, false); 36 | 37 | let vm2 = new Constructor({ propsData: { 38 | 'id': 'map2', 39 | 'disabled': true 40 | }}).$mount(); 41 | 42 | t.is(vm2.$el.disabled, true); 43 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-google-autocomplete", 3 | "version": "1.1.4", 4 | "description": "Vue component to Google Places Autocomplete", 5 | "main": "src/VueGoogleAutocomplete.vue", 6 | "homepage": "https://github.com/olefirenko/vue-google-autocomplete", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/olefirenko/vue-google-autocomplete.git" 10 | }, 11 | "peerDependencies": { 12 | "vue": ">=2" 13 | }, 14 | "keywords": [ 15 | "vue", 16 | "google", 17 | "autocomplete" 18 | ], 19 | "scripts": { 20 | "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules", 21 | "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules", 22 | "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot", 23 | "production": "cross-env NODE_ENV=production webpack --progress --hide-modules", 24 | "deploy:example": "gh-pages -d example/dist", 25 | "test": "NODE_PATH=test ava --verbose" 26 | }, 27 | "ava": { 28 | "require": [ 29 | "babel-register", 30 | "./test/helpers/setup.js" 31 | ] 32 | }, 33 | "author": "Dmytro Olefyrenko ", 34 | "license": "MIT", 35 | "devDependencies": { 36 | "all-contributors-cli": "^6.20.0", 37 | "ava": "^0.18.2", 38 | "babel-register": "^6.24.0", 39 | "browser-env": "^2.0.25", 40 | "cross-env": "^3.2.4", 41 | "gh-pages": "^0.12.0", 42 | "laravel-mix": "^0.8.8", 43 | "vue": "^2.2.1", 44 | "vue-node": "^1.0.2", 45 | "webpack": "^2.3.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for your application, as well as bundling up your JS files. 11 | | 12 | */ 13 | 14 | mix.js('example/src/app.js', 'example/dist/'); 15 | 16 | // Full API 17 | // mix.js(src, output); 18 | // mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation. 19 | // mix.extract(vendorLibs); 20 | // mix.sass(src, output); 21 | // mix.less(src, output); 22 | // mix.stylus(src, output); 23 | // mix.browserSync('my-site.dev'); 24 | // mix.combine(files, destination); 25 | // mix.babel(files, destination); <-- Identical to mix.combine(), but also includes Babel compilation. 26 | // mix.copy(from, to); 27 | // mix.minify(file); 28 | // mix.sourceMaps(); // Enable sourcemaps 29 | // mix.version(); // Enable versioning. 30 | // mix.disableNotifications(); 31 | // mix.setPublicPath('path/to/public'); 32 | // mix.setResourceRoot('prefix/for/resource/locators'); 33 | // mix.autoload({}); <-- Will be passed to Webpack's ProvidePlugin. 34 | // mix.webpackConfig({}); <-- Override webpack.config.js, without editing the file directly. 35 | // mix.then(function () {}) <-- Will be triggered each time Webpack finishes building. 36 | // mix.options({ 37 | // extractVueStyles: false, // Extract .vue component styling to file, rather than inline. 38 | // processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched. 39 | // uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 40 | // postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md 41 | // }); 42 | -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 |
12 |

Vue Google Autocomplete

13 |

A Vue.js autosuggest component for the Google Maps Places API

14 |
15 |
16 |
17 | 18 |
19 |
20 |
21 |

Start typing an address and below you will see found result, 22 | or force current location 23 |

24 |

25 | 34 | 35 |

36 | 37 |
38 |
{{ address }}
39 |
40 |
41 |
42 |
43 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "olefirenko", 10 | "name": "Dmytro Olefyrenko", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/5434459?v=4", 12 | "profile": "https://olefyrenko.com/", 13 | "contributions": [ 14 | "code" 15 | ] 16 | }, 17 | { 18 | "login": "daryledesilva", 19 | "name": "Daryle Dale De Silva", 20 | "avatar_url": "https://avatars.githubusercontent.com/u/4393436?v=4", 21 | "profile": "http://www.daryledesilva.com/", 22 | "contributions": [ 23 | "code" 24 | ] 25 | }, 26 | { 27 | "login": "DjilanoS", 28 | "name": "DjilanoS", 29 | "avatar_url": "https://avatars.githubusercontent.com/u/84568557?v=4", 30 | "profile": "https://github.com/DjilanoS", 31 | "contributions": [ 32 | "maintenance" 33 | ] 34 | }, 35 | { 36 | "login": "juanvillegas", 37 | "name": "Juan Villegas", 38 | "avatar_url": "https://avatars.githubusercontent.com/u/773149?v=4", 39 | "profile": "https://github.com/juanvillegas", 40 | "contributions": [ 41 | "code" 42 | ] 43 | }, 44 | { 45 | "login": "hughsaffar", 46 | "name": "Hugh Saffar", 47 | "avatar_url": "https://avatars.githubusercontent.com/u/10440022?v=4", 48 | "profile": "https://houmaan.dev/", 49 | "contributions": [ 50 | "code" 51 | ] 52 | }, 53 | { 54 | "login": "liliumdev", 55 | "name": "Ahmed", 56 | "avatar_url": "https://avatars.githubusercontent.com/u/8971846?v=4", 57 | "profile": "https://www.lilium.dev/", 58 | "contributions": [ 59 | "code" 60 | ] 61 | }, 62 | { 63 | "login": "ankurk91", 64 | "name": "Ankur Kumar", 65 | "avatar_url": "https://avatars.githubusercontent.com/u/6111524?v=4", 66 | "profile": "https://ankurk91.github.io/", 67 | "contributions": [ 68 | "code" 69 | ] 70 | }, 71 | { 72 | "login": "ArturGrigio", 73 | "name": "Artur Grigio", 74 | "avatar_url": "https://avatars.githubusercontent.com/u/6424589?v=4", 75 | "profile": "https://github.com/ArturGrigio", 76 | "contributions": [ 77 | "code" 78 | ] 79 | }, 80 | { 81 | "login": "bhrutledge", 82 | "name": "Brian Rutledge", 83 | "avatar_url": "https://avatars.githubusercontent.com/u/1326704?v=4", 84 | "profile": "https://bhrutledge.com/", 85 | "contributions": [ 86 | "code" 87 | ] 88 | }, 89 | { 90 | "login": "bryanjamesmiller", 91 | "name": "Bryan Miller", 92 | "avatar_url": "https://avatars.githubusercontent.com/u/8781182?v=4", 93 | "profile": "https://github.com/bryanjamesmiller", 94 | "contributions": [ 95 | "code" 96 | ] 97 | }, 98 | { 99 | "login": "cgs", 100 | "name": "Chris Sepic", 101 | "avatar_url": "https://avatars.githubusercontent.com/u/16057?v=4", 102 | "profile": "https://github.com/cgs", 103 | "contributions": [ 104 | "code" 105 | ] 106 | }, 107 | { 108 | "login": "mrgix", 109 | "name": "Dennis van Breukelen", 110 | "avatar_url": "https://avatars.githubusercontent.com/u/6233470?v=4", 111 | "profile": "https://github.com/mrgix", 112 | "contributions": [ 113 | "code" 114 | ] 115 | }, 116 | { 117 | "login": "Eoksni", 118 | "name": "Dmitry Mazurok", 119 | "avatar_url": "https://avatars.githubusercontent.com/u/2010503?v=4", 120 | "profile": "https://github.com/Eoksni", 121 | "contributions": [ 122 | "code" 123 | ] 124 | }, 125 | { 126 | "login": "julianfox", 127 | "name": "Julian Renard", 128 | "avatar_url": "https://avatars.githubusercontent.com/u/1648714?v=4", 129 | "profile": "https://github.com/julianfox", 130 | "contributions": [ 131 | "code" 132 | ] 133 | }, 134 | { 135 | "login": "leonardoarroyo", 136 | "name": "Leonardo Arroyo", 137 | "avatar_url": "https://avatars.githubusercontent.com/u/4290407?v=4", 138 | "profile": "http://leonardoarroyo.com/", 139 | "contributions": [ 140 | "code" 141 | ] 142 | }, 143 | { 144 | "login": "probil", 145 | "name": "Max Lyashuk", 146 | "avatar_url": "https://avatars.githubusercontent.com/u/6773202?v=4", 147 | "profile": "https://probil.github.io/", 148 | "contributions": [ 149 | "code" 150 | ] 151 | }, 152 | { 153 | "login": "mgibowski", 154 | "name": "Michał Gibowski", 155 | "avatar_url": "https://avatars.githubusercontent.com/u/617315?v=4", 156 | "profile": "https://mgibowski.dev/", 157 | "contributions": [ 158 | "code" 159 | ] 160 | }, 161 | { 162 | "login": "mickeyschwab", 163 | "name": "Mickey Schwab", 164 | "avatar_url": "https://avatars.githubusercontent.com/u/2643491?v=4", 165 | "profile": "https://mickeyschwab.com/", 166 | "contributions": [ 167 | "code" 168 | ] 169 | }, 170 | { 171 | "login": "rleger", 172 | "name": "Romain Léger", 173 | "avatar_url": "https://avatars.githubusercontent.com/u/3156035?v=4", 174 | "profile": "http://www.lelaboratoiredeco.fr/", 175 | "contributions": [ 176 | "code" 177 | ] 178 | }, 179 | { 180 | "login": "skmbr", 181 | "name": "Simon Kimber", 182 | "avatar_url": "https://avatars.githubusercontent.com/u/1945312?v=4", 183 | "profile": "https://skmbr.uk/", 184 | "contributions": [ 185 | "code" 186 | ] 187 | }, 188 | { 189 | "login": "syffs", 190 | "name": "syffs", 191 | "avatar_url": "https://avatars.githubusercontent.com/u/4192037?v=4", 192 | "profile": "https://github.com/syffs", 193 | "contributions": [ 194 | "code" 195 | ] 196 | }, 197 | { 198 | "login": "yannbertrand", 199 | "name": "Yann Bertrand", 200 | "avatar_url": "https://avatars.githubusercontent.com/u/5855339?v=4", 201 | "profile": "http://yann-bertrand.fr/", 202 | "contributions": [ 203 | "code" 204 | ] 205 | }, 206 | { 207 | "login": "ciaasteczkowy", 208 | "name": "ciaasteczkowy", 209 | "avatar_url": "https://avatars.githubusercontent.com/u/509463?v=4", 210 | "profile": "https://github.com/ciaasteczkowy", 211 | "contributions": [ 212 | "code" 213 | ] 214 | }, 215 | { 216 | "login": "crabaux", 217 | "name": "crabaux", 218 | "avatar_url": "https://avatars.githubusercontent.com/u/7647886?v=4", 219 | "profile": "https://www.linkedin.com/in/cyril-rabaux-90141a82/", 220 | "contributions": [ 221 | "code" 222 | ] 223 | } 224 | ], 225 | "contributorsPerLine": 7, 226 | "projectName": "vue-google-autocomplete", 227 | "projectOwner": "olefirenko", 228 | "repoType": "github", 229 | "repoHost": "https://github.com", 230 | "skipCi": true, 231 | "commitConvention": "none" 232 | } 233 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let webpack = require('webpack'); 3 | let Mix = require('laravel-mix').config; 4 | let plugins = require('laravel-mix').plugins; 5 | 6 | 7 | /* 8 | |-------------------------------------------------------------------------- 9 | | Mix Initialization 10 | |-------------------------------------------------------------------------- 11 | | 12 | | As our first step, we'll require the project's Laravel Mix file 13 | | and record the user's requested compilation and build steps. 14 | | Once those steps have been recorded, we may get to work. 15 | | 16 | */ 17 | 18 | Mix.initialize(); 19 | 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Webpack Context 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This prop will determine the appropriate context, when running Webpack. 27 | | Since you have the option of publishing this webpack.config.js file 28 | | to your project root, we will dynamically set the path for you. 29 | | 30 | */ 31 | 32 | module.exports.context = Mix.Paths.root(); 33 | 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Webpack Entry 38 | |-------------------------------------------------------------------------- 39 | | 40 | | We'll first specify the entry point for Webpack. By default, we'll 41 | | assume a single bundled file, but you may call Mix.extract() 42 | | to make a separate bundle specifically for vendor libraries. 43 | | 44 | */ 45 | 46 | module.exports.entry = Mix.entry(); 47 | 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Webpack Output 52 | |-------------------------------------------------------------------------- 53 | | 54 | | Webpack naturally requires us to specify our desired output path and 55 | | file name. We'll simply echo what you passed to with Mix.js(). 56 | | Note that, for Mix.version(), we'll properly hash the file. 57 | | 58 | */ 59 | 60 | module.exports.output = Mix.output(); 61 | 62 | 63 | /* 64 | |-------------------------------------------------------------------------- 65 | | Rules 66 | |-------------------------------------------------------------------------- 67 | | 68 | | Webpack rules allow us to register any number of loaders and options. 69 | | Out of the box, we'll provide a handful to get you up and running 70 | | as quickly as possible, though feel free to add to this list. 71 | | 72 | */ 73 | 74 | let vueExtractTextPlugin = false; 75 | 76 | if (Mix.options.extractVueStyles) { 77 | vueExtractTextPlugin = Mix.vueExtractTextPlugin(); 78 | 79 | module.exports.plugins = (module.exports.plugins || []).concat(vueExtractTextPlugin); 80 | } 81 | 82 | 83 | module.exports.module = { 84 | rules: [ 85 | { 86 | test: /\.vue$/, 87 | loader: 'vue-loader', 88 | options: { 89 | loaders: Mix.options.extractVueStyles ? { 90 | js: 'babel-loader' + Mix.babelConfig(), 91 | scss: vueExtractTextPlugin.extract({ 92 | use: 'css-loader!sass-loader', 93 | fallback: 'vue-style-loader' 94 | }), 95 | sass: vueExtractTextPlugin.extract({ 96 | use: 'css-loader!sass-loader?indentedSyntax', 97 | fallback: 'vue-style-loader' 98 | }), 99 | stylus: vueExtractTextPlugin.extract({ 100 | use: 'css-loader!stylus-loader?paths[]=node_modules', 101 | fallback: 'vue-style-loader' 102 | }), 103 | css: vueExtractTextPlugin.extract({ 104 | use: 'css-loader', 105 | fallback: 'vue-style-loader' 106 | }) 107 | }: { 108 | js: 'babel-loader' + Mix.babelConfig(), 109 | scss: 'vue-style-loader!css-loader!sass-loader', 110 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax', 111 | stylus: 'vue-style-loader!css-loader!stylus-loader?paths[]=node_modules' 112 | }, 113 | 114 | postcss: Mix.options.postCss 115 | } 116 | }, 117 | 118 | { 119 | test: /\.jsx?$/, 120 | exclude: /(node_modules|bower_components)/, 121 | loader: 'babel-loader' + Mix.babelConfig() 122 | }, 123 | 124 | { 125 | test: /\.css$/, 126 | loaders: ['style-loader', 'css-loader'] 127 | }, 128 | 129 | { 130 | test: /\.s[ac]ss$/, 131 | include: /node_modules/, 132 | loaders: ['style-loader', 'css-loader', 'sass-loader'] 133 | }, 134 | 135 | { 136 | test: /\.html$/, 137 | loaders: ['html-loader'] 138 | }, 139 | 140 | { 141 | test: /\.(png|jpe?g|gif)$/, 142 | loader: 'file-loader', 143 | options: { 144 | name: 'images/[name].[ext]?[hash]', 145 | publicPath: Mix.resourceRoot 146 | } 147 | }, 148 | 149 | { 150 | test: /\.(woff2?|ttf|eot|svg|otf)$/, 151 | loader: 'file-loader', 152 | options: { 153 | name: 'fonts/[name].[ext]?[hash]', 154 | publicPath: Mix.resourceRoot 155 | } 156 | }, 157 | 158 | { 159 | test: /\.(cur|ani)$/, 160 | loader: 'file-loader', 161 | options: { 162 | name: '[name].[ext]?[hash]', 163 | publicPath: Mix.resourceRoot 164 | } 165 | } 166 | ] 167 | }; 168 | 169 | 170 | if (Mix.preprocessors) { 171 | Mix.preprocessors.forEach(preprocessor => { 172 | module.exports.module.rules.push(preprocessor.rules()); 173 | 174 | module.exports.plugins = (module.exports.plugins || []).concat(preprocessor.extractPlugin); 175 | }); 176 | } 177 | 178 | 179 | /* 180 | |-------------------------------------------------------------------------- 181 | | Resolve 182 | |-------------------------------------------------------------------------- 183 | | 184 | | Here, we may set any options/aliases that affect Webpack's resolving 185 | | of modules. To begin, we will provide the necessary Vue alias to 186 | | load the Vue common library. You may delete this, if needed. 187 | | 188 | */ 189 | 190 | module.exports.resolve = { 191 | extensions: ['*', '.js', '.jsx', '.vue'], 192 | 193 | alias: { 194 | 'vue$': 'vue/dist/vue.common.js' 195 | } 196 | }; 197 | 198 | 199 | 200 | /* 201 | |-------------------------------------------------------------------------- 202 | | Stats 203 | |-------------------------------------------------------------------------- 204 | | 205 | | By default, Webpack spits a lot of information out to the terminal, 206 | | each you time you compile. Let's keep things a bit more minimal 207 | | and hide a few of those bits and pieces. Adjust as you wish. 208 | | 209 | */ 210 | 211 | module.exports.stats = { 212 | hash: false, 213 | version: false, 214 | timings: false, 215 | children: false, 216 | errors: false 217 | }; 218 | 219 | process.noDeprecation = true; 220 | 221 | module.exports.performance = { hints: false }; 222 | 223 | 224 | 225 | /* 226 | |-------------------------------------------------------------------------- 227 | | Devtool 228 | |-------------------------------------------------------------------------- 229 | | 230 | | Sourcemaps allow us to access our original source code within the 231 | | browser, even if we're serving a bundled script or stylesheet. 232 | | You may activate sourcemaps, by adding Mix.sourceMaps(). 233 | | 234 | */ 235 | 236 | module.exports.devtool = Mix.sourcemaps; 237 | 238 | 239 | 240 | /* 241 | |-------------------------------------------------------------------------- 242 | | Webpack Dev Server Configuration 243 | |-------------------------------------------------------------------------- 244 | | 245 | | If you want to use that flashy hot module replacement feature, then 246 | | we've got you covered. Here, we'll set some basic initial config 247 | | for the Node server. You very likely won't want to edit this. 248 | | 249 | */ 250 | module.exports.devServer = { 251 | historyApiFallback: true, 252 | noInfo: true, 253 | compress: true, 254 | quiet: true 255 | }; 256 | 257 | 258 | 259 | /* 260 | |-------------------------------------------------------------------------- 261 | | Plugins 262 | |-------------------------------------------------------------------------- 263 | | 264 | | Lastly, we'll register a number of plugins to extend and configure 265 | | Webpack. To get you started, we've included a handful of useful 266 | | extensions, for versioning, OS notifications, and much more. 267 | | 268 | */ 269 | 270 | module.exports.plugins = (module.exports.plugins || []).concat([ 271 | new webpack.ProvidePlugin(Mix.autoload || { 272 | jQuery: 'jquery', 273 | $: 'jquery', 274 | jquery: 'jquery' 275 | }), 276 | 277 | new plugins.FriendlyErrorsWebpackPlugin(), 278 | 279 | new plugins.StatsWriterPlugin({ 280 | filename: 'mix-manifest.json', 281 | transform: Mix.manifest.transform.bind(Mix.manifest), 282 | }), 283 | 284 | new plugins.WebpackMd5HashPlugin(), 285 | 286 | new webpack.LoaderOptionsPlugin({ 287 | minimize: Mix.inProduction, 288 | options: { 289 | postcss: Mix.options.postCss, 290 | context: __dirname, 291 | output: { path: './' } 292 | } 293 | }) 294 | ]); 295 | 296 | 297 | if (Mix.browserSync) { 298 | module.exports.plugins.push( 299 | new plugins.BrowserSyncPlugin( 300 | Object.assign({ 301 | host: 'localhost', 302 | port: 3000, 303 | proxy: 'app.dev', 304 | files: [ 305 | 'app/**/*.php', 306 | 'resources/views/**/*.php', 307 | 'public/js/**/*.js', 308 | 'public/css/**/*.css' 309 | ] 310 | }, Mix.browserSync), 311 | { 312 | reload: false 313 | } 314 | ) 315 | ); 316 | } 317 | 318 | 319 | if (Mix.notifications) { 320 | module.exports.plugins.push( 321 | new plugins.WebpackNotifierPlugin({ 322 | title: 'Laravel Mix', 323 | alwaysNotify: true, 324 | contentImage: Mix.Paths.root('node_modules/laravel-mix/icons/laravel.png') 325 | }) 326 | ); 327 | } 328 | 329 | 330 | if (Mix.copy) { 331 | Mix.copy.forEach(copy => { 332 | module.exports.plugins.push( 333 | new plugins.CopyWebpackPlugin([copy]) 334 | ); 335 | }); 336 | } 337 | 338 | 339 | if (Mix.extract) { 340 | module.exports.plugins.push( 341 | new webpack.optimize.CommonsChunkPlugin({ 342 | names: Mix.entryBuilder.extractions.concat([ 343 | path.join(Mix.js.base, 'manifest').replace(/\\/g, '/') 344 | ]), 345 | minChunks: Infinity 346 | }) 347 | ); 348 | } 349 | 350 | 351 | if (Mix.inProduction) { 352 | module.exports.plugins.push( 353 | new webpack.DefinePlugin({ 354 | 'process.env': { 355 | NODE_ENV: '"production"' 356 | } 357 | }), 358 | 359 | new webpack.optimize.UglifyJsPlugin(Mix.options.uglify) 360 | ); 361 | } 362 | 363 | 364 | module.exports.plugins.push( 365 | new plugins.WebpackOnBuildPlugin( 366 | stats => Mix.events.fire('build', stats) 367 | ) 368 | ); 369 | 370 | 371 | /* 372 | |-------------------------------------------------------------------------- 373 | | Mix Finalizing 374 | |-------------------------------------------------------------------------- 375 | | 376 | | Now that we've declared the entirety of our Webpack configuration, the 377 | | final step is to scan for any custom configuration in the Mix file. 378 | | If mix.webpackConfig() is called, we'll merge it in, and build! 379 | | 380 | */ 381 | Mix.finalize(module.exports); 382 | -------------------------------------------------------------------------------- /src/VueGoogleAutocomplete.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 377 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Google Autocomplete 2 | 3 | [![npm version](https://badgen.net/npm/v/vue-google-autocomplete)](https://www.npmjs.com/package/vue-google-autocomplete) [![sponsored_by](https://badgen.net/badge/sponsored%20by/%F0%9F%A4%96Easy-Peasy.AI/f2a)](https://Easy-Peasy.AI/?utm_source=npm&utm_medium=badge&utm_campaign=vue_google_autocomplete) 4 | 5 | A Vue.js (2.x) autosuggest component for the Google Maps Places API. 6 | 7 | ## Demo 8 | 9 | Live demo: [olefirenko.github.io/vue-google-autocomplete](https://olefirenko.github.io/vue-google-autocomplete/) 10 | 11 | ## Benefits 12 | 13 | I have tried to use different Vue Google Autocomplete components, but did not find any that would solve my needs. So below I would like to mention what you can get from this exact component: 14 | 15 | - Load more than one autocompletion inputs (I could not achieve this with existing vue components) 16 | - Getting geolocation data (latitude, longitude) for found address object along with other address data (country, city, state, county, street, house number, zip code). So no need to do additional geocode request on backend side. 17 | - No external dependencies 18 | - You can get access to underlying [PlaceResult object](https://developers.google.com/maps/documentation/javascript/reference#PlaceResult) to get more details about found location. You are able to specify the specific fields you want to fetch from the PlaceResult object. 19 | - You can limit results to specific country or use users geolocation data 20 | 21 | ## Installation 22 | 23 | This component uses Google Maps Places API to get geo suggests for autocompletion, so you have to include the Google Maps Places API in the `` of your HTML: 24 | 25 | ```html 26 | 27 | 28 | 29 | … 30 | 31 | 32 | 33 | … 34 | 35 | 36 | ``` 37 | 38 | To obtain API key please visit the [Google Developer Console](https://console.developers.google.com). The API's that you have to enable in your Google API Manager Dashboard are [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start), [Google Places API Web Service](https://developers.google.com/places/web-service/) and [Google Maps Javascript API](https://developers.google.com/maps/documentation/javascript/). 39 | 40 | The easiest way to use Vue Google Autocomplete is to install it from **npm** or **yarn**. 41 | 42 | ```sh 43 | npm install vue-google-autocomplete --save 44 | ``` 45 | 46 | Or 47 | 48 | ```sh 49 | yarn add vue-google-autocomplete 50 | ``` 51 | 52 | ## Usage 53 | 54 | The Vue Google Autocomplete works out of the box by just including it. 55 | 56 | ```js 57 | import VueGoogleAutocomplete from "vue-google-autocomplete"; 58 | ``` 59 | 60 | In your template you can use this syntax: 61 | 62 | ```html 63 | 64 | 65 | ``` 66 | 67 | ### Properties 68 | 69 | #### id 70 | 71 | Type: `String` 72 | 73 | `required` ID for the input container. 74 | 75 | #### classname 76 | 77 | Type: `String` 78 | 79 | Class to the input container. 80 | 81 | #### placeholder 82 | 83 | Type: `String` 84 | Default: `Start typing` 85 | 86 | The input field will get this placeholder text. 87 | 88 | #### types 89 | 90 | Type: `String` 91 | Default: `address` 92 | 93 | Types supported in place autocomplete requests. [More info](https://developers.google.com/places/supported_types#table3) 94 | 95 | You may find [this example](#correct-usage-of-the-types-parameter) helpful. 96 | 97 | #### fields 98 | 99 | Type: `Array` 100 | Default: `['address_components', 'adr_address', 'alt_id', 'formatted_address', 'geometry', 'icon', 'id', 'name', 'permanently_closed', 'photo', 'place_id', 'scope', 'type', 'url', 'utc_offset', 'vicinity']` 101 | 102 | Set which data fields to return in the PlaceResult from the Google Autocomplete API when the user selects a place. [Google Autocomplete API by default returns all available data fields](https://developers.google.com/maps/documentation/javascript/places-autocomplete#get_place_information) for the selected place, which may result in additional charges and thus the API users might pay for data they don't need. This package sets a sensible default for the fields value, fetching only the Basic Data fields which do not result in any additional charges. If you want to fetch other fields in addition to the default ones, make sure that the array you pass in to the `fields` prop contains the default fields listed above, and not only the additional fields you want to fetch. 103 | 104 | Refer to [this page](https://developers.google.com/maps/billing/understanding-cost-of-use#data-skus) for more details on how certain data fields are billed. 105 | 106 | #### country 107 | 108 | Type: `String`|`Array` 109 | Default: null 110 | 111 | Option to restrict the autocomplete search to a particular country. Countries must be passed as a two-character, ISO 3166-1 Alpha-2 compatible country code (i.e. "br", "sg", "fr"). You can provide a single one, or an array of up to 5 country code strings. 112 | Note: this is a dynamic property. You must pass it as `:country=""` to your component, otherwise it won't work. For example: 113 | 114 | ```html 115 | 116 | ``` 117 | 118 | will restrict the countries to Australia and New Zealand. 119 | 120 | #### enable-geolocation 121 | 122 | Type: `Boolean` 123 | Default: `false` 124 | 125 | Bias the search towards user current location. 126 | 127 | #### geolocationOptions 128 | 129 | Type: [`Object`](https://developer.mozilla.org/en/docs/Web/API/PositionOptions) 130 | Default: `{}` 131 | 132 | Allow to configure Options for [`navigator.getCurrentPosition`](https://developer.mozilla.org/en/docs/Web/API/Geolocation/getCurrentPosition) 133 | 134 | ### Events 135 | 136 | The component emits next events, which you can listen in your application: 137 | 138 | #### placechanged 139 | 140 | Gets triggered when the address data got obtained. This data is available on the returned objects: 141 | 142 | - `street_number`, `route`, `locality`, `administrative_area_level_1`, `country`, `postal_code`, `latitude`, `longitude`. 143 | - `place` - [PlaceResult object](https://developers.google.com/maps/documentation/javascript/reference#PlaceResult) is available as second parameter. 144 | - `id` a String representing the ID of the autocomplete that triggered the event. 145 | 146 | #### no-results-found 147 | 148 | Gets triggered when a user entered the name of a Place that was not suggested and pressed the Enter key, or the Place Details request failed. 149 | 150 | - `object` an object with a key _name_ representing the user's input. 151 | 152 | #### focus 153 | 154 | Gets triggered when the autocomplete input field receives focus. 155 | 156 | #### blur 157 | 158 | Gets triggered when the autocomplete input field loses focus. 159 | 160 | #### inputChange 161 | 162 | Gets triggered every time autocomplete input got changed 163 | 164 | #### change 165 | 166 | Gets triggered when the autocomplete results got changed 167 | 168 | #### keypress 169 | 170 | Gets triggered when a key gets pressed 171 | 172 | #### error 173 | 174 | Gets triggered when an error is encountered 175 | 176 | ### Exposed component functions 177 | 178 | These functions are accessible by setting "ref" on the component ([Refs documentation](https://vuejs.org/v2/guide/components.html#Child-Component-Refs)). See example below how to use these functions. 179 | 180 | #### clear() 181 | 182 | Call to clear the value of the user input. 183 | 184 | #### focus() 185 | 186 | Call focus to focus on the element 187 | 188 | #### blur() 189 | 190 | Call blur to blur (unfocus) the element 191 | 192 | #### update(value) 193 | 194 | Call to update the user input with a new value 195 | 196 | #### updateCoordinates([latlng](https://developers.google.com/maps/documentation/javascript/reference#LatLng)) 197 | 198 | Call to force coordinates and update the input accordingly 199 | 200 | #### geolocate() 201 | 202 | Call to retrieve current position from `navigator` and update the input accordingly 203 | 204 | ### Example 205 | 206 | Please note that you need to provide what method will listen (`v-on:placechanged`) to an event when the address data is obtained. 207 | 208 | ```html 209 | 224 | 225 | 256 | ``` 257 | 258 | #### Correct usage of the types parameter 259 | 260 | The example below shows the correct usage of the `types` parameter, when limiting the search to cities: 261 | 262 | ```vue 263 | 272 | 273 | ``` 274 | 275 | ## Contributors ✨ 276 | 277 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 |

Dmytro Olefyrenko

💻

Daryle Dale De Silva

💻

DjilanoS

🚧

Juan Villegas

💻

Hugh Saffar

💻

Ahmed

💻

Ankur Kumar

💻

Artur Grigio

💻

Brian Rutledge

💻

Bryan Miller

💻

Chris Sepic

💻

Dennis van Breukelen

💻

Dmitry Mazurok

💻

Julian Renard

💻

Leonardo Arroyo

💻

Max Lyashuk

💻

Michał Gibowski

💻

Mickey Schwab

💻

Romain Léger

💻

Simon Kimber

💻

syffs

💻

Yann Bertrand

💻

ciaasteczkowy

💻

crabaux

💻
316 | 317 | 318 | 319 | 320 | 321 | 322 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 323 | --------------------------------------------------------------------------------