Vue not updating - javascript

I'm new to Vue js - the following is not updating:
<div id="error" class="col s12 red center">
<span v-if="seen">
Error fetching readings: {{ msg }}
</span>
</div>
Vue:
var error = new Vue({
el: '#error',
data: {
msg: '',
seen: false
},
methods: {
show: function(message) {
this.msg = message;
this.seen = true;
},
hide: function() {
this.seen = false;
}
}
});
Post fetch:
fetch( ... )
.then(...)
.catch(err => {
error.show( err );
loader.hide();
});
error.show() displays the previously hidden div, but displays:
Error fetching readings: {}
Why?

i created a CodeSandbox sample based upon your code, you need to have computed property to have the Vue reactivity
Sample can be found, check code in HelloWorld.vue in components folder
https://codesandbox.io/s/x2klzr59wo
<template>
<div id="error" class="col s12 red center">
{{ seen }}
<hr />
<span v-if="computedSeen"> Error fetching readings: {{ msg }} </span>
<hr />
<button #click="show('effe');">SHOW</button>
<button #click="hide();">HIDE</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
msg: "",
seen: false
};
},
methods: {
show: function(message) {
this.msg = message;
this.seen = true;
},
hide: function() {
this.seen = false;
}
},
computed: {
computedSeen: function() {
// `this` points to the vm instance
return this.seen;
}
}
};
</script>

Oops, problem was err from the fetch is an object, and I should have used err.message.
In my code I had a console.log('Error: %s', err) which appears to format the err object into text. Which is what threw me :(
Sorry.

Related

Vue method not passing data to array of objects

So I'm going to be explaining this in the best way possible as I don't understand what might be causing this issue on my end as I feel like I've followed all of the directions and keep hitting a brick wall.
Here is my vue.js app:
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
const default_apps = [
{
'post_title': 'Excel',
}, {
'post_title': 'Word',
}, {
'post_title': 'SharePoint',
}];
console.log(default_apps);
const default_apps1 = this.get_array_of_post_objects('application_launcher');
console.log(default_apps1);
return {
available_list: [],
selected_list: default_apps.map(function(name, index) {
return {
name: name.post_title,
order: index + 1,
fixed: false
};
}),
}
},
methods: {
get_array_of_post_objects(slug) {
let items = [];
wp.api.loadPromise.done(function () {
const Posts = wp.api.models.Post.extend({
url: wpApiSettings.root + 'menus/v1/locations/' + slug,
});
const all_posts = new Posts();
all_posts.fetch().then((posts) => {
items.push(...posts.items);
});
});
return items;
},
},
computed: {
dragOptions() {
// Pass in additional <draggable> options inside the return for both lists.
return {
tag: 'div',
group: 'o365apps',
disabled: !this.editable,
ghostClass: "ghost",
};
},
},
});
Inside my methods, I have a method called get_array_of_post_objects which returns an array of objects that I'm pulling through.
So inside data, I'm console logging my manual default_apps and my default_apps1 which is the method. Both of the arrays of objects have post_title: "something" inside.
Here is the return that I'm getting:
Inside my mapping, when I define default_apps, my IDE returns some result for name but when I switch it over to default_apps1, it's not finding any results as shown below:
I don't know what else to look at - All help would be appreciated!
Here is the HTML code if that is needed:
<div class="column is-half-desktop is-full-mobile buttons">
<nav class="level is-mobile mb-0">
<div class="level-left">
<div class="level-item is-size-5 has-text-left">Selected</div>
</div>
<div class="level-right">
<div class="level-item" #click="orderList()"><i class="fas fa-sort-alpha-up is-clickable"></i></div>
</div>
</nav>
<hr class="mt-1 mb-3">
<!-- Decorator: # also known as v-on: -->
<!-- Bind: : also known as v-bind: -->
<draggable class="list-group"
v-model="selected_list"
v-bind="dragOptions"
:move="onMove"
#add="onAdd"
#remove="onRemove"
#start="isDragging=true"
#end="isDragging=false">
<button class="button is-fullwidth is-flex list-group-item o365_app_handle level is-mobile" v-for="(app, index) in selected_list" :key="app.order">
<div class="level-left">
<span class="icon" aria-hidden="true">
<img :src="`<?= Path::o365('${app.name}' . '.svg'); ?>'`" />
</span>
<span>{{app.name}}</span>
</div>
<div class="level-right is-hidden-desktop">
<span class="icon has-text-danger is-clickable" #click="remove(index)">
<i class="fas fa-times"></i>
</span>
</div>
</button>
</draggable>
</div>
I'm not 100% sure what your app is supposed to do, so modify it for your needs.
Here the selected_list will be empty first.
Then we call your method, which is asynchronous, and once it's done selected_list gets populated.
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
return {
available_list: [],
selected_list: [],
}
},
created() {
this.get_array_of_post_objects("add-your-slug")
},
methods: {
get_array_of_post_objects(slug) {
wp.api.loadPromise.done(function() {
const Posts = wp.api.models.Post.extend({
url: wpApiSettings.root + 'menus/v1/locations/' + slug,
});
const all_posts = new Posts();
all_posts.fetch().then((posts) => {
// You might want to modify posts for your needs
this.selectedList = posts
});
});
},
},
});

