How do I emit multiple arguments via setup()? - vue.js

I have the following function being passed as an emit to the component:
setTray(tray, pk) {
alert(tray)
alert(pk)
},
Calling inside a component, I am able to reach the function, but not the arguments:
setup(props, ctx) {
ctx.emit('setTray', 'profile-task', pk)
ctx.emit('setTray', {tray: 'profile-task', pk: pk})
}
Both approaches result in the arguments being undefined when setTray() is executed. What is the correct syntax in this situation?

The emit function accepts one or two arguments, the event name and the payload which in your case should be defined as object :
ctx.emit('setTray', {tray: 'profile-task', pk: pk})
in parent :
setTray({tray, pk}) {//destruct the payload
alert(tray)
alert(pk)
},
or in old way :
setTray(payload) {
alert(payload.tray)
alert(payload.pk)
},

Related

Why Vue.js doesn't trigger reactivity when Component Props are changed in a helper function, outside of the Component scope(in a different file)?

I prefer to move functionality outside Components when the Component code becomes to crowded. So, this is a problem with which I have confronted several times when I have passed Component Props as arguments to functions that were outside of the Component scope, hosted in a different file as helper functions or as class methods. The mistake was fed also by the personal idea that I should use imutable objects everywere for better performance.
// the component file hosted in "MyComponent.vue"
<template>
<button #click="update">Please, update!</button>
</template>
<script>
import {
updatePrimitiveFn,
updateLiteralObjectFn,
updateArrayFn,
} from "../helpers.js";
export default {
name: "MyComponent",
data() {
return {
primitiveToBeUpdated: false,
arrayToBeUpdated: [],
literalObjectToBeUpdated: {},
};
},
methods: {
update() {
updatePrimitiveFn(this.primitiveToBeUpdated);
updatedLiteralObjectFn(this.literalObjectToBeUpdated);
updateArrayFn(this.arrayToBeUpdated);
console.log("primitiveToBeUpdated", this.primitiveToBeUpdated);
console.log("literalObjectToBeUpdated", this.literalObjectToBeUpdated);
console.log("arrayToBeUpdated", this.arrayToBeUpdated);
},
},
};
</script>
// the helpers functions hosted in "helpers.js"
export function updatePrimitiveFn(primitiveParameter) {
primitiveParameter = true; // it will not trigger reactivity, the argument it's a primitive and for primitives JavaScript copies the argument value to the formal parameter. For arguments that are objects, JavaScript copies the pointers of these objects to the formal parameter, keeping the link between component props and formal parameters. Pointers stores the memory address where some data lives.
}
export function updateLiteralObjectFn(literalObjectParameter) {
literalObjectParameter = { value: true }; // it will not trigger reactivity, it replaces the pointer of the received argument with a fresh new one.
}
export function updateArrayFn(arrayToBeUpdated) {
arrayToBeUpdated = [true]; // it will not trigger reactivity, it replaces the pointer of the received argument with a fresh new one.
}
The solution is to pass only objects, as arguments, to the external functions and mutate them as follows:
// the helpers functions hosted in "helpers.js"
export function updatePrimitiveFn(primitiveParameter) {
primitiveParameter = true; // it will not trigger reactivity, the argument it's a primitive and for primitives JavaScript copies the argument value to the formal parameter. For arguments that are objects, JavaScript copies the pointers of these objects to the formal parameter, keeping the link between component props and formal parameters. Pointers stores the memory address where some data lives.
}
export function updateLiteralObjectFn(literalObjectParameter) {
literalObjectParameter.value = true; // mutation keeps pointing same object in memory
}
export function updateArrayFn(arrayToBeUpdated) {
arrayToBeUpdated.push(true); mutation keeps pointing same object in memory
}
Check live demo: https://codesandbox.io/s/hardcore-volhard-mf6x0?file=/src/components/MyComponent.vue:0-179
For more information can be studied the subject "Pass by Value vs. Pass by Reference".

$refs.myChildComponent is undefined although I see it in the console

