Vue js. Data fields not binding - javascript

I have the following definition for the Vue element:
new Vue({
el: "#app",
data: {
latitude1: 'a',
name: 'aa'
},
mounted() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
this.latitude1 = position.coords.latitude;
})
} else {
this.latitude1 = "WTF??"
// this doesn't work either:
// this.$nextTick(() => { this.latitude1 = "WTF??" })
}
},
methods: {
// button works... WTF?!?
doIt() {
this.latitude1 = "WTF??"
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div>{{ latitude1 }}: {{ name }}</div>
<button #click="doIt">Do it</button>
</div>
I can see the location data being populated. The alert displays the latitude but the 2 way binding for the data field latitude1 is not working.
I have tried storing the object state using this and that also did not work.
My html is as follows:
<div class="form-group" id="app">
<p>
{{latitude1}}
</p>
</div>

One of the things to do inside the Vue.js is to use the defined methods for reactive properties changes.
Here is a code I've provided for it:
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
new Vue({
el: "#app",
data: {
latitude1: 'a',
name: 'aa'
},
mounted: function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
console.log(position.coords.latitude);
Vue.set(this, 'latitude1', position.coords.latitude);
}, error, options)
}
}
});
I also set error handler and options for the navigator query. For following the results please check the console.

Related

Vuejs - show autocomplete suggestions while user digit