Vue form validation

I have some problems with mine Vue app.
I'm trying to validate login form that is connected with my Laravel App.
This is how template looks
<template>
<div>
<div class="main" v-if="canLogin">
<img class="logo" src="../assets/logo.png">
<form id="app"
#submit="checkForm"
method="post">
<p v-if="validation.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="validation in validation">{{ error }}</li>
</ul>
</p>
<input class="form-input" type="email" v-model="form.email" id="email" align="center" placeholder="eMail" required>
<input class="form-input" type="password" v-model="form.password" id="password" align="center" placeholder="Password" required>
<button #click.prevent="login" class="submit">Sign In</button>
</form>
</div>
<div class="main" v-if="!canLogin">
<span> YOU ARE BLOCKED FOR 15 MINUTES</span>
</div>
</div>
</template>
As you see I want to foreach errors, but it's always giving error that
'validation' is defined but never used
And this is how mine script looks.
<script>
import User from "../apis/User";
export default {
data() {
return {
form: {
email: "",
password: ""
},
validation: [],
errors: '',
message: '',
canLogin: true,
};
},
mounted() {
User.canLogin().then(response => {
this.canLogin = response.data.canLogin;
});
},
methods: {
checkForm: function (e) {
this.errors = [];
if (!this.form.password) {
this.errors.push("Name required.");
}
if (!this.form.email) {
this.errors.push('Email required.');
} else if (!this.validEmail(this.email)) {
this.errors.push('Valid email required.');
}
if (!this.errors.length) {
return true;
}
e.preventDefault();
},
validEmail: function (email) {
var re = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
},
login() {
User.login(this.form)
.then(response => {
this.$store.commit("LOGIN", true);
localStorage.setItem("token", response.data.token);
this.$router.push({ name: "Dashboard" });
this.$snotify.success(response.data.message, {
timeout: 2000,
showProgressBar: true,
closeOnClick: true,
pauseOnHover: true
});
})
.catch(error => {
if (error.response.status === 400) {
this.errors = error.response.data.message;
this.$snotify.error(error.response.data.message, {
timeout: 2000,
showProgressBar: true,
closeOnClick: true,
pauseOnHover: true
});
}
if(error.response.status === 429){
this.canLogin = false;
}
});
}
}
};
</script>
I'm catching few thhings, like, canLogin, this is checking if IP is not blocked.
There is one more error like:
Elements in iteration expect to have 'v-bind:key' directives
I'm just a started with vue so don't judge me if it's simple fix.
BTW: without validation works fine, I believe it's not only problem with those errors and probbly I'm not catching some things as needed.
What am I doing wrong here?
Change
<ul>
<li v-for="validation in validation">{{ error }}</li>
</ul>
To:
<ul>
<li v-for="(error,index) in errors" v-bind:key="index">{{ error }}</li>
</ul>
In vue, you must provide a key for every v-for looping.
And change your data to:
data() {
return {
form: {
email: "",
password: ""
},
validation: [],
errors: [],
message: '',
canLogin: true,
};
},
I made your errors variable an arrayList.

Vue Event Bus - $on works with fat arrow function but not 'traditional' function

I was having a lot of trouble figuring out why I wasn't able to have an event bus listener update one of my components.
Below, in one of my component files, my server data property wouldn't get properly updated when using a traditional function accepting the outside server argument:
<template>
<div class="col-xs-12 col-sm-6">
<p v-if="!server">Please select a server</p>
<p v-else>Server #{{ server.id }} selected, Status: {{ server.status }}</p>
</div>
</template>
<script>
import { serverBus } from '../../main.js';
export default {
data: function() {
return {
server: null
}
},
created() {
/* DOESNT WORK */
serverBus.$on('serverSelected', function(server) {
this.server = server;
});
}
}
</script>
However, once I change serverBus.$on to accept a fat arrow as its parameter receiving the server, it works and the <p v-else> gets properly triggered after the server is no longer null.
<template>
<div class="col-xs-12 col-sm-6">
<p v-if="!server">Please select a server</p>
<p v-else>Server #{{ server.id }} selected, Status: {{ server.status }}</p>
</div>
</template>
<script>
import { serverBus } from '../../main.js';
export default {
data: function() {
return {
server: null
}
},
created() {
/* WORKS */
serverBus.$on('serverSelected', (server) => {
this.server = server;
});
}
}
</script>
Do you know why this is? I even did a console.log inside of the created() in the one that wasn't working, and the server information was getting properly logged... the <p v-else> just wasn't responding to the data server property no longer being null.
Here's my $emit portion, if it helps:
<script>
import { serverBus } from '../../main.js';
export default {
props: ['server'],
methods: {
serverSelected() {
serverBus.$emit('serverSelected', this.server);
}
}
}
</script>
As #RoyJ says, arrow functions are anonymous and change the way this binds in functions. Using the es5 syntax function creates a new context for this.
Consider the following:
var obj = {
user: 'John',
roles: ['Admin', 'Manager'],
displayUserRoles: function () {
return this.roles.map(function (role) { // es5 function
return this.user + ' is a ' + role + '.'
})
}
}
obj.displayUserRoles()
// output would be
['undefined is a Admin.', 'undefined is a Manager.']
vs:
var obj = {
user: 'John',
roles: ['Admin', 'Manager'],
displayUserRoles: function () {
return this.roles.map(role => { // es6 arrow function
return this.user + ' is a ' + role + '.'
})
}
}
obj.displayUserRoles()
// output would be
['John is a Admin.', 'John is a Manager.']