In my child component I have two functions:
methods: {
tutu: function () {
...
},
openMenu: function () {
...
}
}
In my parent component, I'm trying to execute each of these functions in reaction to different events:
methods: {
openMenu: function () {
this.$refs.main_menu.openMenu();
},
handleResize: function () {
this.$refs.main_menu.tutu();
}
},
The first call (this.$refs.main_menu.openMenu()) works fine, but the second one fails with this error message:
TypeError: Cannot read property 'tutu' of undefined
In my parent component, console.log(this.$refs) shows both functions the same way. EDIT: console.log(this.$refs.main_menu) shows undefined.
I cannot understand why one of them works and not the other if everything is the same for both.
main_menu: VueComponent
...
openMenu: ƒ ()
arguments: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.invokeGetter (<anonymous>:2:14)]
caller: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.invokeGetter (<anonymous>:2:14)]
length: 0
name: "bound openMenu"
...
tutu: ƒ ()
arguments: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.invokeGetter (<anonymous>:2:14)]
caller: [Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at Function.invokeGetter (<anonymous>:2:14)]
length: 0
name: "bound tutu"
__proto__: ƒ ()
$refs will only be populated after a component is mounted. So if you try to access a ref prior to that, for example from a created hook, it won't be there.
There are other ways that a ref can be missing. For example, if you're using v-if and the condition is false. In that case it isn't sufficient to wait for the condition to become true, you would also need to wait for a rendering update to be performed and such updates are queued. In that case you'd either need to use the updated hook or a call to $nextTick.

Pass parameter while emitting using Vuejs event hub

I have checked similar question, but there is still one thing that is unclear to me:
Can I pass a parameter in emit on event hub, but I need parameter to be VALUE and not the VARIABLE which stores value. So for example: eventHub.$emit('test_emit', true) and the method which is called on test_emit should have it's parameter set on true.
From the similar question that you provided, you would just replace name with true when you are emitting event
methods: {
showModal(name) { this.bus.$emit('showModal', true); },
}
created() {
// `show` will have the value that you emitted
this.bus.$on('showModal', (show) => console.log(show);
}
Sure you can, what you cannot do is to pass more then one variable (like eventHub.$emit('test_emit', true, false) as $emit accepts only one additional parameter (that can be the value or an object containing the key: value associations, also know as payload.

Polymer: Call a behavior's property function in elements property values?

Recently I looked up Polymers app-localize-behavior and I saw they typed the localize() method as Function (see on GitHub):
excerpt from app-localize-behavior.html:
localize: {
type: Function,
computed: '__computeLocalize(language, resources, formats)'
},
This method works perfectly fine in data-bindings, like <div>{{localize('welcome')}}</div>, but how can I call this method from my elements properties? I try to do something like:
excerpt from my-element.html:
properties: {
_pageTitle: {
type: String,
value: this.localize('welcome')
}
}
But when I try this, I get a Uncaught TypeError: this.localize is not a function. Even in my ready method I need to call this.localize asynchronously as otherwise it isn't defined, too.
How could I solve that problem?
Thank you in advance!
Use a computed property that invokes localize(...):
properties: {
_pageTitle: {
computed: 'localize("welcome")'
}
}
demo

Dojo this.inherit throws 'Uncaught TypeError: Cannot read property 'callee' of undefined'

To facilitate a JsonRest store with a non-standard url scheme, I am trying to inherit JsonRest and override the _getTarget(id) function. Here is what my inherited javascript class looks like:
define([
"dojo/_base/declare",
"dojo/store/JsonRest",
],
function(declare, JsonRest) {
return declare(JsonRest, {
_getTarget: function(id){
var target = this.target;
if(typeof id != "undefined"){
if(target.indexOf("{id}") != -1) {
//use template
target = target.replace("{id}", id);
} else {
target = this.inherited(id);
}
}
return target;
},
});
});
However the line target = this.inherited(id); returns an error: Uncaught TypeError: Cannot read property 'callee' of undefined.
I looked at the docs, and I think I am doing it right:
http://dojotoolkit.org/reference-guide/1.10/dojo/_base/declare.html#calling-superclass-methods
What is the proper way to call the base class's _getTarget(id) function?
If you look closely the part of the documentation you linked, you are supposed to literally pass the arguments object to this.inherited - that's what contains the callee property it is looking for (and will include the id and any other arguments anyway, to be passed along to the superclass).
A few paragraphs in, the documentation also explains how to call this.inherited with arguments other than the same ones passed, if necessary: you can pass custom arguments in an array after arguments, i.e. this.inherited(arguments, [ ... ]). arguments always has to be first.