How can I call method from data on vue.js? - javascript

My vue component like this :
<template>
<ul class="nav nav-tabs nav-tabs-bg">
<li v-for="tab in tabs" role="presentation" :class="setActive(tab.url)">
<a :href="baseUrl + tab.url">{{tab.title}}</a>
</li>
</ul>
</template>
<script>
export default {
props: ['shop'],
data() {
return{
tabs: [
{
title: 'product',
url: '/store/' + this.shop.id + '/' + strSlug(this.shop.name)
},
{
title: 'info',
url: '/store/' + this.shop.id + '/' + strSlug(this.shop.name) + '/info'
}
]
}
},
methods: {
setActive(pathname){
return {active: window.location.pathname == pathname}
},
strSlug: function(val) {
return _.kebabCase(val)
}
}
}
</script>
If the code run, there exist error like this :
[Vue warn]: Error in data(): "ReferenceError: strSlug is not defined"
If I console.log(window.location.pathname), the result like this :
/store/21/chelsea-hazard-store
So if it is the same as url with data in tabs, then it will active
I call the strSlug method to convert each into lowercase and convert spaces into -
Seems it can not call the method from the data
How can I solve the error?

If you have a function in data that will be used in a context of another object (like an event handler, for example), then this will not point to the Vue instance. You will have to preserve the reference in another variable from the scope of data():
methods: {
shuffle() {}
},
data() {
var self = this;
return {
onClick: function() {
self.shuffle()
}
}
}

When accessing data or methods from within the vue object, use this.thing. In your case, that would be this.strSlug(this.shop.name).

Does not work even with 'this.' because that function has not been defined at the time data is being initialized. I think you have to do it in the created() life-cycle hook.

Related

Can I send a custom event from a eventBus listener?

I have the following on a Vue component:
data: function() {
return {
quotes: []
};
},
created() {
eventBus.$on("quoteWasAdded", message => {
this.quotes.push(message);
this.$emit("quotesWereUpdated", this.quotes);
});
}
What I want to achieve is when the quotes arrays is updated, it creates a custom event so I can use it on a parent or on other siblings.
I'm trying to use it on the parent component, but it's returning undefined
Parent:
<template>
<div class="container">
<p>{{messages.length}}</p>
<quote-header></quote-header>
<new-quote></new-quote>
<quotes #quotesWereUpdated="messages = $event"></quotes>
</div>
</template>
I would try something like this:
<quotes #quotesWereUpdated="updateMessages"></quotes>
then declare a method:
updateMessages (data) {
this.messages = data
}

Vue.js undefined error on object value when loaded and rendered

OK. I'm not a total newbie and do have some Vue xp but this is bugging me. What really obvious thing am I missing.
I have an object loaded via an ajax call inside a mounted method:
job: {
"title": "value",
"location": {
"name":"HONG KONG"
}
}
When I call {{ job.title }} all good. When I call {{ job.location.name }} I have an undefined error but the value renders. When I call {{ job.location }} I get the json object so it is defined.
Aaargh! I'm sure it's really simple but can't possibly see why this isn't as straight forward as it should be.
// Additional
This is my entire Vue class
const router = new VueRouter({
mode: 'history',
routes: []
});
const app = new Vue( {
router,
el: '#app',
data: {
job: {}
},
mounted: function () {
var vm = this
jQuery.ajax({
url: 'https://xxx' + this.jobId,
method: 'GET',
success: function (data) {
vm.job = data;
},
error: function (error) {
console.log(error);
}
});
},
computed: {
jobId: function() {
return this.$route.query.gh_jid
}
}
})
When your component renders it tries to get value from job.location.name but location is undefined before ajax request is completed. So I guess error is kind of Cannot read property 'name' of undefined.
To fix this you can define computed property locationName and return, for example, empty string when there is no loaded job object yet:
computed:{
//...
locationName() {
return this.job.location ? this.job.location.name : '';
}
}
Or you can define computed for location and return empty object if there is no location, or you can just add empty location object to your initial data(if you are sure that your API response always has location) like job: { location: {}} all ways will fix your issue.
Also there is a way to fix it with v-if directive in your template:
<div v-if="job.location">
{{ job.location.name }}
<!-- other location related stuff -->
</div>
An ES6 solution for you:
computed: {
getJobName(){
return this.job?.location.name
}
}
Optional Chaining

Trying to access an API using Vue js