Vuejs not updating list but updating obect

I am learning Vuejs and I am stuck. Why can I see the messages get added to the object (in Chrome Vue debugger) yet it is not added to the div that contains the list?
My Vue Component:
<template>
<div id="round-status-message" class="round-status-message">
<div class="row">
<div class="col-xs-12" v-for="sysmessage in sysmessages" v-html="sysmessage.message"></div>
</div>
</div>
</template>
<script>
export default {
props: ['sysmessages'],
methods: {
scrollToTop () {
this.$el.scrollTop = 0
}
}
};
</script>
My Vue instance:
$(document).ready(function()
{
Vue.component('chat-system', require('../components/chat-system.vue'));
var chatSystem = new Vue({
el: '#system-chat',
data: function () {
return {
sysmessages: []
};
},
created() {
this.fetchMessages();
Echo.private(sys_channel)
.listen('SystemMessageSent', (e) => {
this.sysmessages.unshift({
sysmessage: e.message.message,
});
this.processMessage(e);
});
},
methods: {
fetchMessages() {
axios.get(sys_get_route)
.then(response => {
this.sysmessages = response.data;
});
},
processMessage(message) {
this.$nextTick(() => {
this.$refs.sysmessages.scrollToTop();
});
// updateGame();
}
}
});
});
My template call in HTML:
<div id="system-chat">
<chat-system ref="sysmessages" v-on:systemmessagesent="processMessage" :sysmessages="sysmessages" :player="{{ Auth::user() }}"></chat-system>
</div>
There are no compile or run time errors and I can see records added to the props in the vue chrome tool. I can also see empty HTML elements added to the div.
What have I missed?
UPDATE: My record structures:
response.data is an array of objects, each like this:
{"data":[
{"id":100,
"progress_id":5,
"message":"start message",
"action":"welcome"
},
{"id"....
e.message.message contains the text message entry, so just a string.
I am trying to access the message variable in each object during the fetchMessages method.
You're adding objects with sysmessage as the property.
this.sysmessages.unshift({
sysmessage: e.message.message,
});
But you are trying to view
v-for="sysmessage in sysmessages" v-html="sysmessage.message"
Based on your update, the code should be:
this.sysmessages.unshift({
message: e.message.message,
});
And you can leave the template as
v-html="sysmessage.message"

Passing Parent Function to Child Component in VueJS

I'm having my practice in VueJS 1.0 and I am learning about Components.
in this example, there is an input element and has to supply coupon or some kind of a code from an API. and I have to validate. I have my <coupon > component and has props of when-applied. The when-applied must call the parent function setCoupon but it won't.
I only got this error this.whenApplied is not a function.
<div id="demo" class="list-group">
<script id="coupon-template" type="x-template">
<input type="text" v-model="coupon" v-on:blur="whenCouponHasBeenEntered">
<div v-text="text"></div>
</script>
<coupon when-applied="setCoupon"></coupon>
</div>
Here is my app.js file
Vue.component('coupon', {
template: '#coupon-template',
props: ['whenApplied'],
data: function() {
return {
coupon: '',
invalid: false,
text: ''
}
},
methods: {
whenCouponHasBeenEntered: function() {
this.validate();
},
validate: function() {
if( this.coupon == 'FOOBAR') {
this.whenApplied(this.coupon);
return this.text = '20% OFF!!';
}
return this.text = 'that coupon doesn`t exists';
}
}
});
new Vue({
el: '#demo',
methods: {
setCoupon: function(coupon) {
alert('set coupon'+ coupon);
}
}
});
Someone pls help. Suggestions pretty much appreciated.
You should bind the property:
<coupon v-bind:when-applied="setCoupon"></coupon>
or you could use the shorthand syntax for v-bind:
<coupon :when-applied="setCoupon"></coupon>
Read more about the props here.

Categories