2

I'm trying to use jQuery geocomplete along with Vue.js to populate a form with geo data.

My code contains this form:

<form>
    <label for="get-offer-location">location: </label><input id="get-offer-location" v-model="newoffer.location" type="text"/>
    <div style="visibility:hidden">
        <input name="lat" type="text" value=""/>
        <input name="lng" type="text" value=""/>
    </div>
</form>

After I click on a suggested location from the get-offer-location input, it looks like the field is filled out -- but then when I start typing in another field, the location input field reverts to just the letters I typed in for the location search. Try it out here by clicking "post", then "news" or "offers": https://jsfiddle.net/dvdgdnjsph/157w6tk8/

Can anyone tell me what's wrong?

mic4ael
  • 7,974
  • 3
  • 29
  • 42
David J.
  • 1,753
  • 13
  • 47
  • 96

4 Answers4

2

The problem you are having is that v-model binds on input, since the geolocation dropdown is a plugin that changes the value programatically the input event is not fired, so v-model is not updated. As a case, try typing a space after selecting a location, you will see that it sticks.

Fortunately, v-model is nothing more than syntactic sugar for v-on:input, so you can use v-on to fire your event instead. Considering that you are going to need to unfocus to get out of the box, the blur event is likely to be your best option, so you can simply do:

v-on:blur="newarticle.location = $event.target.value"

Unfortunately, JSFiddle won't let me save or update your Fiddle, but I did get it working with the code above.

For completeness, in case you want to use this behavior extensively, and because the Vue docs are fairly limited in this regard, you may write a custom directive to encapsulate the code:

Vue.directive('model-blur', {
  bind: function(el, binding, vnode) {
    el.addEventListener('blur', function() {
      vnode.context[binding.expression] = el.value;
    });
  }
});

Then you can use like so:

<input v-model-blur="myVar" />

Here's the JSFiddle: https://jsfiddle.net/4vp6Lvmc/

tony19
  • 125,647
  • 18
  • 229
  • 307
craig_h
  • 31,871
  • 6
  • 59
  • 68
1

Can't tell for sure. But it looks like jQuery plugin just changes input#get-article-location value, but not the Vue model. So when you trigger model update (e.g. editing headline) it overwrites complete location with whatever you typed in.

Yaroslav
  • 31
  • 1
  • 3
1

I have something like this for catch the geocomplete event and try to set the vueJS value :

$("#get-article-location")
  .geocomplete({details: ".details"})
  .bind("geocode:result", function (event, result) {
    vm.newoffer.location = result.formatted_address;
    console.log('done');
  });

But something still appears wrong, I think you should really change the name of your vueJS instance (var vm) it may be use by another script and make troubles.

Nhan
  • 3,595
  • 6
  • 30
  • 38
Antoine Pointeau
  • 399
  • 2
  • 14
  • I tried that too, can't get it to work. Tried changing the variable name and it doesn't help. – David J. Jan 06 '17 at 10:32
  • @DavidJ. Sorry I didn't check out the other answers really carefully before posting mine, this solution seems to be the same as I posted below, but it worked fine when I tried on jsfiddle. – JJPandari Jan 08 '17 at 10:51
1

This is because v-model, as two-way binding, on the receiving-user-input way, listens to the input event on the input element, while js plugins (like jquery-geocomplete) obviously set input values via js, which leads to the view model's data not changing as we discussed in other answers.

To fix this, just listen to the geocode:result event of the plugin and manually change the data with code (there seems to be something wrong with jsfiddle so I'm posting it here):

var vueVM = this;

$("#get-offer-location").geocomplete({ details: ".details" });

$("#get-article-location")
.geocomplete({ details: ".details" })
/***** highlight start *****/
.bind("geocode:result", function(event, result){
    console.log(result);
    //tried result.something but couldn't find the the same thing as `this.value`
    vueVM.newarticle.location = this.value;
});
/***** highlight end *****/

extra knowledge: the mechanism of v-model stated above is usually used in making reusable components, by receiving a value prop from the parent, and emitting an input event with the user-input value when detecting change on the input element in the component. And then we can use <my-component v-model='parentData'></my-component> as the child behaves exactly like a simple input element from the parent's perspective. example

JJPandari
  • 3,454
  • 1
  • 17
  • 24