I have this js fiddle code. I want to create a suggestions autocomplete using vuejs. At the moment I've achived only in part the scope, I have a problem with the suggestions. They will be placed under the user input chars and it's not exactly what I was expecting, I want to do something similar to the autocompleto of a smartphone keyboard where the suggested words will be displayed while the user digit a word. Can anyone help me?
<div id="app">
<textarea id="input" v-model="input" #input="predictWord()"></textarea>
<span id="suggestion" ref="suggestion"></span>
</div>
#app {
.input {
position: relative;
}
#suggestion {
position: absolute;
left: 0;
}
}
Vue prototype code
new Vue({
el: "#app",
data() {
return {
input: null,
t9: null,
words: []
}
},
mounted() {
this.init();
},
methods: {
init() {
axios({
method: 'GET',
url: 'https://raw.githubusercontent.com/napolux/paroleitaliane/master/paroleitaliane/660000_parole_italiane.txt'
}).then( (res) => {
this.words = res.data.split('\n');
this.t9 = Predictionary.instance();
this.t9.addWords(this.words);
});
},
predictWord() {
let suggestion;
this.countChars();
suggestion = this.t9.predict(this.input);
this.$refs.suggestion.innerText = suggestion[0];
},
countChars() {
console.log(this.input.length);
}
}
});
I created a working snippet: simplified it a bit, added a loading state (as the dictionary is quite large), updated the resulting output, so it's not dependent on any DOM element.
new Vue({
el: "#app",
data() {
return {
loading: false,
input: null,
t9: null,
suggestion: [],
}
},
mounted() {
this.init();
},
methods: {
async init() {
this.loading = true
try {
const {
data = ''
} = await axios({
method: 'GET',
url: 'https://raw.githubusercontent.com/napolux/paroleitaliane/master/paroleitaliane/660000_parole_italiane.txt'
})
this.t9 = Predictionary.instance();
const a = data.split('\n').filter(e => e)
this.t9.addWords(a)
} catch (err) {
console.error(err)
} finally {
this.loading = false
}
},
predictWord: _.debounce(function() {
this.suggestion = this.input ? this.t9.predict(this.input) : [];
}, 300),
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios#0.21.1/dist/axios.min.js"></script>
<script src="https://unpkg.com/predictionary/dist/predictionary.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
<div id="app">
<textarea id="input" v-model="input" #input="predictWord" :disabled="loading"></textarea><br />
<span id="suggestion">{{ suggestion.join(', ') }}</span>
</div>
Also added a debounce function, so the prediction doesn't have to run so many times - 300ms is a reasonable delay in my experience.

Vue component get and set conversion with imask.js

I am trying to use iMask.js to change 'yyyy-mm-dd' to 'dd/mm/yyyy' with my component however when I am setting the value I think it is taking the value before the iMask has finished. I think using maskee.updateValue() would work but don't know how to access maskee from my component.
I am also not sure if I should be using a directive to do this.
Vue.component("inputx", {
template: `
<div>
<input v-mask="" v-model="comp_date"></input>
</div>
`,
props: {
value: { type: String }
},
computed: {
comp_date: {
get: function () {
return this.value.split("-").reverse().join("/");
},
set: function (val) {
const iso = val.split("/").reverse().join("-");
this.$emit("input", iso);
}
}
},
directives: {
mask: {
bind(el, binding) {
var maskee = IMask(el, {
mask: "00/00/0000",
overwrite: true,
});
}
}
}
});
var app = new Vue({
el: "#app",
data: {
date: "2020-12-30"
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<script src="https://unpkg.com/imask"></script>
<div id="app">
<inputx v-model="date"></inputx>
Date: {{date}}
</div>
The easiest way you can achieve this is by installing the external functionality on the mounted hook of your Vue component, instead of using a directive.
In this way you can store the 'maskee' object on your component's data object to later access it from the setter method.
Inside the setter method you can then call the 'updateValue' method as you hinted. Then, you can extract the processed value just by accessing the '_value' prop of the 'maskee' object.
Here is a working example:
Vue.component("inputx", {
template: `
<div>
<input ref="input" v-model="comp_date"></input>
</div>
`,
data: {
maskee: false,
},
props: {
value: { type: String },
},
computed: {
comp_date: {
get: function () {
return this.value.split("-").reverse().join("/");
},
set: function () {
this.maskee.updateValue()
const iso = this.maskee._value.split("/").reverse().join("-");
this.$emit("input", iso);
}
}
},
mounted(){
console.log('mounted');
const el = this.$refs.input;
this.maskee = IMask(el, {
mask: "00/00/0000",
overwrite: true,
});
console.log('maskee created');
}
});
var app = new Vue({
el: "#app",
data: {
date: "2020-12-30"
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<script src="https://unpkg.com/imask"></script>
<div id="app">
<inputx v-model="date"></inputx>
Date: {{date}}
</div>

Vue watcher executed before the new data is bound?

I am using this code:
var vueApp = new Vue({
el: '#app',
data: {
modalKanji: {}
},
methods: {
showModalKanji(character) {
sendAjax('GET', '/api/Dictionary/GetKanji?character=' + character, function (res) { vueApp.modalKanji = JSON.parse(res); });
}
},
watch: {
'modalKanji': function (newData) {
setTimeout(function () {
uglipop({
class: 'modalKanji', //styling class for Modal
source: 'div',
content: 'divModalKanji'
});
}, 1000);
}
}
});
and I have an element that when clicked on, displays a popup with the kanji data inside:
<span #click="showModalKanji(kebChar)" style="cursor:pointer;>
{{kebChar}}
</span>
<div id="divModalKanji" style='display:none;'>
<div v-if="typeof(modalKanji.Result) !== 'undefined'">
{{ modalKanji.Result.literal }}
</div>
</div>
It works, but only when used with a setTimeout delay to "let the time for Vue to update its model"...if I remove the setTimeout so the code is called instantaneousely in the watch function, the popup data is always "1 iteration behind", it's showing the info of the previous kanji I clicked...
Is there a way for a watcher function to be called AFTER Vue has completed is binding with the new data?
I think you need nextTick, see Async-Update-Queue
watch: {
'modalKanji': function (newData) {
this.$nextTick(function () {
uglipop({
class: 'modalKanji', //styling class for Modal
source: 'div',
content: 'divModalKanji'
});
});
}
}

Vue.js global event not working

I've got
<component-one></component-one>
<component-two></component-two>
<component-three></component-three>
Component two contains component three.
Currently I emit an event in <component-one> that has to be caught in <component-three>.
In <component-one> I fire the event like this:
this.$bus.$emit('setSecondBanner', finalBanner);
Then in <component-three> I catch it like this:
mounted() {
this.$bus.$on('setSecondBanner', (banner) => {
alert('Caught');
this.banner = banner;
});
},
But the event is never caught!
I define the bus like this (in my core.js):
let eventBus = new Vue();
Object.defineProperties(Vue.prototype, {
$bus: {
get: () => { return eventBus; }
}
});
What could be wrong here? When I check vue-dev-tools I can see that the event has fired!
This is the working example for vue1.
Object.defineProperty(Vue.prototype, '$bus', {
get() {
return this.$root.bus;
}
});
Vue.component('third', {
template: `<div> Third : {{ data }} </div>`,
props:['data']
});
Vue.component('second', {
template: `<div>Second component <third :data="data"></third></div>`,
ready() {
this.$bus.$on('setSecondBanner', (event) => {
this.data = event.data;
});
},
data() {
return {
data: 'Defautl value in second'
}
}
});
Vue.component('first', {
template: `<div>{{ data }}</div>`,
ready() {
setInterval(() => {
this.$bus.$emit('setSecondBanner', {
data: 'Bus sending some data : '+new Date(),
});
}, 1000);
},
data() {
return {
data: 'Defautl value in first'
}
}
});
var bus = new Vue({});
new Vue({
el: '#app',
data: {
bus: bus
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.js"></script>
<div id="app">
<second></second>
<first></first>
</div>
Have you tried registering the listener in created instead of mounted?
Also, why define the bus with defineProperties and not simply:
Vue.prototype.$bus = new Vue();

Javascript / vue.js receive json

I'm trying to receive json in my vue.js app like this:
new Vue({
el: 'body',
data:{
role: '',
company: '',
list:[],
created: function() {
this.getJson();
},
methods: {
getJson: function(){
$.getJSON('http://domain.dev/data',function(task){
this.list = task;
}.bind(this));
}
}
}
});
But the result is null? When I test this in postman the url returns json. What am I doing wrong here?
EDIT:
JSON (testdata):
{"EmployeeId":1,"RoleId":5,"DepartmentId":6,"InternId":1,"FirstName":"Zoe","LastName":"Altenwerth","Bio":"Quidem perferendis.","email":"Kole.Bechtelar#hotmail.com","LinkedIn":"Sterling.Schowalter#example.net","Gender":0,"password":"$2y$10$bbUlDh2060RBRVHSPHoQSu05ykfkw2hGQa8ZO8nmZLFFa3Emy18gK","PlainPassword":"gr^S=Z","remember_token":"D528C0Ba1Xzq3yRV7FdNvDd8SYbrM0gAJdFUcOBq4sNEJdHEOb2xIQ0geVhZ","Address":"0593 Dallin Parkway Apt. 499\nBotsfordborough, MT 12501","Zip":"21503-","City":"East Janiston","ProfilePicture":null,"BirthDate":"2002-10-13 00:00:00","StartDate":"1995-11-09 21:42:22","EndDate":"2011-01-27","Suspended":0,"created_at":"2016-02-29 12:21:42","updated_at":"2016-03-02 11:53:58","deleted_at":null,"role":{"RoleId":5,"RoleName":"Superadministrator","Description":"Mag administrators toevoegen en bewerken","deleted_at":null,"created_at":"-0001-11-30 00:00:00","updated_at":"-0001-11-30 00:00:00"},"department":{"DepartmentId":6,"CompanyId":12,"DepartmentName":"com","Description":"Accusantium quae.","deleted_at":null,"created_at":"2016-02-29 12:21:41","updated_at":"2016-02-29 12:21:41","company":{"CompanyId":12,"CompanyName":"Dare, Bailey and Bednar","Logo":null,"Address":"85762 Tabitha Lights\nWest Jettie, AK 20878-2569","Zip":"29601","City":"Traceside","KvKNumber":"84c70661-9","EcaboNumber":"fdee61e3-a22d-3332-a","deleted_at":null,"created_at":"2016-02-29 12:21:41","updated_at":"2016-02-29 12:21:41"}}}
Here is a little example of how to load external JSON data into your component:
a.json:
{"hello": "welcome"}
index.html:
<div id="app">
<pre>{{ json.hello }}</pre>
</div>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
json: null
}
});
$.getJSON('http://localhost/a.json', function (json) {
app.json = json;
});
</script>
--- Edited ---
Or with created event:
<script type="text/javascript">
new Vue({
el: '#app',
data: {
json: null
},
created: function () {
var _this = this;
$.getJSON('http://localhost/a.json', function (json) {
_this.json = json;
});
}
});
</script>
Building on #vbarbarosh's answer, but using the browser's fetch api:
a.json:
{"hello": "welcome"}
index.html:
<div id="app">
<pre>{{ json.hello }}</pre>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
json: null
},
created: function () {
fetch("/a.json")
.then(r => r.json())
.then(json => {
this.json=json;
});
}
});
</script>
You have to bind this to the outer function, too.
getJson: function () { ...}.bind(this)
Update for Vue3
const app = Vue.createApp({
data: function() {
return {
role: '',
company: '',
list:[]
};
},
beforeMount: function() {
this.getJson();
},
methods: {
getJson: function(){
$.getJSON('http://domain.dev/data',function(task){
this.list = task;
}.bind(this));
}
}
});
const mountedApp = app.mount('body');

Categories

Resources