I'm having some trouble trying to access an API to get or fetch data. I'm still currently new to vue.js and javascript. I'm getting an error Uncaught SyntaxError: Invalid shorthand property initializer. I can't seem to understand what the error means or seems to indicate.
<body>
<div id="vue-app">
{{ articles }}
</div>
<body>
var article = new Vue({
el: '#vue-app',
data: {
articles = ''
},
created: function () {
this.fetchData();
},
methods: {
fetchData: function () {
var that = this
this.$http.get('localhost/aim-beta/rest/export/json/article'),
function (data) {
vm.articles = data.main.temp;
}
}
}
});
Instead of using this.$http, use axios library for making api calls.
I think you can't use equal in the JS object syntax
data: {
articles = ''
}
Try
data: function() {
return () {
articles: ‘’
}
}
And specify http:// to the localhost
this.$http.get('http://localhost/aim-beta/rest/export/json/article'),
function (data) {
this.articles = data.json()
}
Use this for the data JSON object:
data: {
articles: ''
}
Then, use Promise for firing the HTTP request (note that I used the http:// with the URL):
this.$http.get('http://localhost/aim-beta/rest/export/json/article')
.then(function(response){
this.articles = response.json();
});
Source : Documentation

Vuejs: How to properly pass props to component data

i'm playing with Vue 2.0, but there is something unclear..
how can i pass the props to the internal data of a component?
Looking at the documentation it seems that i have done right.
HTML
<lista-servizi :servizi="modello"></lista-servizi>
the "modello" is a data already defined.
THE VUE COMPONENT
Vue.component('lista-servizi', {
template:
'<span class="blu">{{listaServizi.lineaGialla.descrizione}}</span>',
props: ['servizi'],
data: function(){
return{
listaServizi : this.servizi
}
basically i try to give to data listaServizi the same value as props servizi,
but in the console i have the following message:
[Vue warn]: Error in render function: "TypeError: Cannot read property 'descrizione' of undefined"
found in
---> <ListaServizi>
<Root>
You should used computed instead.
Vue.component('lista-servizi', {
//...
computed: {
listaServizi() {
return this.servizi
}
}
}
Most likely you have a problem with modello.
By defining the modello, your code works fine. Below is an example based on your code that works:
<div id="app-1">
<lista-servizi :servizi="modello"></lista-servizi>
</div>
Vue.component('lista-servizi', {
template: '<span class="blu">{{listaServizi.lineaGialla.descrizione}}</span>',
props: ['servizi'],
data: function(){
return{
listaServizi : this.servizi
}
}
})
var app1 = new Vue({
el: '#app-1',
data: {
modello: {
lineaGialla : {
descrizione : " This is a description"
}
}
}
})
Here is a link to a working bin
https://jsbin.com/qoloqoz/1/edit?html,js,output

knockout throws Message: TypeError: <xxx> is not a function. What does it mean?

I have this code:
<ul id="chats" data-bind="foreach: chats">
<li>
<div class="chat_response" data-bind="visible: CommentList().length == 0">
<form data-bind="submit: $root.addComment">
<input class="comment_field" placeholder="Comment…" data-bind="value: NewCommentText" />
</form>
</div>
<a class="read_more_messages" data-bind="visible: moreChats, click: showMoreChats">Read More Messages...</a>
</li>
</ul>
function ChatListViewModel(chats) {
// Data
var self = this;
self.chats = ko.observableArray(ko.utils.arrayMap(chats, function (chat) {
return { CourseItemDescription: chat.CourseItemDescription,
CommentList: ko.observableArray(chat.CommentList),
CourseItemID: chat.CourseItemID,
UserName: chat.UserName,
ChatGroupNumber: chat.ChatGroupNumber,
ChatCount: chat.ChatCount,
NewCommentText: ko.observable("")
};
}));
self.moreChats = ko.observable(true);
self.showMoreChats = function () {
var LastChatGroupNumber = self.chats()[self.chats().length - 1].ChatGroupNumber;
$.ajax({
url: $.CourseLogic.dataitem.GetMoreChatsUrl,
data: "{chatGroupNumber: " + ko.toJSON(LastChatGroupNumber + 1) + "}",
type: "post",
contentType: "application/json",
success: function (chats) {
var chatList = self.chats();
$.each(chats, function (index, chat) {
self.chats.push(chat);
});
}
});
}
}
ko.applyBindings(new ChatListViewModel(initialData));
But I get this error when the showMoreChats function is called:
Unable to parse bindings.
Message: TypeError: CommentList is not a function;
Bindings value: visible: CommentList().length == 0
What does it mean?
It's not that CommentList is undefined, it's just that it's not an observable (hence not a function). The reason being that in your ajax callback, you are just pushing the 'chat' objects received from your server "as is". You're not creating for example a new observableArray called CommentList, but you're just putting a bare array CommentList - hence the thrown error by KO.
You would need to make the same transformation as you did when constructing self.chats in the viewmodel constructor, e.g.:
$.each(chats, function(index, chat) {
self.chats.push(
{
CourseItemDescription: chat.CourseItemDescription,
CommentList: ko.observableArray(chat.CommentList),
CourseItemID: chat.CourseItemID,
UserName: chat.UserName,
ChatGroupNumber: chat.ChatGroupNumber,
ChatCount: chat.ChatCount,
NewCommentText: ko.observable("")
}
);
});
By the way, you should also take a look at the ko.mapping plugin, it can do this transformation for you.
Edit: Also, for better performance you shouldn't push each individual item into the observable array, but add them in one bulk operation, something like:
self.chats( self.chats().concat( ko.utils.arrayMap(chats, function(chat) {
return { /* ... same as before ... */ };
} ) );
Found this question via Google, adding my case for reference.
It's really, really stupid; yet this is a mistake caused by inattention I often make:
When using one of the ko.utils array functions (arrayMap, arrayForEach, arrayFirst, etc.), Knockout will throw this error when you forget to specify the source array, eg. when you do:
ko.utils.arrayMap(function(item) { ... })
instead of:
ko.utils.arrayMap(myArray, function(item) { ... });
It means your binding cannot detect CommentList, i.e. CommentList is undefined in the current context.

Categories

Resources