Vue use object value as method name - javascript

Is it possible what I am trying to achieve here to use a value from an object as a method name?
This works great:
Vue.mixin({
methods: {
name: function () {
console.log('hello')
}
}
});
But this:
options = {
methodName: 'name'
};
const method = options.methodName;
Vue.mixin({
methods: {
method: function () {
console.log('hello')
}
}
});
Gives me the following error:
Property or method "name" is not defined on the instance but referenced during render.

Vue.mixin({
methods: {
[method]: function () {
console.log('hello')
}
}
});
will work. And you can spare assigning a constant by using
methods: {
[options.methodName]: function() {...}
}

Related

Why can't I access to my data function from my computed property?

I have this in my data :
data() {
return {
hello: "hello",
}
}
And I have a computed property like this :
computed: {
serviceHello() {
return {
sayHello() {
console.log(this.hello);
},
sayHi(){
console.log("hi");
}
}
}
When I'm calling my computed properties like this in my mounted.
this.serviceHello.sayHello(); // console : undefined
this.serviceHello.sayHi(); //console write "hi"
So I tried to see what is inside this but there's only the content from the computed(sayHello and sayHi), I can't access to my values in my data.
My question is, how can I access to the data from my computed ? I want the sayHello to display the hello from my data.
Just assign this to a global variable and use inside the returned function :
new Vue({
el: "#app",
data() {
return {
message: 'Welcome to Vue !',
};
},
computed: {
serviceHello() {
let vm = this //assign it here to a global variable vm
return {
sayHello() {
console.log(vm.message);//use vm here
},
sayHi() {
console.log("hi");
}
}
},
},
methods: {
doSomething() {
this.serviceHello.sayHello();
this.serviceHello.sayHi();
}
},
mounted(){
this.serviceHello.sayHello();
this.serviceHello.sayHi();
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>{{ message }}</h1>
<button #click="doSomething">Say hello.</button>
</div>
This works fine but it's not the job of the computed property which should be used to return some stuff based on other properties
Your computed functions are wrong. It should be:
computed: {
sayHello() {
console.log(this.hello);
},
sayHi() {
console.log("hi");
}
}
The way you have wrote it means that the keyword this will be referencing to the object context itself and not to the context of the component.
You are using the wrong way a computed property.
Computed properties must return a value;
Try this way.
computed: {
sayHello() {
return this.hello;
},
sayHi() {
return "hi";
}
}
and access as this.sayHello or {{sayHello}} in templates.
If you are trying to use a computed Setter you can use as this example below:
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
More infor here https://v2.vuejs.org/v2/guide/computed.html

Use Vue.js 3 with lodash debounce function

Is there any solution to use lodash debounce on method? I also need 'this' in the function.
Example:
data() {
info: 'Read Me!'
},
methods: {
readData() {
console.log(this.info)
}
}
In Vue2 I could use:
methods: {
readData: debounce(function() {
console.log(this.info)
}, 500)
}
Your data property should be a function that returns an object :
data() {
return{
info: 'Read Me!'
}
},
and write your method by giving a name to the debounce callback :
methods: {
readData: debounce(function debounceRead() {
console.log(this.info)
}, 500)
}

How to get the parent function name of the function being called

I am trying to get the name of the parent function of the function being called.
For example if I have these functions:
var functions = {
coolfunction1: {
add: function () {
},
delete: function () {
},
save: function () {
}
},
coolfunction2: {
add: function () {
// i want to console.log() the name of the parent of this function,
// output: coolfunction2
},
delete: function () {
},
save: function () {
}
}
}
When I call functions.coolfunction2.add(), is there a way to log the name of the parent function that was run?
I know I can use the variable this but that only outputs the names of the children functions, add(), delete(), save().
How can I know that the coolfuntion2 was run?
I know this can be done manually, by rewriting the function name in the add() function, but is there a way to get the name dynamically?
You can add a getter to those methods as
Object.keys(functions).forEach(t =>
Object.keys(functions[t]).forEach(t2 => {
var func = functions[t][t2]; //save a reference to function since it won't be a function anymore once a getter is assigned
Object.defineProperty(functions[t], t2, {
get: function() {
console.log(t); //print the name of parent property or grand-parent property, etc
//func();
return func; //return the reference to this function
}
});
})
);
Demo
var functions = {
coolfunction1: {
add: function() {
},
delete: function() {
},
save: function() {
}
},
coolfunction2: {
add: function() {
console.log("a is invoked");
},
delete: function() {
},
save: function() {
}
}
};
Object.keys(functions).forEach(t =>
Object.keys(functions[t]).forEach(t2 => {
var func = functions[t][t2];
Object.defineProperty(functions[t], t2, {
get: function() {
console.log(t);
//func();
return func;
}
});
})
);
functions.coolfunction2.add();
functions.coolfunction2.add();
functions.coolfunction1.add();

Vue.js Call method from another component

I have 2 components. How can I call fetchProjectList() method in createProject() method.
First component:
Vue.component('projects', {
template: '#projects-template',
data: function () {
return {
list: []
}
},
ready: function () {
this.fetchProjectList();
},
methods: {
fetchProjectList: function () {
resource.get().then(function (projects) {
this.list = projects.data;
}.bind(this));
}
}
});
Second component
Vue.component('createProjects', {
template: '#create-projects-template',
methods: {
createProject: function () {
resource.save({}, {name: this.name}).then(function () {
this.fetchProjectList()
}.bind(this), function (response) {
// error callback
});
}
}
});
You don't, or rather you shouldn't. components should not depend on other components in such a direct way.
You should either extract this method into a mixin, or keep it in it's own object which you import into each component.
Read up on the store pattern: http://vuejs.org/guide/application.html#State_Management

How to extends a javascript object?

I made a simple example of my problem with a babel object :
function babel(){
this.english = {
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { alert('T-shirt'); }
}
}
Now, I want to extends this object :
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('au revoir'); }
}
But what if I need to use an existing function define before ?
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { this.english.teeshirt(); }
}
What I could do is :
var say = new babel();
(function (_this) {
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
hello: function () { _this.english.hello(); }
}
})(say);
But in this case, I will always use the context of the say object, isn't it ?
The problem is, that in teeshirt function call this points to the french object, not babel object. If you have to access parent object, you should store reference to it somewhere. For example you can change your constructor like this:
function babel(){
this.english = {
parent: this,
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { this.parent.french.something(); }
}
}
But as you can see, there is a problem if you don't create object in constructor. I don't see any 'nice' approach, but you can do this:
function babel(){
this.english = {
parent: this,
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { this.parent.french.something(); }
};
for (var i in babel.prototype) {
this[i].parent = this;
}
}
Then your french will look like this:
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { this.parent.english.teeshirt(); }
}
While the question as asked does bring up all the fascinating issues with JavaScript's this and prototypal inheritance, I would suggest simplifying the whole problem and refactoring your objects. There are a couple ways to do this.
If the English version of teeshirt is the default, it should be in the object which is at the end of the prototype chain. That is, a French object would have as its prototype an English object. The French object would simply not contain a teeshirt member. This is similar to the way resource bundles work.
Now this idea may not work for you, because the relationship among the different bundles may be complex: perhaps sometimes Engish is a fallback sometimes but not other times. In this case, see if you can make your babel objects all singletons (i.e., just plain objects).
var babel = {}
babel.english = {
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); },
teeshirt: function () { alert('T-shirt'); }
}
babel.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { babel.english.teeshirt(); }
}
babel.english.teeshirt();
babel.french.teeshirt();
Try it at http://jsfiddle.net/yRnLj/
I realize this looks like a complete avoidance of your interesting question. But if you only need one copy of each language bundle, it is a lot simpler. :-)

Categories

Resources